def handle_cmd(): appdb.collect_apps("../apks/") serial = sys.argv[1] cmd = sys.argv[2] args = sys.argv[3:] dev = device.Device(serial=serial, no_uimon=True) if cmd == "clear": if args[0] == 'all': for app in appdb.apps: clear(dev, appdb.get_app(app)) else: clear(dev, appdb.get_app(args[0])) elif cmd == "install": appname = args[0] install(dev, appname) elif cmd == "uninstall": appname = args[0] uninstall(dev, appname) elif cmd == "version": appname = args[0] apk_version(appname) elif cmd == "dver": appname = args[0] ret = check_dev_version(dev, appname) if ret: sys.exit(0) else: sys.exit(1)
def check_dev_version(dev, appname): app = appdb.get_app(appname) ret = dev.run_adb_shell("pm list packages").decode('utf-8') found = False for line in ret.split('\n'): line = line.strip() if line == 'package:' + app: found = True break if not found: print(appname, "NOT INSTALLED") return False ret = dev.run_adb_shell("pm dump %s" % app).decode('utf-8') vercode = None vername = None for line in ret.split('\n'): if dver_vercode_re.match(line): vercode = dver_vercode_re.match(line).group(1) elif dver_vername_re.match(line): vername = dver_vername_re.match(line).group(1) print(appname, vercode, vername) ver_code_apk = apk_version(appname) if ver_code_apk == vercode: print(appname, "VERSION MATCH") return True else: print(appname, "VERSION MISMATCH!") return False
def dump_to_file(dev, basename, appname=None, scrname=None, guispath=None): ret = grab_full(dev) if appname is None: appname = appdb.guess_app(ret['act']) logger.info("app guessed as %s", appname) else: logger.info("dumping for app %s", appname) webdatas = None if 'WebView' in ret['xml']: app = appdb.get_app(appname) if app is None: app = appdb.app_from_act(ret['act']) logger.warning("unknown app, using %s directly", app) webgrabber = webview.WebGrabber(app) pages = webgrabber.find_webviews(dev) webdata = [] for page in pages: webgrabber.capture_webnodes(dev, page) webdata.append({'title': page['title'], 'pageinfo': page, 'page': webgrabber.dump()}) webgrabber.clear() webdatas = yaml.dump(webdata) with open(basename + ".xml", 'w') as xmlf: xmlf.write(ret['xml']) shutil.move(ret['scr'], basename + ".png") #with open(basename + ".png", 'wb') as pngf: #pngf.write(open(ret['scr'], 'rb').read()) with open(basename + ".txt", "w") as actf: actf.write(ret['act']) if webdatas is not None: with open(basename + ".web", "w") as webf: webf.write(webdatas)
def dump_page(dev, path, appname=None, scrname=None, guispath=None): ret = grab_full(dev) if appname is None or scrname is None: template = "page%d" else: template = "%s_%%d_%s" % (appname, scrname) if appname is None or scrname is None or guispath is None: page_id = 0 while (os.path.exists( os.path.join(path, ("%s.xml" % template) % page_id)) and os.path.exists( os.path.join(path, ("%s.png" % template) % page_id))): page_id += 1 else: page_id = dump.get_next_page_id([guispath, path], appname, scrname) if page_id > config.PER_PAGE_CAPTURE_LIMIT: return if appname is None: appname = appdb.guess_app(ret['act']) logger.info("app guessed as %s", appname) else: logger.info("dumping for app %s", appname) webdatas = None if 'WebView' in ret['xml']: app = appdb.get_app(appname) if app is None: app = appdb.app_from_act(ret['act']) logger.warning("unknown app, using %s directly", app) webgrabber = webview.WebGrabber(app) pages = webgrabber.find_webviews(dev) webdata = [] for page in pages: webgrabber.capture_webnodes(dev, page) webdata.append({ 'title': page['title'], 'pageinfo': page, 'page': webgrabber.dump() }) webgrabber.clear() webdatas = yaml.dump(webdata) logger.info("dumping to page %s", template % page_id) basename = os.path.join(path, template % page_id) with open(basename + ".xml", 'w') as xmlf: xmlf.write(ret['xml']) shutil.move(ret['scr'], basename + ".png") #with open(basename + ".png", 'wb') as pngf: #pngf.write(open(ret['scr'], 'rb').read()) with open(basename + ".txt", "w") as actf: actf.write(ret['act']) if webdatas is not None: with open(basename + ".web", "w") as webf: webf.write(webdatas)
def load_app(app, ob, tlib, envs): ob.set_app(app) tlib.set_app(app) envs['app'] = app value.init_params("../etc/", app) ob.load("../model/", "../guis/", "../guis-extra/", config.extra_screens, config.extra_element_scrs) tlib.add_test(microtest.init_test(appdb.get_app(app)))
def __init__(self, dev, guispath, modelpath, tlibpath, batch, appname, statpath, errpath, skippath, extrapath, mempath, need_observer): self.dev = dev self.appname = appname # type: str self.app = appdb.get_app(appname) # type: str self.tlib = testlib.collect_pieces(tlibpath) self.tlib.set_app(appname) if skippath is not None: self.tlib.load_skip(skippath) self.slib = screenlib.Screenlib(self.tlib.essential_props()) if need_observer: self.observer = observer.Observer(errpath) self.observer.set_app(appname) self.observer.load(modelpath, guispath, extrapath, config.extra_screens, config.extra_element_scrs) self.observer.tlib = self.tlib # TODO: so ugly else: self.observer = None self.watchdog = watchdog.create(config.WATCHDOG_TIMEOUT) self.statemgr = statemgr.StateMgr(self.tlib, self.slib, self.dev, self.observer, self.watchdog) self.statpath = statpath self.batch = batch if batch: self.console = None else: self.console = console.Console(self.handle_cmd) self.console.start() self.explored_ops = { } # type: Dict[state.State, Set[operation.Operation]] self.round_no = 0 self.progress = '' self.tlib.add_test(microtest.init_test(self.app)) restart_test = microtest.restart_test(self.app) if not config.allow_restart: restart_test.set_prio(-1000) self.tlib.add_test(restart_test) self.mempath = mempath self.load_memory()
def handle_console_cmd(cons, cmd, envs): threading.current_thread().name = 'MainThread' dev = envs['dev'] ob = envs['ob'] st = envs['state'] tlib = envs['tlib'] env = envs['env'] if 'app' in envs: app = envs['app'] else: app = 'cui' def save_stat(): tlib.save_stat(os.path.join("../stat/", "%s.txt" % app)) if cmd == 'q': save_stat() dev.finish() sys.exit(0) elif cmd == 'sense': scr = ob.grab_state(dev, no_verify=True, no_print=True) if scr.get('guess_descs') is None: util.print_tree(scr.get('tree')) else: util.print_tree(scr.get('tree'), scr.get('guess_descs'), scr.get('guess_score')) st.merge(scr) return elif cmd == 'tags': config.show_guess_tags = True scr = ob.grab_state(dev, no_verify=True, no_print=True) util.print_tree(scr.get('tree'), scr.get('guess_descs'), scr.get('guess_score')) st.merge(scr) config.show_guess_tags = False return elif cmd == 'tree': scr = ob.grab_state(dev, no_img=True) util.print_tree(scr.get('tree')) st.merge(scr) return elif cmd.startswith('app '): app = cmd.split(' ')[1] load_app(app, ob, tlib, envs) return elif cmd == 'load': tlib = testlib.collect_pieces("../tlib/") envs['tlib'] = tlib load_app(app, ob, tlib, envs) return elif cmd == 'reload': value.init_params("../etc/", app) try: if app: os.remove("../model/screen_%s" % app) os.remove("../model/element_%s" % app) else: os.remove("../model/screen") os.remove("../model/element") except: pass ob.load("../model/", "../guis/", "../guis-extra/", config.extra_screens, config.extra_element_scrs) return elif cmd == 'tlib': tlib = testlib.collect_pieces("../tlib/") envs['tlib'] = tlib return elif cmd == 'test': tlib = testlib.collect_pieces("../tlib/") tlib.set_app(app) tlib.add_test(microtest.init_test(appdb.get_app(app))) envs['tlib'] = tlib config.show_guess_tags = True scr = ob.grab_state(dev) config.show_guess_tags = False st.merge(scr) begin_state = st.to_essential(tlib.essential_props()) tests = tlib.usable_tests(st) tests.sort(key=lambda test: test.prio) for i in range(len(tests)): testinfo = tlib.get_testinfo(tests[i]) print("%2d. %s: %s [%d %d]" % (i, tests[i].feature_name, tests[i].name, testinfo.succs, testinfo.fails)) if len(tests) == 0: print("no test available!") return if len(tests) == 1: tid = 0 else: tid = input("which one? ") try: tid = int(tid) except: return test = tests[tid] ret = test.attempt(dev, ob, st, tlib, environ.empty) util.print_tree(st.get('tree'), st.get('guess_descs')) end_state = st.to_essential(tlib.essential_props()) if ret: print("test SUCC") tlib.clear_stat(test) tlib.mark_succ(test, begin_state, end_state) else: print("test FAIL") tlib.mark_fail(test, begin_state) save_stat() return elif cmd == 'save': save_stat() return elif cmd == 'stat': tlib.print_stat() return elif cmd == 'items': scr = ob.grab_state(dev, no_img=True) util.printitems(scr.get('items')) return elif cmd.startswith('item'): itemid = int(cmd.split(' ')[1]) scr = ob.grab_state(dev, no_img=True) items = scr.get('items') if itemid in items: print(util.describe(items[itemid])) else: print("no such item: %d" % itemid) return elif cmd == 'debug': logging.basicConfig(level=logging.DEBUG) return elif cmd == 'idle': dev.wait_idle() return elif cmd == 'dialog': scr = ob.grab_state(dev) ret = tlib.handle_dialog(scr, dev, ob) if ret: print("dialog handled") else: print("dialog not handled") return elif cmd.startswith('find '): tag = cmd.split(' ', 1)[1] con = concept.parse(tag) if con is None: print("invalid locator") return scr = ob.grab_state(dev) widgets = con.locate(scr, ob, environ.Environment()) if widgets == []: print("can't find") else: for widget in widgets: print("FOUND: %s" % widget) print(" content:", widget.content()) return elif cmd == 'perf': perfmon.print_stat() return elif cmd == 'clear': init = tlib.find_test('meta', 'start app') st.reset() init.attempt(dev, ob, st, tlib, None) ob.update_state(dev, st) tlib.mark_succ(init, state.init_state, st) return elif cmd.startswith('set'): parts = cmd.split(' ', 2) if len(parts) == 2: key = parts[1] val = "1" else: (key, val) = parts[1:] st.set(key, val) return elif cmd.startswith('del'): parts = cmd.split(' ', 1) key = parts[1] st.remove(key) return elif cmd == 'dump': filename = util.choose_filename("../cap/", "page%d") logger.info("dumping to page %s", filename) dev.dump(filename) #sense.dump_page(dev, "../cap/") return elif cmd == 'list': scr = ob.grab_state(dev, no_img=True) tree = scr.get('tree') treeinfo = analyze.collect_treeinfo(tree) for root in sorted(treeinfo['listlike']): print("ROOT:", util.describe_node(tree[root])) for item in sorted(treeinfo['itemlike']): if listinfo.get_lca(tree, [root, item]) == root: print(" NODE:", util.describe_node(tree[item])) for field in sorted(treeinfo['dupid']): if listinfo.get_lca(tree, [item, field]) == item: print(" FIELD:", util.describe_node(tree[field])) return elif cmd == 'webon': config.GRAB_WEBVIEW = True return elif cmd == 'weboff': config.GRAB_WEBVIEW = False return elif cmd.startswith('ob '): prop = cmd.split(' ', 1)[1] wd = watchdog.Watchdog(100000) smgr = statemgr.StateMgr(tlib, None, dev, ob, wd) ret = smgr.observe_prop(prop, st) if ret: print("prop %s = %s" % (prop, st.get(prop, ''))) else: print("observe error") return elif cmd.startswith('clean '): parts = cmd.split(' ', 2) if len(parts) == 2: prop = parts[1] val = "1" else: (prop, val) = parts[1:] wd = watchdog.Watchdog(100000) smgr = statemgr.StateMgr(tlib, None, dev, ob, wd) ret = smgr.cleanup_prop(prop, val, st) if ret: print("prop %s cleaned" % prop) else: print("clean error") return elif cmd.startswith('oc '): prop = cmd.split(' ', 1)[1] wd = watchdog.Watchdog(100000) smgr = statemgr.StateMgr(tlib, None, dev, ob, wd) ret = smgr.observe_and_clean(prop, st) if ret: print("prop %s is clean now" % prop) else: print("observe/clean error") return elif cmd == 'dbg': print(tlib) return elif cmd.startswith('skip '): name = cmd.split(' ', 1)[1] add_skip(app, name) print("skipping %s" % name) return elif cmd == 'skip': skips = load_skip(app) for skip in skips: print("now skipping %s" % skip) return elif cmd.startswith('noskip '): name = cmd.split(' ', 1)[1] del_skip(app, name) print("not skipping %s" % name) return elif cmd == 'src': if st.get('xml') is not None: print(st.get('xml')) if st.get('src') is not None: print(st.get('src')) return elif cmd == 'install': apputils.install(dev, app) return elif cmd == 'uninstall': apputils.uninstall(dev, app) return op = operation.parse_line(cmd) if op is None: print("unknown op") return ret = op.do(dev, ob, st, env, tlib) if not ret: print("op failed")
def uninstall(dev, appname): app = appdb.get_app(appname) dev.run_adb_shell("pm uninstall %s" % app) return True
def set_app(self, appname): self.appname = appname self.app = appdb.get_app(appname)
else: logger.error("ERROR! parent missing!") def dump(self): dumper = objdump.ObjDumper(self.props) return dumper.dump(self) def load(self, s): dumper = objdump.ObjDumper(self.props) return dumper.load(self, s) if __name__ == "__main__": logging.basicConfig(level=logging.INFO) import appdb appdb.collect_apps("../apks/") serial = sys.argv[1] app = sys.argv[2] appname = appdb.get_app(app) import device dev = device.Device(serial=serial, no_uimon=True) webgrabber = WebGrabber(appname) pages = webgrabber.find_webviews(dev) for page in pages: webgrabber.capture_webnodes(dev, page, print_nodes=True) webgrabber.check_convert() webgrabber.clear()
def do(self, dev, observer, state, env, tlib): logger.info("doing %s", self) perfmon.record_start("op", self) if self.name == 'call': realargs = [] for arg in self.attr['args']: realargs.append(arg.get(env)) return tlib.call(self.attr['func'], realargs, dev, observer, state) elif self.name == 'not': return not self.attr['op'].do(dev, observer, state, env, tlib) elif self.name == 'restart': appname = appdb.get_app(tlib.app) return microtest.restart_test(appname).attempt( dev, observer, state, tlib, env) widgets = [] if self.target is not None: logger.info("finding target %s", self.target) perfmon.record_start("find", "%s" % self.target) state = observer.grab_state(dev) init_scr = state.get('screen') last_state = state for scroll_count in range(config.NOTFOUND_SCROLLDOWN_LIMIT): widgets = self.target.locate(state, observer, env) if widgets != []: break if self.target.no_scroll(): logger.info("not found, scroll forbidden, fail") perfmon.record_stop("find", "%s" % self.target) return False logger.info("%s not found, scroll down", self.target) scroll_act = action.Action("scroll", {'direction': 'down'}) if not scroll_act.do(dev, observer, env): logger.info("nothing to scroll, fail") perfmon.record_stop("find", "%s" % self.target) return False state = observer.grab_state(dev, known_scr=init_scr) if state.same_as(last_state): logger.info("scrolled to the bottom") break # TODO: hack! tlib.handle_sys_screen(state, dev, observer) if widgets == []: for scroll_count in range(config.NOTFOUND_SCROLLUP_LIMIT): widgets = self.target.locate(state, observer, env) if widgets != []: break logger.info("%s not found, scroll up", self.target) scroll_act = action.Action("scroll", {'direction': 'up'}) if not scroll_act.do(dev, observer, env): logger.info("nothing to scroll, fail") perfmon.record_stop("find", "%s" % self.target) return False state = observer.grab_state(dev, known_scr=init_scr) if state.same_as(last_state): logger.info("scrolled to the top") break # TODO: hack! tlib.handle_sys_screen(state, dev, observer) if widgets == []: logger.warn("fail to find %s", self.target) return False perfmon.record_stop("find", "%s" % self.target) logger.info("found %s", widgets[0]) actions = self.to_actions(widgets, env) if actions is None: return False for act in actions: ret = act.do(dev, observer, env) if not ret: return False # TODO: maybe wait for idle? time.sleep(0.1) usedtime = perfmon.record_stop("op", self) logger.info("%s finished %.3fs", self, usedtime) return True