def tearDown(self): self.m_logger.debug('First try - quit emulator by adb emu kill') adb_binary = path_utils.get_adb_binary() kill_proc = psutil.Popen([adb_binary, "emu", "kill"]) # check emulator process is terminated result = self.term_check(timeout=5) if not result: self.m_logger.debug('Second try - quit emulator by psutil') self.kill_proc_by_name(["emulator", "qemu-system"]) result = self.term_check(timeout=10) self.m_logger.debug("term_check after psutil.kill - %s", result) self.m_logger.info("Remove AVD inside of tear down") # avd should be found $HOME/.android/avd/ avd_dir = os.path.join(os.path.expanduser('~'), '.android', 'avd') try: if result and self.start_proc: self.start_proc.wait() time.sleep(1) self.kill_proc_by_name(["crash-service", "adb"]) os.remove(os.path.join(avd_dir, '%s.ini' % self.avd_config.name())) shutil.rmtree(os.path.join(avd_dir, '%s.avd' % self.avd_config.name()), ignore_errors=True) except Exception, e: self.m_logger.error("Error in cleanup - %r", e) pass
def adb_power_key(): """ Simulate touching the power button on the running emulator. '26' maps to "KEYCODE_POWER" event code. :return: None. """ adb_binary = path_utils.get_adb_binary() time.sleep(2) subprocess.call([adb_binary, 'shell', 'input', 'keyevent', '26']) time.sleep(2)
def adb_input_text(textstr): """ Perform a simulated text input on the running emulator, using the passed textstr as the simulated input. :param textstr: String we wish to 'type' into the emulator. :return: None. """ adb_binary = path_utils.get_adb_binary() time.sleep(2) subprocess.call([adb_binary, 'shell', 'input', 'text', textstr]) time.sleep(2)
def adb_touch(x, y): """ Perform a emulated touch action at the x,y coordinates passed. :param x: X position where we wish to perform emulated touch. :param y: Y position where we wish to perform emulated touch. :return: None. """ adb_binary = path_utils.get_adb_binary() time.sleep(2) subprocess.call([adb_binary, 'shell', 'input', 'tap', x, y]) time.sleep(2)
def emu_console_finger_touch(finger): """ Simulate a fingerprint touch on the running emulator. 'finger' is the registered fingerprint we are simulating. :param finger: Int representing the finger we are simulating a touch for. eg. '1' means simulate touch of first registered finger. :return: None. """ adb_binary = path_utils.get_adb_binary() time.sleep(2) subprocess.call([adb_binary, 'emu', 'finger', 'touch', finger]) time.sleep(2)
def kill_emulator(self): self.m_logger.debug('First try - quit emulator by adb emu kill') adb_binary = path_utils.get_adb_binary() kill_proc = psutil.Popen([adb_binary, "emu", "kill"]).communicate() # Check emulator process is terminated result = self.term_check(timeout=5) if not result: self.m_logger.info('Second try - quit emulator by psutil') self.kill_proc_by_name(["emulator", "qemu-system"]) result = self.term_check(timeout=10) self.m_logger.info("term_check after psutil.kill - %s" % result) return result
def dump_and_pull_screen_xml(filepath): """ Call into ADB to dump out the current window_dump.xml file. Then copy the dumped file to filepath. :param filepath: Local filesystem path to copy the window_dump.xml file to. :return: None. """ adb_binary = path_utils.get_adb_binary() subprocess.call( [adb_binary, '-s', g_emulator_serial, 'shell', 'uiautomator', 'dump']) subprocess.call([ adb_binary, '-s', g_emulator_serial, 'pull', '/sdcard/window_dump.xml', filepath ])
def do_activity_test(): """ Using adb, dump the current stack list and pull down the dump to the local filesystem. Then check this dump file to see if one of the EXPECTED_LAUNCHERS is labeled as the top_activity. :return: Boolean. Return of function find_home_activity. True if EXPECTED_LAUNCHER is topActivity. False otherwise. """ adb_binary = path_utils.get_adb_binary() subprocess.call([ adb_binary, 'shell', 'am', 'stack', 'list', '>', '/data/local/tmp/activity.txt' ]) subprocess.call([adb_binary, 'pull', '/data/local/tmp/activity.txt']) return find_home_activity('activity.txt')
def do_fingerprint_test(): """ Perform a fingerprint test on the running emulator. This is done in the following order: 1. Enroll a fingerprint. 2. Turn off the screen. 3. Turn on the screen. 4. Check that the screen reports as locked once powered on. 5. Simulate a fingerprint touch. 6. Check that the screen is reporting as unlocked. :return: """ try: adb_binary = path_utils.get_adb_binary() # Start the fingerprint enroll process. Then simulate enrollment of finger '1'. subprocess.call([ adb_binary, 'shell', 'am', 'start', '-n', 'com.android.settings/com.android.settings.fingerprint.FingerprintEnrollIntroduction' ]) adb_touch_button('NEXT') adb_touch_button('Fingerprint + PIN') adb_touch_button('NO') adb_input_text('1111') adb_touch_button('NEXT') adb_input_text('1111') adb_touch_button('CONFIRM') adb_touch_button('DONE') emu_console_finger_touch('1') emu_console_finger_touch('1') emu_console_finger_touch('1') adb_touch_button('DONE') # Test that we successfully unlock the device. We will try 3 times. for tries in range(0, 3): # Turn off the screen adb_power_key() # Turn on the screen adb_power_key() # Check if the device reports as locked check_screen_is_locked() # Simulate fingerprint touch. emu_console_finger_touch('1') # Check if the device reports as unlocked. ret = check_screen_is_unlocked() if ret: print 'Successfully tested fingerprint test.' return True return False except Exception as e: print 'Exception occurred while attempting fingerprint test' print traceback.format_exc() return False
def check_screen_is_locked(): """ Check if the screen is currently locked on the running emulator. :return: Boolean. True if the screen is locked. False if the screen is unlocked. """ adb_binary = path_utils.get_adb_binary() ret1 = subprocess.call([ adb_binary, 'shell', 'dumpsys', 'deviceidle', '|', 'grep', 'mScreenLocked=true' ]) if ret1: print 'Emulated screen is not reporting as locked.' return False else: print 'Emulated screen is reporting as locked.' return True
def run_adb_perf(self, avd): """ Performs an ADB test on the given AVD. The test consists of calling ADB push/pull on .zip files and return the time that these operations take. The small_file.zip is 21Mb. The large_file.zip is 121Mb. :param avd: The AVD we will be performing the test on. :return: None. Results are printed to self.m_logger """ test_file = "large_file.zip" local_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "adb_test_data", test_file) file_size = os.path.getsize(local_path) device_path = "/data/local/tmp/%s" % test_file adb_binary = path_utils.get_adb_binary() push_cmd = [adb_binary, "push", local_path, device_path] pull_cmd = [adb_binary, "pull", device_path, "."] run_time = [] for cmd in [push_cmd, pull_cmd]: try: start_time = time.time() (exit_code, stdout, stderr) = self.run_with_timeout(cmd, 600) # deduct 0.015 seconds for the overhead of sending adb command (this is arbitrarily chosen). elapsed_time = time.time() - start_time - 0.015 calculated_speed = (file_size / 1024) / elapsed_time speed = "%.0f KB/s" % calculated_speed self.m_logger.info( 'Cmd: %s, Time elapsed: %s, File size: %s, speed: %s' % (' '.join(cmd), elapsed_time, file_size, speed)) if exit_code == 0: run_time.append(speed) else: self.m_logger.info( 'Failed to run adb performance test cmd: %s, exit_code: %s' % (' '.join(cmd), exit_code)) return except Exception as e: if os.path.isfile(test_file): os.unlink(test_file) self.m_logger.error('Exception for run_with_timeout %s:' % ' '.join(cmd)) print 'Exception Thrown: ' + traceback.format_exc() return if os.path.isfile(test_file): os.unlink(test_file) self.m_logger.info( 'AVD %s ADB Performance test, adb push: %s, adb pull: %s' % (str(avd), run_time[0], run_time[1]))
def do_popup_test(): """ Dump the current UI Window hierarchy and pull down this file. Search this file to see if we can find the target EXPECTED_LAUNCHERS entry. :return: Boolean. True if we find one of the expected launchers. False otherwise. """ adb_binary = path_utils.get_adb_binary() subprocess.call([adb_binary, 'shell', 'uiautomator', 'dump']) subprocess.call( [adb_binary, 'pull', '/sdcard/window_dump.xml', 'topscreen.xml']) root = parse_xml('topscreen.xml') os.remove('topscreen.xml') for launcher in EXPECTED_LAUNCHERS: active_launcher = find_package(root, launcher) if active_launcher: return True print 'Failed to find one of Launchers %s' % ",".join(EXPECTED_LAUNCHERS) return False
def run_script_run_adb_shell(testcase_call_dir): """Run Python script to install apk. Run Python script to install Rest Service app and corresponding test on Emulator; on emulator, do a port forwarding from tcp:8080 to tcp:8081. Args: testcase_call_dir: The directory where the test case is called from. """ script_run_adb_shell = ('%s/%s' % (testcase_call_dir, SCRIPT_TO_RUN_ADB_SHELL)) script_install_apk = '%s/%s' % (testcase_call_dir, SCRIPT_TO_INSTALL_APK) adb_binary = path_utils.get_adb_binary() subprocess.call([ adb_binary, '-s', 'emulator-%s' % str(CONSOLE_PORT), '-e', 'forward', 'tcp:8080', 'tcp:8081' ]) subprocess.call([PYTHON_INTERPRETER, script_install_apk]) subprocess.Popen([PYTHON_INTERPRETER, script_run_adb_shell]) time.sleep(SETUP_WAIT_TIMEOUT_S)
def check_network_connectivity(self): """ Calls into ADB to get 'dumpsys connectivity' output. Parses this output to confirm network connectivity settings. :return: Boolean. False if environment appears incorrect. True otherwise. """ adb_binary = path_utils.get_adb_binary() ret, stdout, stderr = self.run_with_timeout( [adb_binary, 'shell', 'dumpsys', 'connectivity'], 60) numNetworkReg = r'Active default network: (?P<numNetworkStr>\d+)' numNetworkMatch = re.search(numNetworkReg, stdout) hasNumNetwork = numNetworkMatch and numNetworkMatch.group( 'numNetworkStr') > 0 dnsSuccessReg = r'PROBE_DNS (.*) OK' dnsSuccess = re.search(dnsSuccessReg, stdout) if not hasNumNetwork or not dnsSuccess: self.m_logger.error('adb shell dumpsys connectivity returns: %s' % stdout) return False return True
def launch_logcat_in_thread(logcat_filepath): """ Launches a logcat instance in a new psutil.Popen() call. Logcat output is directed to a txt file named "testcase_logcat.txt". Called as a target to the threading library so this runs in its own thread, not as part of the main test thread. :param logcat_filepath: Location where we will write logcat output. :return: None. Returns when emulator is no longer found. """ with open(logcat_filepath, 'a') as output: local_test_name = self.id().rsplit('.', 1)[-1] logcat_proc = None while True: if logcat_proc is None or logcat_proc.poll() is not None: self.m_logger.info( 'Launching logcat for test %s at location %s' % (local_test_name, logcat_filepath)) output.flush() output.write("----Starting logcat----\n") output.flush() adb_binary = path_utils.get_adb_binary() logcat_proc = psutil.Popen([adb_binary, "logcat"], stdout=output, stderr=STDOUT) time.sleep(10) if not self.find_emu_proc(): self.m_logger.info( 'No emulator found, stopping logcat %s' % local_test_name) break if logcat_proc: try: logcat_proc.terminate() except: # Could not terminate logcat; probably already dead. print "Exception Thrown. Logcat is not found even though it is expected." print traceback.format_exc() pass
def launch_emu_and_wait(self, avd): """ Attempts to launch the passed in AVD. Emulator Binary and other system settings are contained within emu_argparser.emy_args. The emulator is started in a separate thread. The timeout that is passed in via emu_argparser.emu_args.expected_boot_time is the timeout value of the 'wait' -> it is not forever. For API P, we also check network connection. :param avd: AVD we wish to launch. :return: Boot time (in seconds) it took to get a fully booted emulator. """ adb_binary = path_utils.get_adb_binary() self.run_with_timeout([adb_binary, 'kill-server'], 20) self.run_with_timeout([adb_binary, 'start-server'], 20) launcher_emu = threading.Thread(target=self.launch_emu, args=[avd]) launcher_emu.start() start_time = time.time() completed = '0' counter = 0 real_time_out = emu_argparser.emu_args.expected_boot_time # We wait 20 seconds after attempting to start the emulator before polling ADB. This is because the ADB # Daemon can be unresponsive on some machines during the startup period with the device. time.sleep(20) stdout = None stderr = None # While loop implements the timeout check by constantly checking the current run time against timeout. while (time.time() - start_time) < real_time_out: # We use ADB to directly look at the emulator instance and see if its marked as booted. cmd = [adb_binary, 'shell', 'getprop', 'sys.boot_completed'] try: (exit_code, stdout, stderr) = self.run_with_timeout(cmd, 10) except Exception: self.m_logger.error( 'Failed in call to ADB when looking for sys.boot_completed property.' ) print 'Exception Thrown: ' + traceback.format_exc() continue # We will print out a status message every 20 invocations. Keeps the log updated without spamming. if counter % 20 is 0: self.m_logger.info( 'Boot Timeout Max is set to %s, current is %s' % (real_time_out, time.time() - start_time)) self.m_logger.info( 'Ping AVD %s for boot completion. stdout: %s stderr: %s' % (str(avd), stdout.strip(), stderr.strip())) counter = counter + 1 if exit_code is 0: completed = stdout.strip() if completed is "1": self.m_logger.info( 'AVD %s is fully booted. getprop sys.boot_completed = 1' % str(avd)) break time.sleep(1) if completed is not "1": self.m_logger.info( 'ADB Failed to detect a booted emulator and timeout has been reached.' ) self.m_logger.info('Command: %s') self.m_logger.info('stdout: %s' % stdout) self.m_logger.info('stderr: %s' % stderr) self.m_logger.error('AVD %s didn\'t boot up within %s seconds' % (str(avd), real_time_out)) self.boot_time = -1 raise TimeoutError(avd, real_time_out) self.boot_time = time.time() - start_time self.m_logger.info('AVD %s, boot time is %s' % (str(avd), self.boot_time)) if 'apiP' in str(avd): network_succeeded = False # Spend 3 mins (180 seconds) to check for network for i in range(18): time.sleep(10) # Connectivity check for P network_succeeded = self.check_network_connectivity() if network_succeeded: self.m_logger.info('Network check succeeded.') break if not network_succeeded: raise Exception( 'Network check error. Failed to parse proper output.') if 'wear' in str(avd) or 'tv' in str(avd) or 'car' in str(avd): # We do not perform a homescreen or fingerprint test for these images. self.m_logger.info( "Detected 'wear', 'tv' or 'car' AVD. Skip Homescreen / Fingerprint tests." ) elif 'google_apis' in str(avd): # Perform a homescreen test first. self.m_logger.info("Begin homescreen test for phone device.") homescreen_succeeded = test_homescreen.do_homescreen_test() if homescreen_succeeded: self.m_logger.info( "Homescreen test for phone device succeeded.") else: self.m_logger.info( "Homescreen test for phone device failed.") # Perform a fingerprint test. self.m_logger.info("Begin fingerprint test for phone device.") fingerprint_succeeded = test_fingerprint.do_fingerprint_test() if not fingerprint_succeeded: # for now, just issue some message, later will turn it into exception self.m_logger.info( "Fingerprint test for phone device failed.") #raise Exception('Fingerprint check error') else: self.m_logger.info( "Fingerprint test for phone device succeeded.") launcher_emu.join(10) if not emu_argparser.emu_args.skip_adb_perf: self.run_adb_perf(avd) return self.boot_time
subunit_file = emu_argparser.emu_args.subunit_file if subunit_file and not subunit_run: err_msg = "Subunit requested, yet subunit is not installed." raise Exception(err_msg) if emu_argparser.emu_args.avd_list is None: emu_argparser.emu_args.avd_list = findSystemAVDs() test_root_dir = os.path.dirname(os.path.realpath(__file__)) emuSuite = unittest.TestLoader().discover( start_dir=test_root_dir, pattern=emu_argparser.emu_args.pattern) if subunit_file: with open(subunit_file, 'ab') as stream: emuRunner = subunit_run.SubunitTestRunner(stream=stream) emuResult = emuRunner.run(emuSuite) else: emuRunner = emu_unittest.EmuTextTestRunner(stream=sys.stdout) emuResult = emuRunner.run(emuSuite) printResult(emuResult) except Exception: print "Error in dotest.py : " + traceback.format_exc() # Always attempt to kill the adb server. We are now done testing with it. try: adb_binary = path_utils.get_adb_binary() check_call([adb_binary, 'kill-server'], stdout=PIPE, stdin=PIPE) except CalledProcessError: print "Error shutting down adb. Error: " + traceback.format_exc() sys.exit(not emuResult.wasSuccessful())