1*9c5db199SXin Li# Lint as: python2, python3 2*9c5db199SXin Li# Copyright 2015 The Chromium OS Authors. All rights reserved. 3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 4*9c5db199SXin Li# found in the LICENSE file. 5*9c5db199SXin Li 6*9c5db199SXin Lifrom __future__ import absolute_import 7*9c5db199SXin Lifrom __future__ import division 8*9c5db199SXin Lifrom __future__ import print_function 9*9c5db199SXin Li 10*9c5db199SXin Liimport collections 11*9c5db199SXin Liimport glob 12*9c5db199SXin Liimport logging 13*9c5db199SXin Liimport os 14*9c5db199SXin Liimport pipes 15*9c5db199SXin Liimport shutil 16*9c5db199SXin Liimport socket 17*9c5db199SXin Liimport sys 18*9c5db199SXin Liimport tempfile 19*9c5db199SXin Liimport time 20*9c5db199SXin Li 21*9c5db199SXin Lifrom autotest_lib.client.bin import test, utils 22*9c5db199SXin Lifrom autotest_lib.client.common_lib import error 23*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import chrome, arc_common 24*9c5db199SXin Lifrom six.moves import range 25*9c5db199SXin Li 26*9c5db199SXin Li_ADB_KEYS_PATH = '/tmp/adb_keys' 27*9c5db199SXin Li_ADB_VENDOR_KEYS = 'ADB_VENDOR_KEYS' 28*9c5db199SXin Li_ANDROID_CONTAINER_PID_PATH = '/run/containers/android*/container.pid' 29*9c5db199SXin Li_ANDROID_DATA_ROOT_PATH = '/opt/google/containers/android/rootfs/android-data' 30*9c5db199SXin Li_ANDROID_CONTAINER_ROOT_PATH = '/opt/google/containers/android/rootfs' 31*9c5db199SXin Li_SCREENSHOT_DIR_PATH = '/var/log/arc-screenshots' 32*9c5db199SXin Li_SCREENSHOT_BASENAME = 'arc-screenshot' 33*9c5db199SXin Li_MAX_SCREENSHOT_NUM = 10 34*9c5db199SXin Li# This address should match the one present in 35*9c5db199SXin Li# https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/main/chromeos-base/arc-sslh-init/files/sslh.conf 36*9c5db199SXin Li_ADBD_ADDRESS = ('100.115.92.2', 5555) 37*9c5db199SXin Li_ADBD_PID_PATH = '/run/arc/adbd.pid' 38*9c5db199SXin Li_SDCARD_PID_PATH = '/run/arc/sdcard.pid' 39*9c5db199SXin Li_ANDROID_ADB_KEYS_PATH = '/data/misc/adb/adb_keys' 40*9c5db199SXin Li_PROCESS_CHECK_INTERVAL_SECONDS = 1 41*9c5db199SXin Li_PROPERTY_CHECK_INTERVAL_SECONDS = 1 42*9c5db199SXin Li_WAIT_FOR_ADB_READY = 60 43*9c5db199SXin Li_WAIT_FOR_ANDROID_PROCESS_SECONDS = 60 44*9c5db199SXin Li_PLAY_STORE_PKG = 'com.android.vending' 45*9c5db199SXin Li_SETTINGS_PKG = 'com.android.settings' 46*9c5db199SXin Li 47*9c5db199SXin Li 48*9c5db199SXin Lidef setup_adb_host(): 49*9c5db199SXin Li """Setup ADB host keys. 50*9c5db199SXin Li 51*9c5db199SXin Li This sets up the files and environment variables that wait_for_adb_ready() 52*9c5db199SXin Li needs""" 53*9c5db199SXin Li if _ADB_VENDOR_KEYS in os.environ: 54*9c5db199SXin Li return 55*9c5db199SXin Li if not os.path.exists(_ADB_KEYS_PATH): 56*9c5db199SXin Li os.mkdir(_ADB_KEYS_PATH) 57*9c5db199SXin Li # adb expects $HOME to be writable. 58*9c5db199SXin Li os.environ['HOME'] = _ADB_KEYS_PATH 59*9c5db199SXin Li 60*9c5db199SXin Li # Generate and save keys for adb if needed 61*9c5db199SXin Li key_path = os.path.join(_ADB_KEYS_PATH, 'test_key') 62*9c5db199SXin Li if not os.path.exists(key_path): 63*9c5db199SXin Li utils.system('adb keygen ' + pipes.quote(key_path)) 64*9c5db199SXin Li os.environ[_ADB_VENDOR_KEYS] = key_path 65*9c5db199SXin Li 66*9c5db199SXin Li 67*9c5db199SXin Lidef restart_adbd(timeout): 68*9c5db199SXin Li """Restarts the adb daemon. 69*9c5db199SXin Li 70*9c5db199SXin Li Follows the same logic as tast. 71*9c5db199SXin Li """ 72*9c5db199SXin Li logging.debug('restarting adbd') 73*9c5db199SXin Li config = 'adb' 74*9c5db199SXin Li _android_shell('setprop persist.sys.usb.config ' + config) 75*9c5db199SXin Li _android_shell('setprop sys.usb.config ' + config) 76*9c5db199SXin Li 77*9c5db199SXin Li def property_check(): 78*9c5db199SXin Li return _android_shell('getprop sys.usb.state') == config 79*9c5db199SXin Li 80*9c5db199SXin Li try: 81*9c5db199SXin Li utils.poll_for_condition( 82*9c5db199SXin Li condition=property_check, 83*9c5db199SXin Li desc='Wait for sys.usb.state', 84*9c5db199SXin Li timeout=timeout, 85*9c5db199SXin Li sleep_interval=_PROPERTY_CHECK_INTERVAL_SECONDS) 86*9c5db199SXin Li except utils.TimeoutError: 87*9c5db199SXin Li raise error.TestFail('Timed out waiting for sys.usb.state change') 88*9c5db199SXin Li 89*9c5db199SXin Li _android_shell('setprop ctl.restart adbd') 90*9c5db199SXin Li 91*9c5db199SXin Li 92*9c5db199SXin Lidef restart_adb(): 93*9c5db199SXin Li """Restarts adb. 94*9c5db199SXin Li 95*9c5db199SXin Li Follows the same logic as in tast, specifically avoiding kill-server 96*9c5db199SXin Li since it is unreliable (crbug.com/855325). 97*9c5db199SXin Li """ 98*9c5db199SXin Li logging.debug('killing and restarting adb server') 99*9c5db199SXin Li utils.system('killall --quiet --wait -KILL adb') 100*9c5db199SXin Li utils.system('adb start-server') 101*9c5db199SXin Li 102*9c5db199SXin Li 103*9c5db199SXin Lidef is_adb_connected(): 104*9c5db199SXin Li """Return true if adb is connected to the container.""" 105*9c5db199SXin Li output = utils.system_output('adb get-state', ignore_status=True) 106*9c5db199SXin Li logging.debug('adb get-state: %s', output) 107*9c5db199SXin Li return output.strip() == 'device' 108*9c5db199SXin Li 109*9c5db199SXin Li 110*9c5db199SXin Lidef _is_android_data_mounted(): 111*9c5db199SXin Li """Return true if Android's /data is mounted with partial boot enabled.""" 112*9c5db199SXin Li return _android_shell('getprop ro.data_mounted', ignore_status=True) == '1' 113*9c5db199SXin Li 114*9c5db199SXin Li 115*9c5db199SXin Lidef get_zygote_type(): 116*9c5db199SXin Li """Return zygote service type.""" 117*9c5db199SXin Li return _android_shell('getprop ro.zygote', ignore_status=True) 118*9c5db199SXin Li 119*9c5db199SXin Li 120*9c5db199SXin Lidef get_sdk_version(): 121*9c5db199SXin Li """Return the SDK level version for Android.""" 122*9c5db199SXin Li return _android_shell('getprop ro.build.version.sdk') 123*9c5db199SXin Li 124*9c5db199SXin Li 125*9c5db199SXin Lidef get_product(): 126*9c5db199SXin Li """Return the product string used for the Android build.""" 127*9c5db199SXin Li return _android_shell('getprop ro.build.product', ignore_status=True) 128*9c5db199SXin Li 129*9c5db199SXin Li 130*9c5db199SXin Lidef _is_tcp_port_reachable(address): 131*9c5db199SXin Li """Return whether a TCP port described by |address| is reachable.""" 132*9c5db199SXin Li try: 133*9c5db199SXin Li s = socket.create_connection(address) 134*9c5db199SXin Li s.close() 135*9c5db199SXin Li return True 136*9c5db199SXin Li except socket.error: 137*9c5db199SXin Li return False 138*9c5db199SXin Li 139*9c5db199SXin Li 140*9c5db199SXin Lidef _wait_for_data_mounted(timeout): 141*9c5db199SXin Li utils.poll_for_condition( 142*9c5db199SXin Li condition=_is_android_data_mounted, 143*9c5db199SXin Li desc='Wait for /data mounted', 144*9c5db199SXin Li timeout=timeout, 145*9c5db199SXin Li sleep_interval=_PROCESS_CHECK_INTERVAL_SECONDS) 146*9c5db199SXin Li 147*9c5db199SXin Li 148*9c5db199SXin Lidef wait_for_adb_ready(timeout=_WAIT_FOR_ADB_READY): 149*9c5db199SXin Li """Wait for the ADB client to connect to the ARC container. 150*9c5db199SXin Li 151*9c5db199SXin Li @param timeout: Timeout in seconds. 152*9c5db199SXin Li """ 153*9c5db199SXin Li # Although adbd is started at login screen, we still need /data to be 154*9c5db199SXin Li # mounted to set up key-based authentication. /data should be mounted 155*9c5db199SXin Li # once the user has logged in. 156*9c5db199SXin Li 157*9c5db199SXin Li initial_timeout = timeout 158*9c5db199SXin Li 159*9c5db199SXin Li start_time = time.time() 160*9c5db199SXin Li _wait_for_data_mounted(timeout) 161*9c5db199SXin Li timeout -= (time.time() - start_time) 162*9c5db199SXin Li start_time = time.time() 163*9c5db199SXin Li arc_common.wait_for_android_boot(timeout) 164*9c5db199SXin Li timeout -= (time.time() - start_time) 165*9c5db199SXin Li 166*9c5db199SXin Li setup_adb_host() 167*9c5db199SXin Li if is_adb_connected(): 168*9c5db199SXin Li return 169*9c5db199SXin Li 170*9c5db199SXin Li # Push keys for adb. 171*9c5db199SXin Li pubkey_path = os.environ[_ADB_VENDOR_KEYS] + '.pub' 172*9c5db199SXin Li with open(pubkey_path, 'r') as f: 173*9c5db199SXin Li _write_android_file(_ANDROID_ADB_KEYS_PATH, f.read()) 174*9c5db199SXin Li _android_shell('chown shell ' + pipes.quote(_ANDROID_ADB_KEYS_PATH)) 175*9c5db199SXin Li _android_shell('restorecon ' + pipes.quote(_ANDROID_ADB_KEYS_PATH)) 176*9c5db199SXin Li 177*9c5db199SXin Li attempt_count = 3 178*9c5db199SXin Li timeout = timeout / attempt_count 179*9c5db199SXin Li 180*9c5db199SXin Li for i in range(attempt_count): 181*9c5db199SXin Li if _restart_adb_and_wait_for_ready(timeout): 182*9c5db199SXin Li return 183*9c5db199SXin Li raise error.TestFail( 184*9c5db199SXin Li 'Failed to connect to adb in %d seconds.' % initial_timeout) 185*9c5db199SXin Li 186*9c5db199SXin Li 187*9c5db199SXin Lidef _restart_adb_and_wait_for_ready(timeout): 188*9c5db199SXin Li """Restart adb/adbd and wait adb connection is ready. 189*9c5db199SXin Li 190*9c5db199SXin Li @param timeout: Timeout in seconds. 191*9c5db199SXin Li @return True in case adb connection was established or throw an error in 192*9c5db199SXin Li case persistent error occured. 193*9c5db199SXin Li """ 194*9c5db199SXin Li 195*9c5db199SXin Li # Restart adbd and adb. 196*9c5db199SXin Li start_time = time.time() 197*9c5db199SXin Li restart_adbd(timeout) 198*9c5db199SXin Li timeout -= (time.time() - start_time) 199*9c5db199SXin Li start_time = time.time() 200*9c5db199SXin Li restart_adb() 201*9c5db199SXin Li timeout -= (time.time() - start_time) 202*9c5db199SXin Li 203*9c5db199SXin Li try: 204*9c5db199SXin Li utils.poll_for_condition(condition=is_adb_connected, 205*9c5db199SXin Li timeout=timeout) 206*9c5db199SXin Li return True 207*9c5db199SXin Li except (utils.TimeoutError): 208*9c5db199SXin Li # The operation has failed, but let's try to clarify the failure to 209*9c5db199SXin Li # avoid shifting blame to adb. 210*9c5db199SXin Li 211*9c5db199SXin Li # First, collect some information and log it. 212*9c5db199SXin Li arc_alive = is_android_container_alive() 213*9c5db199SXin Li arc_booted = _android_shell('getprop ro.arc.boot_completed', 214*9c5db199SXin Li ignore_status=True) 215*9c5db199SXin Li arc_system_events = _android_shell( 216*9c5db199SXin Li 'logcat -d -b events *:S arc_system_event', ignore_status=True) 217*9c5db199SXin Li adbd_pid = _android_shell('pidof -s adbd', ignore_status=True) 218*9c5db199SXin Li adbd_port_reachable = _is_tcp_port_reachable(_ADBD_ADDRESS) 219*9c5db199SXin Li adb_state = utils.system_output('adb get-state', ignore_status=True) 220*9c5db199SXin Li logging.debug('ARC alive: %s', arc_alive) 221*9c5db199SXin Li logging.debug('ARC booted: %s', arc_booted) 222*9c5db199SXin Li logging.debug('ARC system events: %s', arc_system_events) 223*9c5db199SXin Li logging.debug('adbd process: %s', adbd_pid) 224*9c5db199SXin Li logging.debug('adbd port reachable: %s', adbd_port_reachable) 225*9c5db199SXin Li logging.debug('adb state: %s', adb_state) 226*9c5db199SXin Li 227*9c5db199SXin Li # Now go through the usual suspects and raise nicer errors to make the 228*9c5db199SXin Li # actual failure clearer. 229*9c5db199SXin Li if not arc_alive: 230*9c5db199SXin Li raise error.TestFail('ARC is not alive.') 231*9c5db199SXin Li if arc_booted != '1': 232*9c5db199SXin Li raise error.TestFail('ARC did not finish booting.') 233*9c5db199SXin Li return False 234*9c5db199SXin Li 235*9c5db199SXin Li 236*9c5db199SXin Lidef grant_permissions(package, permissions): 237*9c5db199SXin Li """Grants permissions to a package. 238*9c5db199SXin Li 239*9c5db199SXin Li @param package: Package name. 240*9c5db199SXin Li @param permissions: A list of permissions. 241*9c5db199SXin Li 242*9c5db199SXin Li """ 243*9c5db199SXin Li for permission in permissions: 244*9c5db199SXin Li adb_shell('pm grant %s android.permission.%s' % ( 245*9c5db199SXin Li pipes.quote(package), pipes.quote(permission))) 246*9c5db199SXin Li 247*9c5db199SXin Li 248*9c5db199SXin Lidef adb_cmd(cmd, **kwargs): 249*9c5db199SXin Li """Executed cmd using adb. Must wait for adb ready. 250*9c5db199SXin Li 251*9c5db199SXin Li @param cmd: Command to run. 252*9c5db199SXin Li """ 253*9c5db199SXin Li # TODO(b/79122489) - Assert if cmd == 'root' 254*9c5db199SXin Li wait_for_adb_ready() 255*9c5db199SXin Li return utils.system_output('adb %s' % cmd, **kwargs) 256*9c5db199SXin Li 257*9c5db199SXin Li 258*9c5db199SXin Lidef adb_shell(cmd, **kwargs): 259*9c5db199SXin Li """Executed shell command with adb. 260*9c5db199SXin Li 261*9c5db199SXin Li @param cmd: Command to run. 262*9c5db199SXin Li """ 263*9c5db199SXin Li output = adb_cmd('shell %s' % pipes.quote(cmd), **kwargs) 264*9c5db199SXin Li # Some android commands include a trailing CRLF in their output. 265*9c5db199SXin Li if kwargs.pop('strip_trailing_whitespace', True): 266*9c5db199SXin Li output = output.rstrip() 267*9c5db199SXin Li return output 268*9c5db199SXin Li 269*9c5db199SXin Li 270*9c5db199SXin Lidef adb_install(apk, auto_grant_permissions=True, ignore_status=False): 271*9c5db199SXin Li """Install an apk into container. You must connect first. 272*9c5db199SXin Li 273*9c5db199SXin Li @param apk: Package to install. 274*9c5db199SXin Li @param auto_grant_permissions: Set to false to not automatically grant all 275*9c5db199SXin Li permissions. Most tests should not care. 276*9c5db199SXin Li @param ignore_status: Set to true to allow the install command to fail, 277*9c5db199SXin Li for example if you are installing multiple architectures and only need 278*9c5db199SXin Li one to succeed. 279*9c5db199SXin Li """ 280*9c5db199SXin Li flags = '-g' if auto_grant_permissions else '' 281*9c5db199SXin Li return adb_cmd('install -r -t %s %s' % (flags, apk), 282*9c5db199SXin Li timeout=60*5, 283*9c5db199SXin Li ignore_status=ignore_status) 284*9c5db199SXin Li 285*9c5db199SXin Li 286*9c5db199SXin Lidef adb_uninstall(apk): 287*9c5db199SXin Li """Remove an apk from container. You must connect first. 288*9c5db199SXin Li 289*9c5db199SXin Li @param apk: Package to uninstall. 290*9c5db199SXin Li """ 291*9c5db199SXin Li return adb_cmd('uninstall %s' % apk) 292*9c5db199SXin Li 293*9c5db199SXin Li 294*9c5db199SXin Lidef adb_reboot(): 295*9c5db199SXin Li """Reboots the container and block until container pid is gone. 296*9c5db199SXin Li 297*9c5db199SXin Li You must connect first. 298*9c5db199SXin Li """ 299*9c5db199SXin Li old_pid = get_container_pid() 300*9c5db199SXin Li logging.info('Trying to reboot PID:%s', old_pid) 301*9c5db199SXin Li adb_cmd('reboot', ignore_status=True) 302*9c5db199SXin Li # Ensure that the old container is no longer booted 303*9c5db199SXin Li utils.poll_for_condition( 304*9c5db199SXin Li lambda: not utils.pid_is_alive(int(old_pid)), timeout=10) 305*9c5db199SXin Li 306*9c5db199SXin Li 307*9c5db199SXin Li# This adb_root() function is deceiving in that it works just fine on debug 308*9c5db199SXin Li# builds of ARC (user-debug, eng). However "adb root" does not work on user 309*9c5db199SXin Li# builds as run by the autotest machines when testing prerelease images. In fact 310*9c5db199SXin Li# it will silently fail. You will need to find another way to do do what you 311*9c5db199SXin Li# need to do as root. 312*9c5db199SXin Li# 313*9c5db199SXin Li# TODO(b/79122489) - Remove this function. 314*9c5db199SXin Lidef adb_root(): 315*9c5db199SXin Li """Restart adbd with root permission.""" 316*9c5db199SXin Li 317*9c5db199SXin Li adb_cmd('root') 318*9c5db199SXin Li 319*9c5db199SXin Li 320*9c5db199SXin Lidef get_container_root(): 321*9c5db199SXin Li """Returns path to Android container root directory.""" 322*9c5db199SXin Li return _ANDROID_CONTAINER_ROOT_PATH 323*9c5db199SXin Li 324*9c5db199SXin Li 325*9c5db199SXin Lidef get_container_pid_path(): 326*9c5db199SXin Li """Returns the container's PID file path. 327*9c5db199SXin Li 328*9c5db199SXin Li Raises: 329*9c5db199SXin Li TestError if no PID file is found, or more than one files are found. 330*9c5db199SXin Li """ 331*9c5db199SXin Li # Find the PID file rather than the android-XXXXXX/ directory to ignore 332*9c5db199SXin Li # stale and empty android-XXXXXX/ directories when they exist. 333*9c5db199SXin Li arc_container_pid_files = glob.glob(_ANDROID_CONTAINER_PID_PATH) 334*9c5db199SXin Li 335*9c5db199SXin Li if len(arc_container_pid_files) == 0: 336*9c5db199SXin Li raise error.TestError('Android container.pid not available') 337*9c5db199SXin Li 338*9c5db199SXin Li if len(arc_container_pid_files) > 1: 339*9c5db199SXin Li raise error.TestError( 340*9c5db199SXin Li 'Multiple Android container.pid files found: %r. ' 341*9c5db199SXin Li 'Reboot your DUT to recover.' % (arc_container_pid_files)) 342*9c5db199SXin Li 343*9c5db199SXin Li return arc_container_pid_files[0] 344*9c5db199SXin Li 345*9c5db199SXin Li 346*9c5db199SXin Lidef get_android_data_root(): 347*9c5db199SXin Li """Returns path to ChromeOS directory that bind-mounts Android's /data.""" 348*9c5db199SXin Li return _ANDROID_DATA_ROOT_PATH 349*9c5db199SXin Li 350*9c5db199SXin Li 351*9c5db199SXin Lidef get_container_pid(): 352*9c5db199SXin Li """Returns the PID of the container.""" 353*9c5db199SXin Li return utils.read_one_line(get_container_pid_path()) 354*9c5db199SXin Li 355*9c5db199SXin Li 356*9c5db199SXin Lidef get_adbd_pid(): 357*9c5db199SXin Li """Returns the PID of the adbd proxy container.""" 358*9c5db199SXin Li if not os.path.exists(_ADBD_PID_PATH): 359*9c5db199SXin Li # The adbd proxy does not run on all boards. 360*9c5db199SXin Li return None 361*9c5db199SXin Li return utils.read_one_line(_ADBD_PID_PATH) 362*9c5db199SXin Li 363*9c5db199SXin Li 364*9c5db199SXin Lidef is_android_process_running(process_name): 365*9c5db199SXin Li """Return whether Android has completed booting. 366*9c5db199SXin Li 367*9c5db199SXin Li @param process_name: Process name. 368*9c5db199SXin Li """ 369*9c5db199SXin Li output = adb_shell('pgrep -c -f %s' % pipes.quote(process_name), 370*9c5db199SXin Li ignore_status=True) 371*9c5db199SXin Li return int(output) > 0 372*9c5db199SXin Li 373*9c5db199SXin Li 374*9c5db199SXin Lidef check_android_file_exists(filename): 375*9c5db199SXin Li """Checks whether the given file exists in the Android filesystem 376*9c5db199SXin Li 377*9c5db199SXin Li @param filename: File to check. 378*9c5db199SXin Li """ 379*9c5db199SXin Li return adb_shell( 380*9c5db199SXin Li 'test -e {} && echo FileExists'.format(pipes.quote(filename)), 381*9c5db199SXin Li ignore_status=True).find("FileExists") >= 0 382*9c5db199SXin Li 383*9c5db199SXin Li 384*9c5db199SXin Lidef read_android_file(filename): 385*9c5db199SXin Li """Reads a file in Android filesystem. 386*9c5db199SXin Li 387*9c5db199SXin Li @param filename: File to read. 388*9c5db199SXin Li """ 389*9c5db199SXin Li with tempfile.NamedTemporaryFile() as tmpfile: 390*9c5db199SXin Li adb_cmd('pull %s %s' % (pipes.quote(filename), 391*9c5db199SXin Li pipes.quote(tmpfile.name))) 392*9c5db199SXin Li with open(tmpfile.name) as f: 393*9c5db199SXin Li return f.read() 394*9c5db199SXin Li 395*9c5db199SXin Li return None 396*9c5db199SXin Li 397*9c5db199SXin Li 398*9c5db199SXin Lidef write_android_file(filename, data): 399*9c5db199SXin Li """Writes to a file in Android filesystem. 400*9c5db199SXin Li 401*9c5db199SXin Li @param filename: File to write. 402*9c5db199SXin Li @param data: Data to write. 403*9c5db199SXin Li """ 404*9c5db199SXin Li with tempfile.NamedTemporaryFile() as tmpfile: 405*9c5db199SXin Li tmpfile.write(data) 406*9c5db199SXin Li tmpfile.flush() 407*9c5db199SXin Li 408*9c5db199SXin Li adb_cmd('push %s %s' % (pipes.quote(tmpfile.name), 409*9c5db199SXin Li pipes.quote(filename))) 410*9c5db199SXin Li 411*9c5db199SXin Li 412*9c5db199SXin Lidef _write_android_file(filename, data): 413*9c5db199SXin Li """Writes to a file in Android filesystem. 414*9c5db199SXin Li 415*9c5db199SXin Li This is an internal function used to bootstrap adb. 416*9c5db199SXin Li Tests should use write_android_file instead. 417*9c5db199SXin Li """ 418*9c5db199SXin Li android_cmd = 'cat > %s' % pipes.quote(filename) 419*9c5db199SXin Li cros_cmd = 'android-sh -c %s' % pipes.quote(android_cmd) 420*9c5db199SXin Li utils.run(cros_cmd, stdin=data) 421*9c5db199SXin Li 422*9c5db199SXin Li 423*9c5db199SXin Lidef get_android_file_stats(filename): 424*9c5db199SXin Li """Returns an object of file stats for an Android file. 425*9c5db199SXin Li 426*9c5db199SXin Li The returned object supported limited attributes, but can be easily extended 427*9c5db199SXin Li if needed. Note that the value are all string. 428*9c5db199SXin Li 429*9c5db199SXin Li This uses _android_shell to run as root, so that it can access to all files 430*9c5db199SXin Li inside the container. On non-debuggable build, adb shell is not rootable. 431*9c5db199SXin Li """ 432*9c5db199SXin Li mapping = { 433*9c5db199SXin Li '%a': 'mode', 434*9c5db199SXin Li '%g': 'gid', 435*9c5db199SXin Li '%h': 'nlink', 436*9c5db199SXin Li '%u': 'uid', 437*9c5db199SXin Li } 438*9c5db199SXin Li output = _android_shell( 439*9c5db199SXin Li 'stat -c "%s" %s' % (' '.join(mapping.keys()), pipes.quote(filename)), 440*9c5db199SXin Li ignore_status=True) 441*9c5db199SXin Li stats = output.split(' ') 442*9c5db199SXin Li if len(stats) != len(mapping): 443*9c5db199SXin Li raise error.TestError('Unexpected output from stat: %s' % output) 444*9c5db199SXin Li _Stats = collections.namedtuple('_Stats', mapping.values()) 445*9c5db199SXin Li return _Stats(*stats) 446*9c5db199SXin Li 447*9c5db199SXin Li 448*9c5db199SXin Lidef remove_android_file(filename): 449*9c5db199SXin Li """Removes a file in Android filesystem. 450*9c5db199SXin Li 451*9c5db199SXin Li @param filename: File to remove. 452*9c5db199SXin Li """ 453*9c5db199SXin Li adb_shell('rm -f %s' % pipes.quote(filename)) 454*9c5db199SXin Li 455*9c5db199SXin Li 456*9c5db199SXin Lidef wait_for_android_boot(timeout=None): 457*9c5db199SXin Li """Sleep until Android has completed booting or timeout occurs. 458*9c5db199SXin Li 459*9c5db199SXin Li @param timeout: Timeout in seconds. 460*9c5db199SXin Li """ 461*9c5db199SXin Li arc_common.wait_for_android_boot(timeout) 462*9c5db199SXin Li 463*9c5db199SXin Li 464*9c5db199SXin Lidef wait_for_android_process(process_name, 465*9c5db199SXin Li timeout=_WAIT_FOR_ANDROID_PROCESS_SECONDS): 466*9c5db199SXin Li """Sleep until an Android process is running or timeout occurs. 467*9c5db199SXin Li 468*9c5db199SXin Li @param process_name: Process name. 469*9c5db199SXin Li @param timeout: Timeout in seconds. 470*9c5db199SXin Li """ 471*9c5db199SXin Li condition = lambda: is_android_process_running(process_name) 472*9c5db199SXin Li utils.poll_for_condition(condition=condition, 473*9c5db199SXin Li desc='%s is running' % process_name, 474*9c5db199SXin Li timeout=timeout, 475*9c5db199SXin Li sleep_interval=_PROCESS_CHECK_INTERVAL_SECONDS) 476*9c5db199SXin Li 477*9c5db199SXin Li 478*9c5db199SXin Lidef _android_shell(cmd, **kwargs): 479*9c5db199SXin Li """Execute cmd instead the Android container. 480*9c5db199SXin Li 481*9c5db199SXin Li This function is strictly for internal use only, as commands do not run in 482*9c5db199SXin Li a fully consistent Android environment. Prefer adb_shell instead. 483*9c5db199SXin Li """ 484*9c5db199SXin Li return utils.system_output('android-sh -c {}'.format(pipes.quote(cmd)), 485*9c5db199SXin Li **kwargs) 486*9c5db199SXin Li 487*9c5db199SXin Li 488*9c5db199SXin Lidef is_android_container_alive(): 489*9c5db199SXin Li """Check if android container is alive.""" 490*9c5db199SXin Li try: 491*9c5db199SXin Li container_pid = get_container_pid() 492*9c5db199SXin Li except Exception as e: 493*9c5db199SXin Li logging.error('is_android_container_alive failed: %r', e) 494*9c5db199SXin Li return False 495*9c5db199SXin Li return utils.pid_is_alive(int(container_pid)) 496*9c5db199SXin Li 497*9c5db199SXin Li 498*9c5db199SXin Lidef _is_in_installed_packages_list(package, option=None): 499*9c5db199SXin Li """Check if a package is in the list returned by pm list packages. 500*9c5db199SXin Li 501*9c5db199SXin Li adb must be ready. 502*9c5db199SXin Li 503*9c5db199SXin Li @param package: Package in request. 504*9c5db199SXin Li @param option: An option for the command adb shell pm list packages. 505*9c5db199SXin Li Valid values include '-s', '-3', '-d', and '-e'. 506*9c5db199SXin Li """ 507*9c5db199SXin Li command = 'pm list packages' 508*9c5db199SXin Li if option: 509*9c5db199SXin Li command += ' ' + option 510*9c5db199SXin Li packages = adb_shell(command).splitlines() 511*9c5db199SXin Li package_entry = 'package:' + package 512*9c5db199SXin Li ret = package_entry in packages 513*9c5db199SXin Li 514*9c5db199SXin Li if not ret: 515*9c5db199SXin Li logging.info('Could not find "%s" in %s', 516*9c5db199SXin Li package_entry, str(packages)) 517*9c5db199SXin Li return ret 518*9c5db199SXin Li 519*9c5db199SXin Li 520*9c5db199SXin Lidef is_package_installed(package): 521*9c5db199SXin Li """Check if a package is installed. adb must be ready. 522*9c5db199SXin Li 523*9c5db199SXin Li @param package: Package in request. 524*9c5db199SXin Li """ 525*9c5db199SXin Li return _is_in_installed_packages_list(package) 526*9c5db199SXin Li 527*9c5db199SXin Li 528*9c5db199SXin Lidef is_package_disabled(package): 529*9c5db199SXin Li """Check if an installed package is disabled. adb must be ready. 530*9c5db199SXin Li 531*9c5db199SXin Li @param package: Package in request. 532*9c5db199SXin Li """ 533*9c5db199SXin Li return _is_in_installed_packages_list(package, '-d') 534*9c5db199SXin Li 535*9c5db199SXin Li 536*9c5db199SXin Lidef get_package_install_path(package): 537*9c5db199SXin Li """Returns the apk install location of the given package.""" 538*9c5db199SXin Li output = adb_shell('pm path {}'.format(pipes.quote(package))) 539*9c5db199SXin Li return output.split(':')[1] 540*9c5db199SXin Li 541*9c5db199SXin Li 542*9c5db199SXin Lidef _before_iteration_hook(obj): 543*9c5db199SXin Li """Executed by parent class before every iteration. 544*9c5db199SXin Li 545*9c5db199SXin Li This function resets the run_once_finished flag before every iteration 546*9c5db199SXin Li so we can detect failure on every single iteration. 547*9c5db199SXin Li 548*9c5db199SXin Li Args: 549*9c5db199SXin Li obj: the test itself 550*9c5db199SXin Li """ 551*9c5db199SXin Li obj.run_once_finished = False 552*9c5db199SXin Li 553*9c5db199SXin Li 554*9c5db199SXin Lidef _after_iteration_hook(obj): 555*9c5db199SXin Li """Executed by parent class after every iteration. 556*9c5db199SXin Li 557*9c5db199SXin Li The parent class will handle exceptions and failures in the run and will 558*9c5db199SXin Li always call this hook afterwards. Take a screenshot if the run has not 559*9c5db199SXin Li been marked as finished (i.e. there was a failure/exception). 560*9c5db199SXin Li 561*9c5db199SXin Li Args: 562*9c5db199SXin Li obj: the test itself 563*9c5db199SXin Li """ 564*9c5db199SXin Li if not obj.run_once_finished: 565*9c5db199SXin Li if is_adb_connected(): 566*9c5db199SXin Li logging.debug('Recent activities dump:\n%s', 567*9c5db199SXin Li adb_shell('dumpsys activity recents', 568*9c5db199SXin Li ignore_status=True)) 569*9c5db199SXin Li if not os.path.exists(_SCREENSHOT_DIR_PATH): 570*9c5db199SXin Li os.mkdir(_SCREENSHOT_DIR_PATH, 0o755) 571*9c5db199SXin Li obj.num_screenshots += 1 572*9c5db199SXin Li if obj.num_screenshots <= _MAX_SCREENSHOT_NUM: 573*9c5db199SXin Li logging.warning('Iteration %d failed, taking a screenshot.', 574*9c5db199SXin Li obj.iteration) 575*9c5db199SXin Li try: 576*9c5db199SXin Li utils.run('screenshot "{}/{}_iter{}.png"'.format( 577*9c5db199SXin Li _SCREENSHOT_DIR_PATH, _SCREENSHOT_BASENAME, obj.iteration)) 578*9c5db199SXin Li except Exception as e: 579*9c5db199SXin Li logging.warning('Unable to capture screenshot. %s', e) 580*9c5db199SXin Li else: 581*9c5db199SXin Li logging.warning('Too many failures, no screenshot taken') 582*9c5db199SXin Li 583*9c5db199SXin Li 584*9c5db199SXin Lidef send_keycode(keycode): 585*9c5db199SXin Li """Sends the given keycode to the container 586*9c5db199SXin Li 587*9c5db199SXin Li @param keycode: keycode to send. 588*9c5db199SXin Li """ 589*9c5db199SXin Li adb_shell('input keyevent {}'.format(keycode)) 590*9c5db199SXin Li 591*9c5db199SXin Li 592*9c5db199SXin Lidef get_android_sdk_version(): 593*9c5db199SXin Li """Returns the Android SDK version. 594*9c5db199SXin Li 595*9c5db199SXin Li This function can be called before Android container boots. 596*9c5db199SXin Li """ 597*9c5db199SXin Li with open('/etc/lsb-release') as f: 598*9c5db199SXin Li values = dict(line.split('=', 1) for line in f.read().splitlines()) 599*9c5db199SXin Li try: 600*9c5db199SXin Li return int(values['CHROMEOS_ARC_ANDROID_SDK_VERSION']) 601*9c5db199SXin Li except (KeyError, ValueError): 602*9c5db199SXin Li raise error.TestError('Could not determine Android SDK version') 603*9c5db199SXin Li 604*9c5db199SXin Li 605*9c5db199SXin Lidef set_device_mode(device_mode, use_fake_sensor_with_lifetime_secs=0): 606*9c5db199SXin Li """Sets the device in either Clamshell or Tablet mode. 607*9c5db199SXin Li 608*9c5db199SXin Li "inject_powerd_input_event" might fail if the DUT does not support Tablet 609*9c5db199SXin Li mode, and it will raise an |error.CmdError| exception. To prevent that, use 610*9c5db199SXin Li the |use_fake_sensor_with_lifetime_secs| parameter. 611*9c5db199SXin Li 612*9c5db199SXin Li @param device_mode: string with either 'clamshell' or 'tablet' 613*9c5db199SXin Li @param use_fake_sensor_with_lifetime_secs: if > 0, it will create the 614*9c5db199SXin Li input device with the given lifetime in seconds 615*9c5db199SXin Li @raise ValueError: if passed invalid parameters 616*9c5db199SXin Li @raise error.CmdError: if inject_powerd_input_event fails 617*9c5db199SXin Li """ 618*9c5db199SXin Li valid_value = ('tablet', 'clamshell') 619*9c5db199SXin Li if device_mode not in valid_value: 620*9c5db199SXin Li raise ValueError('Invalid device_mode parameter: %s' % device_mode) 621*9c5db199SXin Li 622*9c5db199SXin Li value = 1 if device_mode == 'tablet' else 0 623*9c5db199SXin Li 624*9c5db199SXin Li args = ['--code=tablet', '--value=%d' % value] 625*9c5db199SXin Li 626*9c5db199SXin Li if use_fake_sensor_with_lifetime_secs > 0: 627*9c5db199SXin Li args.extend(['--create_dev', '--dev_lifetime=%d' % 628*9c5db199SXin Li use_fake_sensor_with_lifetime_secs]) 629*9c5db199SXin Li 630*9c5db199SXin Li try: 631*9c5db199SXin Li utils.run('inject_powerd_input_event', args=args) 632*9c5db199SXin Li except error.CmdError as err: 633*9c5db199SXin Li # TODO: Fragile code ahead. Correct way to do it is to check 634*9c5db199SXin Li # if device is already in desired mode, and do nothing if so. 635*9c5db199SXin Li # ATM we don't have a way to check current device mode. 636*9c5db199SXin Li 637*9c5db199SXin Li # Assuming that CmdError means that device does not support 638*9c5db199SXin Li # --code=tablet parameter, meaning that device only supports clamshell 639*9c5db199SXin Li # mode. 640*9c5db199SXin Li if device_mode == 'clamshell' and \ 641*9c5db199SXin Li use_fake_sensor_with_lifetime_secs == 0: 642*9c5db199SXin Li return 643*9c5db199SXin Li raise err 644*9c5db199SXin Li 645*9c5db199SXin Li 646*9c5db199SXin Lidef wait_for_userspace_ready(): 647*9c5db199SXin Li """Waits for userspace apps to be launchable. 648*9c5db199SXin Li 649*9c5db199SXin Li Launches and then closes Android settings as a way to ensure all basic 650*9c5db199SXin Li services are ready. This goes a bit beyond waiting for boot-up to complete, 651*9c5db199SXin Li as being able to launch an activity requires more of the framework to have 652*9c5db199SXin Li started. The boot-complete signal happens fairly early, and the framework 653*9c5db199SXin Li system server is still starting services. By waiting for ActivityManager to 654*9c5db199SXin Li respond, we automatically wait on more services to be ready. 655*9c5db199SXin Li """ 656*9c5db199SXin Li output = adb_shell('am start -W -a android.settings.SETTINGS', 657*9c5db199SXin Li ignore_status=True) 658*9c5db199SXin Li if not output.endswith('Complete'): 659*9c5db199SXin Li logging.debug('Output was: %s', output) 660*9c5db199SXin Li raise error.TestError('Could not launch SETTINGS') 661*9c5db199SXin Li adb_shell('am force-stop com.android.settings', ignore_status=True) 662*9c5db199SXin Li 663*9c5db199SXin Li 664*9c5db199SXin Liclass ArcTest(test.test): 665*9c5db199SXin Li """ Base class of ARC Test. 666*9c5db199SXin Li 667*9c5db199SXin Li This class could be used as super class of an ARC test for saving 668*9c5db199SXin Li redundant codes for container bringup, autotest-dep package(s) including 669*9c5db199SXin Li uiautomator setup if required, and apks install/remove during 670*9c5db199SXin Li arc_setup/arc_teardown, respectively. By default arc_setup() is called in 671*9c5db199SXin Li initialize() after Android have been brought up. It could also be 672*9c5db199SXin Li overridden to perform non-default tasks. For example, a simple 673*9c5db199SXin Li ArcHelloWorldTest can be just implemented with print 'HelloWorld' in its 674*9c5db199SXin Li run_once() and no other functions are required. We could expect 675*9c5db199SXin Li ArcHelloWorldTest would bring up browser and wait for container up, then 676*9c5db199SXin Li print 'Hello World', and shutdown browser after. As a precaution, if you 677*9c5db199SXin Li overwrite initialize(), arc_setup(), or cleanup() function(s) in ARC test, 678*9c5db199SXin Li remember to call the corresponding function(s) in this base class as well. 679*9c5db199SXin Li """ 680*9c5db199SXin Li version = 1 681*9c5db199SXin Li _PKG_UIAUTOMATOR = 'uiautomator' 682*9c5db199SXin Li _FULL_PKG_NAME_UIAUTOMATOR = 'com.github.uiautomator' 683*9c5db199SXin Li 684*9c5db199SXin Li def __init__(self, *args, **kwargs): 685*9c5db199SXin Li """Initialize flag setting.""" 686*9c5db199SXin Li super(ArcTest, self).__init__(*args, **kwargs) 687*9c5db199SXin Li self.initialized = False 688*9c5db199SXin Li # Set the flag run_once_finished to detect if a test is executed 689*9c5db199SXin Li # successfully without any exception thrown. Otherwise, generate 690*9c5db199SXin Li # a screenshot in /var/log for debugging. 691*9c5db199SXin Li self.run_once_finished = False 692*9c5db199SXin Li self.logcat_proc = None 693*9c5db199SXin Li self.dep_package = None 694*9c5db199SXin Li self.apks = None 695*9c5db199SXin Li self.full_pkg_names = [] 696*9c5db199SXin Li self.uiautomator = False 697*9c5db199SXin Li self._should_reenable_play_store = False 698*9c5db199SXin Li self._chrome = None 699*9c5db199SXin Li if os.path.exists(_SCREENSHOT_DIR_PATH): 700*9c5db199SXin Li shutil.rmtree(_SCREENSHOT_DIR_PATH) 701*9c5db199SXin Li self.register_before_iteration_hook(_before_iteration_hook) 702*9c5db199SXin Li self.register_after_iteration_hook(_after_iteration_hook) 703*9c5db199SXin Li # Keep track of the number of debug screenshots taken and keep the 704*9c5db199SXin Li # total number valid to avoid issues. 705*9c5db199SXin Li self.num_screenshots = 0 706*9c5db199SXin Li 707*9c5db199SXin Li def initialize(self, extension_path=None, username=None, password=None, 708*9c5db199SXin Li arc_mode=arc_common.ARC_MODE_ENABLED, **chrome_kargs): 709*9c5db199SXin Li """Log in to a test account.""" 710*9c5db199SXin Li extension_paths = [extension_path] if extension_path else [] 711*9c5db199SXin Li self._chrome = chrome.Chrome(extension_paths=extension_paths, 712*9c5db199SXin Li username=username, 713*9c5db199SXin Li password=password, 714*9c5db199SXin Li arc_mode=arc_mode, 715*9c5db199SXin Li **chrome_kargs) 716*9c5db199SXin Li if extension_path: 717*9c5db199SXin Li self._extension = self._chrome.get_extension(extension_path) 718*9c5db199SXin Li else: 719*9c5db199SXin Li self._extension = None 720*9c5db199SXin Li # With ARC enabled, Chrome will wait until container to boot up 721*9c5db199SXin Li # before returning here, see chrome.py. 722*9c5db199SXin Li self.initialized = True 723*9c5db199SXin Li try: 724*9c5db199SXin Li if is_android_container_alive(): 725*9c5db199SXin Li self.arc_setup() 726*9c5db199SXin Li else: 727*9c5db199SXin Li logging.error('Container is alive?') 728*9c5db199SXin Li except Exception as err: 729*9c5db199SXin Li raise error.TestFail(err) 730*9c5db199SXin Li 731*9c5db199SXin Li def after_run_once(self): 732*9c5db199SXin Li """Executed after run_once() only if there were no errors. 733*9c5db199SXin Li 734*9c5db199SXin Li This function marks the run as finished with a flag. If there was a 735*9c5db199SXin Li failure the flag won't be set and the failure can then be detected by 736*9c5db199SXin Li testing the run_once_finished flag. 737*9c5db199SXin Li """ 738*9c5db199SXin Li logging.info('After run_once') 739*9c5db199SXin Li self.run_once_finished = True 740*9c5db199SXin Li 741*9c5db199SXin Li def cleanup(self): 742*9c5db199SXin Li """Log out of Chrome.""" 743*9c5db199SXin Li if not self.initialized: 744*9c5db199SXin Li logging.info('Skipping ARC cleanup: not initialized') 745*9c5db199SXin Li return 746*9c5db199SXin Li logging.info('Starting ARC cleanup') 747*9c5db199SXin Li try: 748*9c5db199SXin Li if is_android_container_alive(): 749*9c5db199SXin Li self.arc_teardown() 750*9c5db199SXin Li except Exception as err: 751*9c5db199SXin Li raise error.TestFail(err) 752*9c5db199SXin Li finally: 753*9c5db199SXin Li try: 754*9c5db199SXin Li if self.logcat_proc: 755*9c5db199SXin Li self.logcat_proc.close() 756*9c5db199SXin Li finally: 757*9c5db199SXin Li if self._chrome is not None: 758*9c5db199SXin Li self._chrome.close() 759*9c5db199SXin Li 760*9c5db199SXin Li def _install_apks(self, dep_package, apks, full_pkg_names): 761*9c5db199SXin Li """"Install apks fetched from the specified package folder. 762*9c5db199SXin Li 763*9c5db199SXin Li @param dep_package: A dependent package directory 764*9c5db199SXin Li @param apks: List of apk names to be installed 765*9c5db199SXin Li @param full_pkg_names: List of packages to be uninstalled at teardown 766*9c5db199SXin Li """ 767*9c5db199SXin Li apk_path = os.path.join(self.autodir, 'deps', dep_package) 768*9c5db199SXin Li if apks: 769*9c5db199SXin Li for apk in apks: 770*9c5db199SXin Li logging.info('Installing %s', apk) 771*9c5db199SXin Li out = adb_install('%s/%s' % (apk_path, apk), ignore_status=True) 772*9c5db199SXin Li logging.info('Install apk output: %s', str(out)) 773*9c5db199SXin Li # Verify if package(s) are installed correctly. We ignored 774*9c5db199SXin Li # individual install statuses above because some tests list apks for 775*9c5db199SXin Li # all arches and only need one installed. 776*9c5db199SXin Li if not full_pkg_names: 777*9c5db199SXin Li raise error.TestError('Package names of apks expected') 778*9c5db199SXin Li for pkg in full_pkg_names: 779*9c5db199SXin Li logging.info('Check if %s is installed', pkg) 780*9c5db199SXin Li if not is_package_installed(pkg): 781*9c5db199SXin Li raise error.TestError('Package %s not found' % pkg) 782*9c5db199SXin Li # Make sure full_pkg_names contains installed packages only 783*9c5db199SXin Li # so arc_teardown() knows what packages to uninstall. 784*9c5db199SXin Li self.full_pkg_names.append(pkg) 785*9c5db199SXin Li 786*9c5db199SXin Li def _count_nested_array_level(self, array): 787*9c5db199SXin Li """Count the level of a nested array.""" 788*9c5db199SXin Li if isinstance(array, list): 789*9c5db199SXin Li return 1 + self._count_nested_array_level(array[0]) 790*9c5db199SXin Li return 0 791*9c5db199SXin Li 792*9c5db199SXin Li def _fix_nested_array_level(self, var_name, expected_level, array): 793*9c5db199SXin Li """Enclose array one level deeper if needed.""" 794*9c5db199SXin Li level = self._count_nested_array_level(array) 795*9c5db199SXin Li if level == expected_level: 796*9c5db199SXin Li return array 797*9c5db199SXin Li if level == expected_level - 1: 798*9c5db199SXin Li return [array] 799*9c5db199SXin Li 800*9c5db199SXin Li logging.error("Variable %s nested level is not fixable: " 801*9c5db199SXin Li "Expecting %d, seeing %d", 802*9c5db199SXin Li var_name, expected_level, level) 803*9c5db199SXin Li raise error.TestError('Format error with variable %s' % var_name) 804*9c5db199SXin Li 805*9c5db199SXin Li def arc_setup(self, dep_packages=None, apks=None, full_pkg_names=None, 806*9c5db199SXin Li uiautomator=False, disable_play_store=False): 807*9c5db199SXin Li """ARC test setup: Setup dependencies and install apks. 808*9c5db199SXin Li 809*9c5db199SXin Li This function disables package verification and enables non-market 810*9c5db199SXin Li APK installation. Then, it installs specified APK(s) and uiautomator 811*9c5db199SXin Li package and path if required in a test. 812*9c5db199SXin Li 813*9c5db199SXin Li @param dep_packages: Array of package names of autotest_deps APK 814*9c5db199SXin Li packages. 815*9c5db199SXin Li @param apks: Array of APK name arrays to be installed in dep_package. 816*9c5db199SXin Li @param full_pkg_names: Array of full package name arrays to be removed 817*9c5db199SXin Li in teardown. 818*9c5db199SXin Li @param uiautomator: uiautomator python package is required or not. 819*9c5db199SXin Li @param disable_play_store: Set this to True if you want to prevent 820*9c5db199SXin Li GMS Core from updating. 821*9c5db199SXin Li """ 822*9c5db199SXin Li if not self.initialized: 823*9c5db199SXin Li logging.info('Skipping ARC setup: not initialized') 824*9c5db199SXin Li return 825*9c5db199SXin Li logging.info('Starting ARC setup') 826*9c5db199SXin Li 827*9c5db199SXin Li # Sample parameters for multi-deps setup after fixup (if needed): 828*9c5db199SXin Li # dep_packages: ['Dep1-apk', 'Dep2-apk'] 829*9c5db199SXin Li # apks: [['com.dep1.arch1.apk', 'com.dep2.arch2.apk'], ['com.dep2.apk'] 830*9c5db199SXin Li # full_pkg_nmes: [['com.dep1.app'], ['com.dep2.app']] 831*9c5db199SXin Li # TODO(crbug/777787): once the parameters of all callers of arc_setup 832*9c5db199SXin Li # are refactored, we can delete the safety net here. 833*9c5db199SXin Li if dep_packages: 834*9c5db199SXin Li dep_packages = self._fix_nested_array_level( 835*9c5db199SXin Li 'dep_packages', 1, dep_packages) 836*9c5db199SXin Li apks = self._fix_nested_array_level('apks', 2, apks) 837*9c5db199SXin Li full_pkg_names = self._fix_nested_array_level( 838*9c5db199SXin Li 'full_pkg_names', 2, full_pkg_names) 839*9c5db199SXin Li if (len(dep_packages) != len(apks) or 840*9c5db199SXin Li len(apks) != len(full_pkg_names)): 841*9c5db199SXin Li logging.info('dep_packages length is %d', len(dep_packages)) 842*9c5db199SXin Li logging.info('apks length is %d', len(apks)) 843*9c5db199SXin Li logging.info('full_pkg_names length is %d', 844*9c5db199SXin Li len(full_pkg_names)) 845*9c5db199SXin Li raise error.TestFail( 846*9c5db199SXin Li 'dep_packages/apks/full_pkg_names format error') 847*9c5db199SXin Li 848*9c5db199SXin Li self.dep_packages = dep_packages 849*9c5db199SXin Li self.apks = apks 850*9c5db199SXin Li self.uiautomator = uiautomator or disable_play_store 851*9c5db199SXin Li # Setup dependent packages if required 852*9c5db199SXin Li packages = [] 853*9c5db199SXin Li if dep_packages: 854*9c5db199SXin Li packages = dep_packages[:] 855*9c5db199SXin Li if self.uiautomator: 856*9c5db199SXin Li packages.append(self._PKG_UIAUTOMATOR) 857*9c5db199SXin Li if packages: 858*9c5db199SXin Li logging.info('Setting up dependent package(s) %s', packages) 859*9c5db199SXin Li self.job.setup_dep(packages) 860*9c5db199SXin Li 861*9c5db199SXin Li self.logcat_proc = arc_common.Logcat() 862*9c5db199SXin Li 863*9c5db199SXin Li wait_for_adb_ready() 864*9c5db199SXin Li 865*9c5db199SXin Li # Setting verifier_verify_adb_installs to zero suppresses a dialog box 866*9c5db199SXin Li # that can appear asking for the user to consent to the install. 867*9c5db199SXin Li adb_shell('settings put global verifier_verify_adb_installs 0') 868*9c5db199SXin Li 869*9c5db199SXin Li # Install apks based on dep_packages/apks/full_pkg_names tuples 870*9c5db199SXin Li if dep_packages: 871*9c5db199SXin Li for i in range(len(dep_packages)): 872*9c5db199SXin Li self._install_apks(dep_packages[i], apks[i], full_pkg_names[i]) 873*9c5db199SXin Li 874*9c5db199SXin Li if self.uiautomator: 875*9c5db199SXin Li path = os.path.join(self.autodir, 'deps', self._PKG_UIAUTOMATOR) 876*9c5db199SXin Li sys.path.append(path) 877*9c5db199SXin Li self._add_ui_object_not_found_handler() 878*9c5db199SXin Li if disable_play_store and not is_package_disabled(_PLAY_STORE_PKG): 879*9c5db199SXin Li self._disable_play_store() 880*9c5db199SXin Li if not is_package_disabled(_PLAY_STORE_PKG): 881*9c5db199SXin Li raise error.TestFail('Failed to disable Google Play Store.') 882*9c5db199SXin Li self._should_reenable_play_store = True 883*9c5db199SXin Li 884*9c5db199SXin Li def arc_teardown(self): 885*9c5db199SXin Li """ARC test teardown. 886*9c5db199SXin Li 887*9c5db199SXin Li This function removes all installed packages in arc_setup stage 888*9c5db199SXin Li first. Then, it restores package verification and disables non-market 889*9c5db199SXin Li APK installation. 890*9c5db199SXin Li 891*9c5db199SXin Li """ 892*9c5db199SXin Li if self.full_pkg_names: 893*9c5db199SXin Li for pkg in self.full_pkg_names: 894*9c5db199SXin Li logging.info('Uninstalling %s', pkg) 895*9c5db199SXin Li if not is_package_installed(pkg): 896*9c5db199SXin Li raise error.TestError('Package %s was not installed' % pkg) 897*9c5db199SXin Li adb_uninstall(pkg) 898*9c5db199SXin Li if (self.uiautomator and 899*9c5db199SXin Li is_package_installed(self._FULL_PKG_NAME_UIAUTOMATOR)): 900*9c5db199SXin Li logging.info('Uninstalling %s', self._FULL_PKG_NAME_UIAUTOMATOR) 901*9c5db199SXin Li adb_uninstall(self._FULL_PKG_NAME_UIAUTOMATOR) 902*9c5db199SXin Li if self._should_reenable_play_store: 903*9c5db199SXin Li adb_shell('pm enable ' + _PLAY_STORE_PKG) 904*9c5db199SXin Li adb_shell('settings put secure install_non_market_apps 0') 905*9c5db199SXin Li adb_shell('settings put global package_verifier_enable 1') 906*9c5db199SXin Li adb_shell('settings put secure package_verifier_user_consent 0') 907*9c5db199SXin Li 908*9c5db199SXin Li # Remove the adb keys without going through adb. This is because the 909*9c5db199SXin Li # 'rm' tool does not have permissions to remove the keys once they have 910*9c5db199SXin Li # been restorecon(8)ed. 911*9c5db199SXin Li utils.system_output('rm -f %s' % 912*9c5db199SXin Li pipes.quote(os.path.join( 913*9c5db199SXin Li get_android_data_root(), 914*9c5db199SXin Li os.path.relpath(_ANDROID_ADB_KEYS_PATH, '/')))) 915*9c5db199SXin Li utils.system_output('adb kill-server') 916*9c5db199SXin Li 917*9c5db199SXin Li def _add_ui_object_not_found_handler(self): 918*9c5db199SXin Li """Logs the device dump upon uiautomator.UiObjectNotFoundException.""" 919*9c5db199SXin Li from uiautomator import device as d 920*9c5db199SXin Li d.handlers.on(lambda d: logging.debug('Device window dump:\n%s', 921*9c5db199SXin Li d.dump())) 922*9c5db199SXin Li 923*9c5db199SXin Li def _disable_play_store(self): 924*9c5db199SXin Li """Disables the Google Play Store app.""" 925*9c5db199SXin Li if is_package_disabled(_PLAY_STORE_PKG): 926*9c5db199SXin Li return 927*9c5db199SXin Li adb_shell('am force-stop ' + _PLAY_STORE_PKG) 928*9c5db199SXin Li adb_shell('am start -a android.settings.APPLICATION_DETAILS_SETTINGS ' 929*9c5db199SXin Li '-d package:' + _PLAY_STORE_PKG) 930*9c5db199SXin Li 931*9c5db199SXin Li # Note: the straightforward "pm disable <package>" command would be 932*9c5db199SXin Li # better, but that requires root permissions, which aren't available on 933*9c5db199SXin Li # a pre-release image being tested. The only other way is through the 934*9c5db199SXin Li # Settings UI, but which might change. 935*9c5db199SXin Li from uiautomator import device as d 936*9c5db199SXin Li d(textMatches='(?i)DISABLE', packageName=_SETTINGS_PKG).wait.exists() 937*9c5db199SXin Li d(textMatches='(?i)DISABLE', packageName=_SETTINGS_PKG).click.wait() 938*9c5db199SXin Li d(textMatches='(?i)DISABLE APP').click.wait() 939*9c5db199SXin Li ok_button = d(textMatches='(?i)OK') 940*9c5db199SXin Li if ok_button.exists: 941*9c5db199SXin Li ok_button.click.wait() 942*9c5db199SXin Li adb_shell('am force-stop ' + _SETTINGS_PKG) 943