def tuple(self): if self._tuple is None: clsname = self.get_classname() if clsname == 'com.android.commands.monkey.ape.naming.EmptyNamer$1': self._tuple = tuple() elif clsname == 'com.android.commands.monkey.ape.naming.ActionPatchNamer$ActionPatchName': self._tuple = ('ActionPatch', Name.init(self.baseName), self.patch, enumToString(self.scrollType)) elif clsname == 'com.android.commands.monkey.ape.naming.TypeNamer$TypeName': if self.resourceId is None or len(self.resourceId) == 0: self._tuple = ('Type', self.klass) else: self._tuple = ('Type', self.klass, self.resourceId) elif clsname == 'com.android.commands.monkey.ape.naming.CompoundNamer$CompoundName': self._tuple = ('Compound', tuple(classReadJavaList(self.names, Name))) elif clsname == 'com.android.commands.monkey.ape.naming.IndexNamer$IndexName': self._tuple = ('Index', self.index) elif clsname == 'com.android.commands.monkey.ape.naming.ParentNamer$ParentName': self._tuple = ('Parent', Name.init(self.parentName), Name.init(self.localName)) elif clsname == 'com.android.commands.monkey.ape.naming.TextNamer$TextName': if self.contentDesc is None or self.contentDesc == "": self._tuple = ('Text', self.text) else: self._tuple = ('Text', self.text, self.contentDesc) elif clsname == 'com.android.commands.monkey.ape.naming.AncestorNamer$AncestorName': self._tuple = ('Ancestor', tuple(classReadJavaList(self.names, Name))) else: raise NotImplementedError(clsname) return self._tuple
def __eq__(self, other): other = StateKey.init(other) if other is None: return False if self.activity != other.activity: return False if namingModule.Naming.init(self.naming) != namingModule.Naming.init( other.naming): return False return classReadJavaList(self.widgets, namingModule.Name) == classReadJavaList( other.widgets, namingModule.Name)
def select_Document(self, document): assert isinstance(document, etree._Element) ret = dict() for namelet in classReadJavaList(self.namelets, Namelet): nodes = namelet.filter_Object(document) for node in nodes: try: ret[node].append(namelet) except KeyError: ret[node] = [namelet] return ret
def select_LNamelet(self, namelets): namelets = classReadJavaList(namelets, Namelet) if len(namelets) == 1: return namelets[0] namelets.sort() for i in range(len(namelets)): namelet = Namelet.init(namelets[i].parent) while namelet is not None: if namelet < namelets[0]: break namelet = Namelet.init(namelet.parent) if namelet is None: return namelets[i] return None
def naming(self, node): node = treeModule.GUITreeNode.init(node) clsname = self.get_classname() if clsname == 'com.android.commands.monkey.ape.naming.EmptyNamer': return Name(tuple()) elif clsname == 'com.android.commands.monkey.ape.naming.ActionPatchNamer': interactiveProperties = [ "isEnabled", "isClickable", "isScrollable", "isLongClickable", "isScrollable" ] patch = 0 for prop in interactiveProperties: patch <<= 1 if getattr(node, prop)(): patch |= 1 scrollType = node.getScrollType() return Name( ('ActionPatch', Namer.init(self.baseNamer).naming(node), patch, enumToString(scrollType))) elif clsname == 'com.android.commands.monkey.ape.naming.TypeNamer': return Name(('Type', node.getClassName(), node.getResourceID())) elif clsname == 'com.android.commands.monkey.ape.naming.CompoundNamer': names = [] for namer in classReadJavaList(self.namers, Namer): names.append(namer.naming(node)) return Name(('Compound', names)) elif clsname == 'com.android.commands.monkey.ape.naming.IndexNamer': return Name(('Index', node.getIndex())) elif clsname == 'com.android.commands.monkey.ape.naming.ParentNamer': parentNode = node.getParent() localName = Namer.init(self.namer).naming(node) if parentNode is not None: parentName = parentNode.getTempXPathName() if parentName is None: parentName = parentNode.getXPathName() assert parentName is not None, "Parent name should not be null" return Name(('Parent', parentName, localName)) return Name(('Parent', tuple(), localName)) elif clsname == 'com.android.commands.monkey.ape.naming.TextNamer': return Name(('Text', node.getText(), node.getContentDesc())) elif clsname == 'com.android.commands.monkey.ape.naming.AncestorNamer': parentNode = node.getParent() namerTypes = self.getNamerTypes() localNamer = NamerFactory.getLocalNamer(self) if parentNode is not None: useParent = 'PARENT' in namerTypes names = [localNamer.naming(node)] if useParent: while parentNode is not None: tempName = parentNode.getTempXPathName() if tempName is None: tempName = parentNode.getXPathName() assert tempName is not None, "Temp name of a parent node should be set." tempNamer = tempName.getNamer() parentNamer = NamerFactory.getLocalNamer(tempNamer) names.append(parentNamer.naming(parentNode)) parentNode = parentNode.getParent() else: while parentNode is not None: names.append(localNamer.naming(parentNode)) parentNode = parentNode.getParent() return Name(('Ancestor', reversed(names))) return Name(('Ancestor', localNamer.naming(node))) else: raise NotImplementedError(clsname)
def makeUnit(expname, exptype, directory, printSubsequence, detail, allcrash): apelog_fname = os.path.join(directory, 'ape_stdout_stderr.txt') logcat_fname = os.path.join(directory, 'logcat.txt') mtdata_directories = glob.glob(os.path.join(directory, 'mt_data', '*')) assert os.path.isfile(apelog_fname), apelog_fname assert os.path.isfile(logcat_fname), logcat_fname modelobjects = glob.glob(os.path.join(directory, 'ape', '*', 'sataModel.obj')) if len(modelobjects) < 1: print("There is no model object in {}".format(directory)) with open(apelog_fname, 'rt') as f: num_lines = int(run_cmd('wc -l {}'.format(apelog_fname)).split()[0]) for i, line in enumerate(f): if i >= num_lines - 10: print(' {}: {}'.format(i, line.rstrip())) return None assert len(modelobjects) == 1, modelobjects modelobject_fname = modelobjects[0] warningCounter = Counter() waitCounter = Counter() crashLongMessagesCounter = Counter() time_elapsed = -1 strategy_cnt = {} first_timestamp = -1 strategy_changed_timestamp = -1 first_met_timestamp = -1 timestamp = -1 with open(apelog_fname, 'rt') as f: it = iter(f) for line in it: line = line.rstrip() if line.startswith('[APE_MT_WARNING]'): warningCounter.append(line) gp = re.match(r'\[APE\] ([a-zA-Z]+) Strategy: buffer size \(([0-9]+)\)', line) if gp: nums = [re.match(r'\[APE\] *([0-9]+) (.*)', next(it).rstrip()) for strategy in strategies[gp.group(1)]] strategy_cnt = dict(map(lambda gp:(gp.group(2), int(gp.group(1))), nums)) continue elif line.startswith('## Network stats: elapsed time='): gp = re.match(r'## Network stats: elapsed time=([0-9]+)ms \(([0-9]+)ms mobile, ([0-9]+)ms wifi, ([0-9]+)ms not connected\)', line) assert gp, line total, mob, wifi, total2 = gp.groups() assert total == total2 and mob == wifi, line time_elapsed = int(total) elif line == "[APE] *** INFO *** We are still waiting for activity loading. Let's wait for another 100ms...": waitCounter.append(line) elif line.startswith("[APE] // Long Msg: "): crashLongMessagesCounter.append(line[len("[APE] // Long Msg: "):]) if allcrash: print(line) while line.startswith("[APE] //"): line = next(it).rstrip() print(line) assert line.startswith('[APE] *** INFO *** Appending crash [') current_timestamp = int(line.split('@')[1]) print('*** Time elapsed {}'.format(current_timestamp - first_timestamp)) print() elif line == "[APE] *** INFO *** Half time/counter consumed": strategy_changed_timestamp = timestamp elif line.startswith("[MonkeyServer] idle fetch"): gp = re.match(r'\[MonkeyServer\] idle fetch ([-]{0,1}[0-9]+)', line) assert gp, line timestamp = int(gp.group(1)) if first_timestamp == -1 and timestamp not in [0, -1]: first_timestamp = timestamp elif line == '[APE_MT] Lastlast transition met target': if first_met_timestamp == -1: first_met_timestamp = timestamp elif 'MET TARGET' in line: # for old version if first_met_timestamp == -1: first_met_timestamp = timestamp if time_elapsed == -1: print("Time elapsed not found") with open(apelog_fname, 'rt') as f: num_lines = int(run_cmd('wc -l {}'.format(apelog_fname)).split()[0]) for i, line in enumerate(f): if i >= num_lines - 10: print(' {}: {}'.format(i, line.rstrip())) return None targetMethods = [] lazy_counter = Counter() registered_counter = Counter() registered_lazily_counter = Counter() with open(logcat_fname, 'rt') as f: for line in f: if 'MiniTrace' not in line: continue line = line.rstrip() line = line[line.index('MiniTrace'):] gp = re.match(r'MiniTrace: TargetMethod (.*):(.*)\[(.*)\] ([a-z ]+)', line) if gp: clsname, mtdname, signature, status = gp.groups() if status == 'lazy': clsname = 'L{};'.format(clsname) if (clsname, mtdname, signature) not in targetMethods: targetMethods.append((clsname, mtdname, signature)) lazy_counter.append((clsname, mtdname, signature)) elif status == 'registered': clsname = 'L{};'.format(clsname) if (clsname, mtdname, signature) not in targetMethods: targetMethods.append((clsname, mtdname, signature)) lazy_counter.append((clsname, mtdname, signature)) else: assert status == 'registered lazily', status assert clsname[0] == 'L' and clsname[-1] == ';', clsname registered_lazily_counter.append((clsname, mtdname, signature)) method_register_status = {} for method in targetMethods: if registered_counter[method] == 0: data = '{}/{}'.format(registered_lazily_counter[method], lazy_counter[method]) else: assert registered_lazily_counter[method] == 0, registered_lazily_counter[method] assert lazy_counter[method] == 0, lazy_counter[method] data = '{}/{}'.format(registered_counter[method], registered_counter[method]) method_register_status[method] = data # self.exptype = exptype # self.expname = expname # self.directory = directory # marked call class MtdCounter(object): def __init__(self): self.cnt = 0 self.main_tid = -1 self.main_cnt = 0 def setTid(self, main_tid): self.main_tid = main_tid def inc(self, value): self.main_cnt += 1 def tidInc(self, tid, value): assert self.main_tid != -1 if tid == self.main_tid: self.main_cnt += 1 self.cnt += 1 class ExecutionData: def __init__(self, string): assert all(c in ['0', '1'] for c in string), string self.string = string def union(self, new_string): assert len(self.string) == len(new_string) new_string = ''.join(['1' if a == '1' or b == '1' else '0' \ for a, b in zip(self.string, new_string)]) self.string = new_string def __or__(self, other): assert len(self.string) == len(other.string) new_string = ''.join(['1' if a == '1' or b == '1' else '0' \ for a, b in zip(self.string, other.string)]) return ExecutionData(new_string) def __repr__(self): return '<ExecutionData string={}>'.format(self.string) def ratio(self): return self.string.count('1') / len(self.string) sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../crashgen')) from consumer import parse_data, Threads, Methods execution_data = {} mtdCounter = MtdCounter() for mtdata_directory in mtdata_directories: binary_fname = os.path.join(mtdata_directory, 'data_0.bin') thread_fname = os.path.join(mtdata_directory, 'info_t.log') method_fname = os.path.join(mtdata_directory, 'info_m.log') if any(not os.path.isfile(fname) for fname in [binary_fname, thread_fname, method_fname]): continue mtdCounter.setTid(Threads(thread_fname).get_main_tid()) parse_data(binary_fname, {10: mtdCounter.inc, 11: mtdCounter.inc, 12: mtdCounter.inc, 13: mtdCounter.tidInc, 14: mtdCounter.tidInc, 15: mtdCounter.tidInc}, verbose=False) methods = Methods(method_fname) execf = os.path.join(mtdata_directory, 'exec.txt') with open(execf, 'rt') as f: for line in f: line = line.rstrip() if line.startswith('\0'): line = line[1:] if line == '': break if not line.startswith('Timestamp'): mtdptr, execdata = line.split() mtdptr = int(mtdptr, 16) clsname, mtdname, signature, defclass = methods[mtdptr] try: execution_data[(clsname, mtdname, signature)].union(execdata) except KeyError: execution_data[(clsname, mtdname, signature)] = ExecutionData(execdata) string = '{},{}'.format(expname, exptype) string += ',{},{},{},'.format(time_elapsed, warningCounter.total(), waitCounter.total()) assert all(method in targetMethods for method in execution_data) method_data = [] for method in targetMethods: if method not in execution_data: data = 0.0 else: data = execution_data[method].ratio() method_data.append('%s:%.3f' % (method_register_status[method], data)) string += '/'.join(method_data) string += ',{},{}'.format(strategy_cnt.get('TARGET', 0) + strategy_cnt.get('MCMC', 0), sum(strategy_cnt.values())) string += ',{},{}'.format(mtdCounter.main_cnt, mtdCounter.cnt) # strategy changed timestamp if strategy_changed_timestamp == -1: string += ',NaN' else: string += ',{}'.format(strategy_changed_timestamp - first_timestamp) # first met transition timestmap if first_met_timestamp == -1: string += ',NaN' else: string += ',{}'.format(first_met_timestamp - first_timestamp) warningCounter.pretty() if not detail: string += ',{}'.format(crashLongMessagesCounter.total()) string += ',{}'.format('/'.join(map(lambda tup:'{} {} [{}]'.format(*tup), targetMethods))) return string # analysis for sataModel.obj # crashes with targets # GUITreeTransition marked/total # State marked/total # StateTransition marked/total # unique subsequences (>=3 times / at least once) # @TODO State score # @TODO StateTransition score data = [] import javaobj from common import classReadJavaList, readJavaList from tree import GUITree from model import Model, Graph, StateTransition try: with open(modelobject_fname, 'rb') as f: model = Model(javaobj.loads(f.read())) except Exception: return string + ',javaobjError' graph = Graph.init(model.graph) # crashes crashWithTargetMethodsCounter = Counter("crashes with target") crashWithoutTargetMethodsCounter = Counter("crashes without target") firstMoment = -1 firstMomentTargetMethods = -1 records = model.actionHistory for record in readJavaList(records): if firstMoment == -1: firstMoment = record.clockTimestamp if not record.guiAction: action = record.modelAction constant = action.type.constant if constant == 'PHANTOM_CRASH': # check stackTrace stackTrace = action.crash.stackTrace metTarget = False for line in stackTrace.split('\n'): if metTarget: break for (clsname, mtdname, signature) in targetMethods: if mtdname in line and clsname[1:-1].split('/')[-1] in line: metTarget = True break if metTarget: crashWithTargetMethodsCounter.append(action.crash.stackTrace) if firstMomentTargetMethods == -1: firstMomentTargetMethods = record.clockTimestamp else: crashWithoutTargetMethodsCounter.append(action.crash.longMsg) crashWithTargetMethodsCounter.pretty() crashWithoutTargetMethodsCounter.pretty() if firstMomentTargetMethods == -1: data.append('NaN') else: data.append(firstMomentTargetMethods - firstMoment) data.append(crashWithTargetMethodsCounter.total()) data.append(crashLongMessagesCounter.total()) treeHistory = graph.treeTransitionHistory marked_gtransitions = [] marked_transitions = set() for gtransition in treeHistory: if gtransition.hasMetTargetMethod: marked_gtransitions.append(gtransition) marked_transitions.add(gtransition.stateTransition) data.append(len(marked_gtransitions)) data.append(len(treeHistory)) targetGUITrees = classReadJavaList(graph.metTargetMethodGUITrees, GUITree) targetStates = set(map(lambda t:t.getCurrentState(), targetGUITrees)) targetStateIds = set(map(lambda t:id(t.currentState), targetGUITrees)) assert len(targetStates) == len(targetStateIds), (len(targetStates), len(targetStateIds)) data.append(len(targetStates)) data.append(graph.size()) # Split with marked State (old) -> Split with marked StateTransition from parseobj import getSubsequences, TargetSubsequence subsequences = getSubsequences(model, graph) subseqCounter = Counter() targetSubsequences = [] for seq in subsequences: targetSubsequence = TargetSubsequence(seq[0], seq.getTimestampDelta(0)) for i in range(1, len(seq)): tr = seq[i] timestamp = seq.getTimestampDelta(i) if tr.hasMetTargetMethod == True: # if id(tr.source.currentState) in targetStateIds: subseqCounter.append(targetSubsequence) targetSubsequences.append(targetSubsequence) targetSubsequence = TargetSubsequence(tr, timestamp) else: targetSubsequence.append(tr, timestamp) # subseqCounter.append(targetSubsequence) targetSubsequence.setActionRecords(seq.actionRecordsAtEnd) targetSubsequences.append(targetSubsequence) data.append(len([s for s in subseqCounter.values() if s >= 3])) data.append(len(subseqCounter)) if printSubsequence: currentRunningSubsequences = [] for subsequence in targetSubsequences: currentRunningSubsequences.append(subsequence) # if subsequence.containsTarget(): crash = subsequence.getCrash() if crash: print('Subsequence newly emrged# {}'.format(subsequence.timestamps[0])) print(crash['stackTrace']) for subsequence in currentRunningSubsequences: print(subsequence.seqdetail()) print() currentRunningSubsequences = [] # print('{}: {}'.format(subsequence.timestamps[0], subsequence.seqdetail())) string += ',' + ','.join(map(str, data)) if len(subseqCounter) == 0: string += ',NaN,NaN,NaN,NaN,NaN,NaN' else: # #subseq with len <=1, <=2, <=3, <=4, <=5 keys = subseqCounter.keys() cnts = [] for sz in [1, 2, 3, 4, 5]: cnts.append(len([s for s in keys if len(s) <= sz])) cnts = tuple(cnts) string += ',%.2f,%d,%d,%d,%d,%d' % ((subseqCounter.total() / len(subseqCounter),) + cnts) # statistics for state / transition state_scores = [] for state in targetStates: state_scores.append(graph.metTargetScore(state)) if state_scores != []: state_scores = np.array(state_scores) string += ',%d,%.3f,%.3f,%.3f,%.3f' % ( len(state_scores), np.min(state_scores), np.max(state_scores), np.average(state_scores), np.std(state_scores)) else: string += ',0,NaN,NaN,NaN,NaN' transition_scores = [] for transition in marked_transitions: transition_scores.append(StateTransition.init(transition).metTargetRatio()) if transition_scores != []: transition_scores = np.array(transition_scores) string += ',%d,%.3f,%.3f,%.3f,%.3f' % ( len(transition_scores), np.min(transition_scores), np.max(transition_scores), np.average(transition_scores), np.std(transition_scores)) else: string += ',0,NaN,NaN,NaN,NaN' string += ',{}'.format('/'.join(map(lambda tup:'{} {} [{}]'.format(*tup), targetMethods))) return string
def getGUITreeTransitions(self): return classReadJavaList(self.treeTransitions, treeModule.GUITreeTransition)
def buildStateKey(naming, componentName, currentNames): naming = namingModule.Naming.init(naming) widgets = classReadJavaList(currentNames, namingModule.Name) return StateKey(componentName, naming, widgets)
def __hash__(self): return hash((self.activity, namingModule.Naming.init(self.naming), \ tuple(classReadJavaList(self.widgets, namingModule.Name))))