blob: 094dc4671121286ca3fbb846e95677448f83803c [file] [log] [blame]
Simran Basi431010f2013-09-04 10:42:41 -07001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -07004import functools
Simran Basi431010f2013-09-04 10:42:41 -07005import logging
Kevin Cheng018db352015-09-20 02:22:08 -07006import os
Simran Basi431010f2013-09-04 10:42:41 -07007import re
Kevin Cheng92fe6ae2015-10-21 11:45:34 -07008import stat
Dan Shia2872172015-10-31 01:16:51 -07009import sys
Simran Basi431010f2013-09-04 10:42:41 -070010import time
11
12import common
13
Simran Basi9c5d3982016-04-01 18:49:44 -070014from autotest_lib.client.bin import utils as client_utils
Dan Shi49d451f2016-04-19 09:25:01 -070015from autotest_lib.client.common_lib import android_utils
Simran Basi431010f2013-09-04 10:42:41 -070016from autotest_lib.client.common_lib import error
Dan Shi6450e142016-03-11 11:52:20 -080017from autotest_lib.client.common_lib import global_config
Dan Shi225b9042015-11-18 10:25:21 -080018from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070019from autotest_lib.client.common_lib.cros import retry
Dan Shi6450e142016-03-11 11:52:20 -080020from autotest_lib.server import afe_utils
Dan Shi225b9042015-11-18 10:25:21 -080021from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070022from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080023from autotest_lib.server import utils
Simran Basi5ace6f22016-01-06 17:30:44 -080024from autotest_lib.server.cros import provision
Dan Shi6450e142016-03-11 11:52:20 -080025from autotest_lib.server.cros.dynamic_suite import tools
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070026from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070027from autotest_lib.server.hosts import abstract_ssh
Kevin Chengc6a645a2015-12-18 11:15:10 -080028from autotest_lib.server.hosts import adb_label
29from autotest_lib.server.hosts import base_label
Kevin Cheng85e864a2015-11-30 11:49:34 -080030from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070031
32
Dan Shi6450e142016-03-11 11:52:20 -080033CONFIG = global_config.global_config
34
Dan Shi6ea3e1c2015-10-28 15:19:04 -070035ADB_CMD = 'adb'
36FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070037SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070038# Some devices have no serial, then `adb serial` has output such as:
39# (no serial number) device
40# ?????????? device
41DEVICE_NO_SERIAL_MSG = '(no serial number)'
42DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070043# Regex to find an adb device. Examples:
44# 0146B5580B01801B device
45# 018e0ecb20c97a62 device
46# 172.22.75.141:5555 device
Kevin Cheng224415e2016-04-22 11:32:10 -070047# localhost:22 device
Alexandru Branciogea380fb2016-04-01 16:01:34 +030048DEVICE_FINDER_REGEX = (r'^(?P<SERIAL>([\w-]+)|((tcp:)?' +
49 '\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}([:]5555)?)|' +
Kevin Cheng224415e2016-04-22 11:32:10 -070050 '((tcp:)?localhost([:]22)?)|' +
Filipe Brandenburger34363392015-08-13 14:57:45 -070051 re.escape(DEVICE_NO_SERIAL_MSG) +
Alexandru Branciogea380fb2016-04-01 16:01:34 +030052 r')[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070053CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
54CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
55 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070056RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070057BOARD_FILE = 'ro.product.device'
Simran Basi38f7ddf2015-09-18 12:25:03 -070058TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070059# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080060# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070061FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
62FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
63# List of the perm stats indexed by the order they are listed in the example
64# supplied above.
65FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
66 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
67 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070068
Dan Shi6ea3e1c2015-10-28 15:19:04 -070069# Default maximum number of seconds to wait for a device to be down.
70DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
71# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080072DEFAULT_WAIT_UP_TIME_SECONDS = 300
73# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080074WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070075
Dan Shi7075f552016-04-21 15:42:41 -070076# Default timeout for retrying adb/fastboot command.
77DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS = 10
78
Dan Shia2872172015-10-31 01:16:51 -070079OS_TYPE_ANDROID = 'android'
80OS_TYPE_BRILLO = 'brillo'
81
Dan Shie234dea2016-01-20 17:15:17 -080082# Regex to parse build name to get the detailed build information.
Dan Shi6450e142016-03-11 11:52:20 -080083BUILD_REGEX = ('(?P<BRANCH>([^/]+))/(?P<BUILD_TARGET>([^/]+))-'
Dan Shie234dea2016-01-20 17:15:17 -080084 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))')
Dan Shia2872172015-10-31 01:16:51 -070085# Regex to parse devserver url to get the detailed build information. Sample
86# url: http://$devserver:8080/static/branch/target/build_id
Dan Shie234dea2016-01-20 17:15:17 -080087DEVSERVER_URL_REGEX = '.*/%s/*' % BUILD_REGEX
Dan Shia2872172015-10-31 01:16:51 -070088
Dan Shi6450e142016-03-11 11:52:20 -080089ANDROID_IMAGE_FILE_FMT = '%(build_target)s-img-%(build_id)s.zip'
Dan Shi49d451f2016-04-19 09:25:01 -070090
Dan Shiab999722015-12-04 14:27:08 -080091BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
Dan Shi6450e142016-03-11 11:52:20 -080092 '%(build_target)s-vendor_partitions-%(build_id)s.zip')
93AUTOTEST_SERVER_PACKAGE_FILE_FMT = (
94 '%(build_target)s-autotest_server_package-%(build_id)s.tar.bz2')
Simran Basi9228a6f2016-03-29 12:03:37 -070095ADB_DEVICE_PREFIXES = ['product:', 'model:', 'device:']
Dan Shia2872172015-10-31 01:16:51 -070096
Simran Basi9c5d3982016-04-01 18:49:44 -070097# Map of product names to build target name.
98PRODUCT_TARGET_MAP = {'dragon' : 'ryu',
99 'flo' : 'razor',
100 'flo_lte' : 'razorg',
101 'gm4g_sprout' : 'seed_l8150',
102 'flounder' : 'volantis',
103 'flounder_lte' : 'volantisg'}
104
Dan Shiab999722015-12-04 14:27:08 -0800105# Command to provision a Brillo device.
106# os_image_dir: The full path of the directory that contains all the Android image
107# files (from the image zip file).
108# vendor_partition_dir: The full path of the directory that contains all the
109# Brillo vendor partitions, and provision-device script.
110BRILLO_PROVISION_CMD = (
Simran Basi7e52c622016-01-05 15:43:51 -0800111 'sudo ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
Dan Shiab999722015-12-04 14:27:08 -0800112 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
113 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -0700114
Dan Shi12a4f662016-05-10 14:49:42 -0700115# Default timeout in minutes for fastboot commands.
116DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN = 10
117
David Purselle01548b2016-05-11 10:00:42 -0700118# Default permissions for files/dirs copied from the device.
119_DEFAULT_FILE_PERMS = 0o600
120_DEFAULT_DIR_PERMS = 0o700
121
Dan Shi626d5412016-05-16 16:05:13 -0700122# Constants for getprop return value for a given property.
123PROPERTY_VALUE_TRUE = '1'
124
Dan Shia2872172015-10-31 01:16:51 -0700125class AndroidInstallError(error.InstallError):
126 """Generic error for Android installation related exceptions."""
127
128
Simran Basi724b8a52013-09-30 11:19:31 -0700129class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700130 """This class represents a host running an ADB server."""
131
Simran Basi5ace6f22016-01-06 17:30:44 -0800132 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700133 _LABEL_FUNCTIONS = []
134 _DETECTABLE_LABELS = []
135 label_decorator = functools.partial(utils.add_label_detector,
136 _LABEL_FUNCTIONS,
137 _DETECTABLE_LABELS)
138
Dan Shi225b9042015-11-18 10:25:21 -0800139 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700140
Dan Shi6450e142016-03-11 11:52:20 -0800141 # Minimum build id that supports server side packaging. Older builds may
142 # not have server side package built or with Autotest code change to support
143 # server-side packaging.
144 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
145 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
146
beeps46dadc92013-11-07 14:07:10 -0800147 @staticmethod
148 def check_host(host, timeout=10):
149 """
150 Check if the given host is an adb host.
151
Simran Basi14622bb2015-11-25 13:23:40 -0800152 If SSH connectivity can't be established, check_host will try to use
153 user 'adb' as well. If SSH connectivity still can't be established
154 then the original SSH user is restored.
155
beeps46dadc92013-11-07 14:07:10 -0800156 @param host: An ssh host representing a device.
157 @param timeout: The timeout for the run command.
158
159
160 @return: True if the host device has adb.
161
162 @raises AutoservRunError: If the command failed.
163 @raises AutoservSSHTimeout: Ssh connection has timed out.
164 """
Dan Shi64e130f2015-12-16 14:45:44 -0800165 # host object may not have user attribute if it's a LocalHost object.
166 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800167 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800168 if not (host.hostname == 'localhost' or
169 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700170 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700171 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700172 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700173 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800174 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800175 if current_user is not None:
176 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800177 return False
178 return result.exit_status == 0
179
180
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700181 # TODO(garnold) Remove the 'serials' argument once all clients are made to
182 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700183 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700184 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700185 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700186 """Initialize an ADB Host.
187
188 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700189 test station connected to an Android DUT. This will be the DUT
190 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700191 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700192
193 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700194 @param serials: DEPRECATED (to be removed)
195 @param adb_serial: An ADB device serial. If None, assume a single
196 device is attached (and fail otherwise).
197 @param fastboot_serial: A fastboot device serial. If None, defaults to
198 the ADB serial (or assumes a single device if
199 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800200 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700201 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800202 # Sets up the is_client_install_supported field.
203 super(ADBHost, self)._initialize(hostname=hostname,
204 is_client_install_supported=False,
205 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800206
Kevin Chengd19e6c62015-10-28 16:39:39 -0700207 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800208 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi1bf60eb2015-12-01 16:39:29 -0800209 # TODO (sbasi/kevcheng): Once the teststation host is committed,
210 # refactor the serial retrieval.
211 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Simran Basi973bf712016-05-26 13:41:34 -0700212 fastboot_serial = fastboot_serial or self.host_attributes.get(
213 'fastboot_serial', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800214 self.adb_serial = adb_serial
Dan Shi3a011ed2016-04-26 12:26:53 -0700215 if adb_serial:
216 adb_prefix = any(adb_serial.startswith(p)
217 for p in ADB_DEVICE_PREFIXES)
218 self.fastboot_serial = (fastboot_serial or
219 ('tcp:%s' % adb_serial.split(':')[0] if
220 ':' in adb_serial and not adb_prefix else adb_serial))
221 self._use_tcpip = ':' in adb_serial and not adb_prefix
222 else:
223 self.fastboot_serial = fastboot_serial or adb_serial
224 self._use_tcpip = False
Kevin Cheng85e864a2015-11-30 11:49:34 -0800225 self.teststation = (teststation if teststation
226 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700227
228 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800229 if self.adb_serial:
230 msg += ', ADB serial: %s' % self.adb_serial
231 if self.fastboot_serial:
232 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700233 logging.debug(msg)
234
Simran Basibeb2bb22016-02-03 15:25:48 -0800235 # Try resetting the ADB daemon on the device, however if we are
236 # creating the host to do a repair job, the device maybe inaccesible
237 # via ADB.
238 try:
239 self._reset_adbd_connection()
240 except (error.AutotestHostRunError, error.AutoservRunError) as e:
241 logging.error('Unable to reset the device adb daemon connection: '
242 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800243 self._os_type = None
244
Simran Basi431010f2013-09-04 10:42:41 -0700245
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700246 def _connect_over_tcpip_as_needed(self):
247 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700248 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700249 return
250 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700251 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700252
253
Roshan Pius4d7540c2015-12-16 13:30:32 -0800254 def _restart_adbd_with_root_permissions(self):
255 """Restarts the adb daemon with root permissions."""
Dan Shi922de302016-04-22 15:19:18 -0700256 @retry.retry(error.AutoservRunError, timeout_min=20/60.0, delay_sec=1)
257 def run_adb_root():
258 """Run command `adb root`."""
259 self.adb_run('root')
260
261 # adb command may flake with error "device not found". Retry the root
262 # command to reduce the chance of flake.
263 run_adb_root()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800264 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
265 time.sleep(1)
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300266 self._connect_over_tcpip_as_needed()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800267 self.adb_run('wait-for-device')
268
269
Simran Basi9228a6f2016-03-29 12:03:37 -0700270 def _set_tcp_port(self):
271 """Ensure the device remains in tcp/ip mode after a reboot."""
272 if not self._use_tcpip:
273 return
274 port = self.adb_serial.split(':')[-1]
275 self.run('setprop persist.adb.tcp.port %s' % port)
276
277
Roshan Pius4d7540c2015-12-16 13:30:32 -0800278 def _reset_adbd_connection(self):
279 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800280 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700281 self._restart_adbd_with_root_permissions()
282 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800283
284
Kevin Cheng85e864a2015-11-30 11:49:34 -0800285 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800286 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700287 """Runs an adb command.
288
Kevin Chengd19e6c62015-10-28 16:39:39 -0700289 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700290
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700291 Refer to _device_run method for docstring for parameters.
292 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800293 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700294
295
Kevin Cheng85e864a2015-11-30 11:49:34 -0800296 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800297 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700298 """Runs an fastboot command.
299
Kevin Chengd19e6c62015-10-28 16:39:39 -0700300 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700301
302 Refer to _device_run method for docstring for parameters.
303 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800304 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700305
306
Dan Shi12a4f662016-05-10 14:49:42 -0700307 # pylint: disable=missing-docstring
308 @retry.retry(error.AutoservRunError,
309 timeout_min=DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN)
310 def _fastboot_run_with_retry(self, command, **kwargs):
311 """Runs an fastboot command with retry.
312
313 This command will launch on the test station.
314
315 Refer to _device_run method for docstring for parameters.
316 """
317 return self.fastboot_run(command, **kwargs)
318
319
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700320 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700321 timeout=3600, ignore_status=False, ignore_timeout=False,
322 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
323 connect_timeout=30, options='', stdin=None, verbose=True,
324 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700325 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700326
Kevin Chengd19e6c62015-10-28 16:39:39 -0700327 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700328
Simran Basi431010f2013-09-04 10:42:41 -0700329 @param command: Command to run.
330 @param shell: If true the command runs in the adb shell otherwise if
331 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700332 reboot with shell=False will call 'adb reboot'. This
333 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700334 @param timeout: Time limit in seconds before attempting to
335 kill the running process. The run() function
336 will take a few seconds longer than 'timeout'
337 to complete if it has to kill the process.
338 @param ignore_status: Do not raise an exception, no matter
339 what the exit code of the command is.
340 @param ignore_timeout: Bool True if command timeouts should be
341 ignored. Will return None on command timeout.
342 @param stdout: Redirect stdout.
343 @param stderr: Redirect stderr.
344 @param connect_timeout: Connection timeout (in seconds)
345 @param options: String with additional ssh command options
346 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700347 @param require_sudo: True to require sudo to run the command. Default is
348 False.
Simran Basi431010f2013-09-04 10:42:41 -0700349 @param args: Sequence of strings to pass as arguments to command by
350 quoting them in " and escaping their contents if
351 necessary.
352
353 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700354 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700355 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800356 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700357 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800358 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700359 else:
360 raise NotImplementedError('Mode %s is not supported' % function)
361
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700362 if function != ADB_CMD and shell:
363 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700364
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700365 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700366
367 if serial:
368 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700369
Simran Basi431010f2013-09-04 10:42:41 -0700370 if shell:
371 cmd += '%s ' % SHELL_CMD
372 cmd += command
373
Roshan Pius58e5dd32015-10-16 15:16:42 -0700374 if verbose:
375 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700376
Kevin Cheng85e864a2015-11-30 11:49:34 -0800377 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400378 ignore_status=ignore_status,
379 ignore_timeout=ignore_timeout, stdout_tee=stdout,
380 stderr_tee=stderr, options=options, stdin=stdin,
381 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700382
383
Dan Shi8c51bda2016-05-26 12:21:02 -0700384 def _run_output_with_retry(self, cmd):
385 """Call run_output method for the given command with retry.
386
387 adb command can be flaky some time and return empty string. It may take
388 several retries until a value can be returned.
389
390 @param cmd: The command to run.
391
392 @return: Return value from the command after retry.
393 """
394 try:
395 return client_utils.poll_for_condition(
396 lambda: self.run_output(cmd),
397 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS,
398 sleep_interval=0.5,
399 desc='Get return value for command `%s`' % cmd)
400 except client_utils.TimeoutError:
401 return ''
402
403
Dan Shie234dea2016-01-20 17:15:17 -0800404 def get_board_name(self):
405 """Get the name of the board, e.g., shamu, dragonboard etc.
406 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700407 product = self.run_output('getprop %s' % BOARD_FILE)
408 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800409
410
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700411 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700412 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700413 """Determine the correct board label for the device.
414
415 @returns a string representing this device's board.
416 """
Dan Shie234dea2016-01-20 17:15:17 -0800417 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700418 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800419 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700420
421
Christopher Wiley08849d52013-11-22 08:57:58 -0800422 def job_start(self):
Christopher Wiley08849d52013-11-22 08:57:58 -0800423 """
Dan Shi2d279cf2016-05-27 22:06:10 +0000424 Disable log collection on adb_hosts.
425
426 TODO(sbasi): crbug.com/305427
427 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800428
429
Simran Basi431010f2013-09-04 10:42:41 -0700430 def run(self, command, timeout=3600, ignore_status=False,
431 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
432 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700433 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700434 """Run a command on the adb device.
435
436 The command given will be ran directly on the adb device; for example
437 'ls' will be ran as: 'abd shell ls'
438
439 @param command: The command line string.
440 @param timeout: Time limit in seconds before attempting to
441 kill the running process. The run() function
442 will take a few seconds longer than 'timeout'
443 to complete if it has to kill the process.
444 @param ignore_status: Do not raise an exception, no matter
445 what the exit code of the command is.
446 @param ignore_timeout: Bool True if command timeouts should be
447 ignored. Will return None on command timeout.
448 @param stdout_tee: Redirect stdout.
449 @param stderr_tee: Redirect stderr.
450 @param connect_timeout: Connection timeout (in seconds).
451 @param options: String with additional ssh command options.
452 @param stdin: Stdin to pass (a string) to the executed command
453 @param args: Sequence of strings to pass as arguments to command by
454 quoting them in " and escaping their contents if
455 necessary.
456
457 @returns A CMDResult object or None if the call timed out and
458 ignore_timeout is True.
459
460 @raises AutoservRunError: If the command failed.
461 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700462 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700463 command = ('"%s; echo %s:\$?"' %
464 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700465 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700466 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700467 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
468 stdout=stdout_tee, stderr=stderr_tee,
469 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700470 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700471 if not result:
472 # In case of timeouts.
473 return None
474
475 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700476 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700477 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700478 'Failed to parse the exit code for command: %s' %
479 command, result)
480 elif parse_output:
481 result.stdout = parse_output.group('OUTPUT')
482 result.exit_status = int(parse_output.group('EXIT_CODE'))
483 if result.exit_status != 0 and not ignore_status:
484 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700485 return result
486
487
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700488 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
489 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700490
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700491 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700492
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700493 @param timeout: Time limit in seconds before returning even if the host
494 is not up.
495 @param command: The command used to test if a device is up, i.e.,
496 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700497
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700498 @returns True if the host was found to be up before the timeout expires,
499 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700500 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700501 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
502 delay_sec=1)
503 def _wait_up():
504 if not self.is_up(command=command):
505 raise error.TimeoutException('Device is still down.')
506 return True
507
508 try:
509 _wait_up()
510 logging.debug('Host %s is now up, and can be accessed by %s.',
511 self.hostname, command)
512 return True
513 except error.TimeoutException:
514 logging.debug('Host %s is still down after waiting %d seconds',
515 self.hostname, timeout)
516 return False
Simran Basi431010f2013-09-04 10:42:41 -0700517
518
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700519 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
520 warning_timer=None, old_boot_id=None, command=ADB_CMD):
521 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700522
523 Overrides wait_down from AbstractSSHHost.
524
525 @param timeout: Time in seconds to wait for the host to go down.
526 @param warning_timer: Time limit in seconds that will generate
527 a warning if the host is not down yet.
528 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700529 @param old_boot_id: Not applicable for adb_host.
530 @param command: `adb`, test if the device can be accessed by adb
531 command, or `fastboot`, test if the device can be accessed by
532 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700533
534 @returns True if the device goes down before the timeout, False
535 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700536 """
537 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
538 delay_sec=1)
539 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700540 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700541 raise error.TimeoutException('Device is still up.')
542 return True
543
544 try:
545 _wait_down()
546 logging.debug('Host %s is now down', self.hostname)
547 return True
548 except error.TimeoutException:
549 logging.debug('Host %s is still up after waiting %d seconds',
550 self.hostname, timeout)
551 return False
552
553
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700554 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700555 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700556
557 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700558 """
559 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700560 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700561 self.adb_run('reboot', timeout=10, ignore_timeout=True)
562 if not self.wait_down():
563 raise error.AutoservRebootError(
564 'ADB Device is still up after reboot')
565 if not self.wait_up():
566 raise error.AutoservRebootError(
567 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800568 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800569
570
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300571 def fastboot_reboot(self):
572 """Do a fastboot reboot to go back to adb.
573
574 @raises AutoservRebootError if reboot failed.
575 """
576 self.fastboot_run('reboot')
577 if not self.wait_down(command=FASTBOOT_CMD):
578 raise error.AutoservRebootError(
579 'Device is still in fastboot mode after reboot')
580 if not self.wait_up():
581 raise error.AutoservRebootError(
582 'Device failed to boot to adb after fastboot reboot.')
583 self._reset_adbd_connection()
584
585
Ralph Nathanb45eb672015-11-18 20:04:39 -0800586 def remount(self):
587 """Remounts paritions on the device read-write.
588
589 Specifically, the /system, /vendor (if present) and /oem (if present)
590 partitions on the device are remounted read-write.
591 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800592 self.adb_run('remount')
593
594
Kevin Cheng549beb42015-11-18 11:42:25 -0800595 @staticmethod
596 def parse_device_serials(devices_output):
597 """Return a list of parsed serials from the output.
598
599 @param devices_output: Output from either an adb or fastboot command.
600
601 @returns List of device serials
602 """
603 devices = []
604 for line in devices_output.splitlines():
605 match = re.search(DEVICE_FINDER_REGEX, line)
606 if match:
607 serial = match.group('SERIAL')
608 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
609 serial = DEVICE_NO_SERIAL_TAG
610 logging.debug('Found Device: %s', serial)
611 devices.append(serial)
612 return devices
613
614
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700615 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700616 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700617
618 @params use_adb: True to get adb accessible devices. Set to False to
619 get fastboot accessible devices.
620
Kevin Chengd19e6c62015-10-28 16:39:39 -0700621 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700622 """
623 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300624 result = self.adb_run('devices').stdout
625 if self.adb_serial and self.adb_serial not in result:
626 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700627 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300628 result = self.fastboot_run('devices').stdout
629 if (self.fastboot_serial and
630 self.fastboot_serial not in result):
631 # fastboot devices won't list the devices using TCP
632 try:
633 if 'product' in self.fastboot_run('getvar product',
634 timeout=2).stderr:
635 result += '\n%s\tfastboot' % self.fastboot_serial
Kevin Chengcfcb2cf2016-04-13 10:04:36 -0700636 # The main reason we do a general Exception catch here instead
637 # of setting ignore_timeout/status to True is because even when
638 # the fastboot process has been nuked, it still stays around and
639 # so bgjob wants to warn us of this and tries to read the
640 # /proc/<pid>/stack file which then promptly returns an
641 # 'Operation not permitted' error since we're running as moblab
642 # and we don't have permission to read those files.
643 except Exception:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300644 pass
645 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700646
647
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700648 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700649 """Get a list of devices currently attached to the test station and
650 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700651 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800652 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700653 raise error.AutoservError(
654 'Not given ADB serial but multiple devices detected')
655 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700656
657
658 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700659 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700660 accessible by fastboot command.
661 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700662 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800663 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700664 raise error.AutoservError(
665 'Not given fastboot serial but multiple devices detected')
666 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700667
668
669 def is_up(self, timeout=0, command=ADB_CMD):
670 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700671
672 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700673 @param command: `adb`, the device can be accessed by adb command,
674 or `fastboot`, the device can be accessed by fastboot command.
675 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700676
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700677 @returns True if the device is detectable by given command, False
678 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700679
680 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700681 if command == ADB_CMD:
682 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800683 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800684 # ADB has a device state, if the device is not online, no
685 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800686 # DUT with single device connected may not have adb_serial set.
687 # Therefore, skip checking if serial is in the list of adb devices
688 # if self.adb_serial is not set.
689 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800690 logging.debug('Waiting for device to enter the ready state.')
691 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700692 elif command == FASTBOOT_CMD:
693 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800694 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700695 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700696 raise NotImplementedError('Mode %s is not supported' % command)
697
698 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700699
700
701 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700702 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700703
704 Called as the test ends. Will return the device to USB mode and kill
705 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700706 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800707 # TODO(sbasi) Originally, we would kill the server after each test to
708 # reduce the opportunity for bad server state to hang around.
709 # Unfortunately, there is a period of time after each kill during which
710 # the Android device becomes unusable, and if we start the next test
711 # too quickly, we'll get an error complaining about no ADB device
712 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700713 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800714 # |close| the associated teststation as well.
715 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700716 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700717
718
719 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700720 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700721
722 @param message String message to log into syslog
723 @param tag String tag prefix for syslog
724
725 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700726 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700727
728
729 def get_autodir(self):
730 """Return the directory to install autotest for client side tests."""
731 return '/data/autotest'
732
Kevin Cheng018db352015-09-20 02:22:08 -0700733
Kris Rambishde8f9d12015-12-16 12:42:41 -0800734 def is_device_ready(self):
735 """Return the if the device is ready for ADB commands."""
Dan Shi7075f552016-04-21 15:42:41 -0700736 try:
737 # Retry to avoid possible flakes.
738 is_ready = client_utils.poll_for_condition(
739 lambda: self.adb_run('get-state').stdout.strip() == 'device',
740 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS, sleep_interval=1,
741 desc='Waiting for device state to be `device`')
742 except client_utils.TimeoutError:
743 is_ready = False
744
745 logging.debug('Device state is %sready', '' if is_ready else 'NOT ')
746 return is_ready
Kris Rambishde8f9d12015-12-16 12:42:41 -0800747
748
Kevin Chengd19e6c62015-10-28 16:39:39 -0700749 def verify_connectivity(self):
750 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800751 if not self.is_device_ready():
752 raise error.AutoservHostError('device state is not in the '
753 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700754
755
Simran Basid3ba3fb2015-09-11 14:35:07 -0700756 def verify_software(self):
757 """Verify working software on an adb_host.
758
Simran Basi38f7ddf2015-09-18 12:25:03 -0700759 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700760 """
Dan Shiab999722015-12-04 14:27:08 -0800761 # Check if adb and fastboot are present.
762 self.teststation.run('which adb')
763 self.teststation.run('which fastboot')
764 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700765
Dan Shi626d5412016-05-16 16:05:13 -0700766 # Apply checks only for Android device.
Dan Shi1e2a98a2016-05-18 12:08:08 -0700767 if self.get_os_type() == OS_TYPE_ANDROID:
Dan Shi626d5412016-05-16 16:05:13 -0700768 # Make sure ro.boot.hardware and ro.build.product match.
Dan Shi8c51bda2016-05-26 12:21:02 -0700769 hardware = self._run_output_with_retry('getprop ro.boot.hardware')
770 product = self._run_output_with_retry('getprop ro.build.product')
Dan Shi1e2a98a2016-05-18 12:08:08 -0700771 if hardware != product:
772 raise error.AutoservHostError('ro.boot.hardware: %s does not '
773 'match to ro.build.product: %s' %
774 (hardware, product))
775
Dan Shi626d5412016-05-16 16:05:13 -0700776 # Check the bootloader is not locked. sys.oem_unlock_allowed is not
777 # applicable to Brillo devices.
Dan Shi8c51bda2016-05-26 12:21:02 -0700778 result = self._run_output_with_retry(
779 'getprop sys.oem_unlock_allowed')
Dan Shi626d5412016-05-16 16:05:13 -0700780 if result != PROPERTY_VALUE_TRUE:
781 raise error.AutoservHostError(
782 'The bootloader is locked. sys.oem_unlock_allowed: %s.'
783 % result)
784
Kevin Cheng018db352015-09-20 02:22:08 -0700785
Simran Basid3ba3fb2015-09-11 14:35:07 -0700786 def verify_job_repo_url(self, tag=''):
787 """Make sure job_repo_url of this host is valid.
788
Simran Basi38f7ddf2015-09-18 12:25:03 -0700789 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700790
791 @param tag: The tag from the server job, in the format
792 <job_id>-<user>/<hostname>, or <hostless> for a server job.
793 """
794 return
Kevin Cheng018db352015-09-20 02:22:08 -0700795
796
Simran Basibeb2bb22016-02-03 15:25:48 -0800797 def repair(self):
798 """Attempt to get the DUT to pass `self.verify()`."""
799 try:
800 self.ensure_adb_mode(timeout=30)
801 return
802 except error.AutoservError as e:
803 logging.error(e)
804 logging.debug('Verifying the device is accessible via fastboot.')
805 self.ensure_bootloader_mode()
806 if not self.job.run_test(
807 'provision_AndroidUpdate', host=self, value=None,
808 force=True, repair=True):
809 raise error.AutoservRepairTotalFailure(
810 'Unable to repair the device.')
811
812
Simran Basi1b023762015-09-25 12:12:20 -0700813 def send_file(self, source, dest, delete_dest=False,
814 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700815 """Copy files from the drone to the device.
816
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400817 Just a note, there is the possibility the test station is localhost
818 which makes some of these steps redundant (e.g. creating tmp dir) but
819 that scenario will undoubtedly be a development scenario (test station
820 is also the moblab) and not the typical live test running scenario so
821 the redundancy I think is harmless.
822
Kevin Cheng018db352015-09-20 02:22:08 -0700823 @param source: The file/directory on the drone to send to the device.
824 @param dest: The destination path on the device to copy to.
825 @param delete_dest: A flag set to choose whether or not to delete
826 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700827 @param preserve_symlinks: Controls if symlinks on the source will be
828 copied as such on the destination or
829 transformed into the referenced
830 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700831 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700832 # If we need to preserve symlinks, let's check if the source is a
833 # symlink itself and if so, just create it on the device.
834 if preserve_symlinks:
835 symlink_target = None
836 try:
837 symlink_target = os.readlink(source)
838 except OSError:
839 # Guess it's not a symlink.
840 pass
841
842 if symlink_target is not None:
843 # Once we create the symlink, let's get out of here.
844 self.run('ln -s %s %s' % (symlink_target, dest))
845 return
846
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400847 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700848 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400849 src_path = os.path.join(tmp_dir, os.path.basename(dest))
850 # Now copy the file over to the test station so you can reference the
851 # file in the push command.
852 self.teststation.send_file(source, src_path,
853 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700854
855 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400856 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700857
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700858 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700859
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400860 # Cleanup the test station.
861 try:
862 self.teststation.run('rm -rf %s' % tmp_dir)
863 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
864 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700865
866
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700867 def _get_file_info(self, dest):
868 """Get permission and possible symlink info about file on the device.
869
870 These files are on the device so we only have shell commands (via adb)
871 to get the info we want. We'll use 'ls' to get it all.
872
873 @param dest: File to get info about.
874
875 @returns a dict of the file permissions and symlink.
876 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800877 # Grab file info.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700878 file_info = self.run_output('ls -ld %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700879 symlink = None
880 perms = 0
881 match = re.match(FILE_INFO_REGEX, file_info)
882 if match:
883 # Check if it's a symlink and grab the linked dest if it is.
884 if match.group('TYPE') == 'l':
885 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
886 if symlink_match:
887 symlink = symlink_match.group('SYMLINK')
888
889 # Set the perms.
890 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
891 if perm != '-':
892 perms |= perm_flag
893
894 return {'perms': perms,
895 'symlink': symlink}
896
897
Simran Basi1b023762015-09-25 12:12:20 -0700898 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
899 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700900 """Copy files from the device to the drone.
901
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400902 Just a note, there is the possibility the test station is localhost
903 which makes some of these steps redundant (e.g. creating tmp dir) but
904 that scenario will undoubtedly be a development scenario (test station
905 is also the moblab) and not the typical live test running scenario so
906 the redundancy I think is harmless.
907
Kevin Cheng018db352015-09-20 02:22:08 -0700908 @param source: The file/directory on the device to copy back to the
909 drone.
910 @param dest: The destination path on the drone to copy to.
911 @param delete_dest: A flag set to choose whether or not to delete
912 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700913 @param preserve_perm: Tells get_file() to try to preserve the sources
914 permissions on files and dirs.
915 @param preserve_symlinks: Try to preserve symlinks instead of
916 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700917 """
David Purselle01548b2016-05-11 10:00:42 -0700918 # Stage the files on the test station under teststation_temp_dir.
919 teststation_temp_dir = self.teststation.get_tmp_dir()
920 teststation_dest = os.path.join(teststation_temp_dir,
921 os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700922
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700923 source_info = {}
924 if preserve_symlinks or preserve_perm:
925 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700926
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700927 # If we want to preserve symlinks, just create it here, otherwise pull
928 # the file off the device.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700929 #
930 # TODO(sadmac): Directories containing symlinks won't behave as
931 # expected.
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700932 if preserve_symlinks and source_info['symlink']:
933 os.symlink(source_info['symlink'], dest)
934 else:
David Purselle01548b2016-05-11 10:00:42 -0700935 self.adb_run('pull %s %s' % (source, teststation_temp_dir))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700936
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400937 # Copy over the file from the test station and clean up.
David Purselle01548b2016-05-11 10:00:42 -0700938 self.teststation.get_file(teststation_dest, dest,
939 delete_dest=delete_dest)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400940 try:
David Purselle01548b2016-05-11 10:00:42 -0700941 self.teststation.run('rm -rf %s' % teststation_temp_dir)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400942 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
David Purselle01548b2016-05-11 10:00:42 -0700943 logging.warn('failed to remove dir %s: %s',
944 teststation_temp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700945
David Pursell788b1b52016-05-19 09:03:31 -0700946 # Source will be copied under dest if either:
947 # 1. Source is a directory and doesn't end with /.
948 # 2. Source is a file and dest is a directory.
949 source_is_dir = self.run('[ -d "$${%s} ]',
950 ignore_status=True).exit_status == 0
951 if ((source_is_dir and not source.endswith(os.sep)) or
952 (not source_is_dir and os.path.isdir(dest))):
953 receive_path = os.path.join(dest, os.path.basename(source))
954 else:
955 receive_path = dest
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700956
David Pursell788b1b52016-05-19 09:03:31 -0700957 # Set the permissions of the received file/dirs.
958 if os.path.isdir(receive_path):
959 for root, _dirs, files in os.walk(receive_path):
960 def process(rel_path, default_perm):
961 info = self._get_file_info(os.path.join(source,
962 rel_path))
963 if info['perms'] != 0:
964 target = os.path.join(receive_path, rel_path)
965 if preserve_perm:
966 os.chmod(target, info['perms'])
967 else:
968 os.chmod(target, default_perm)
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700969
David Pursell788b1b52016-05-19 09:03:31 -0700970 rel_root = os.path.relpath(root, receive_path)
971 process(rel_root, _DEFAULT_DIR_PERMS)
972 for f in files:
973 process(os.path.join(rel_root, f), _DEFAULT_FILE_PERMS)
974 elif preserve_perm:
975 os.chmod(receive_path, source_info['perms'])
976 else:
977 os.chmod(receive_path, _DEFAULT_FILE_PERMS)
Kevin Cheng018db352015-09-20 02:22:08 -0700978
979
980 def get_release_version(self):
981 """Get the release version from the RELEASE_FILE on the device.
982
983 @returns The release string in the RELEASE_FILE.
984
985 """
986 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700987
988
989 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700990 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700991
Kevin Chengd19e6c62015-10-28 16:39:39 -0700992 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700993
994 @param parent: Parent directory of the returned tmp dir.
995
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700996 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700997 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700998 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
999 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -07001000 if not parent.startswith(TMP_DIR):
1001 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -07001002 self.run('mkdir -p %s' % parent)
1003 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
1004 self.tmp_dirs.append(tmp_dir)
1005 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -07001006
1007
1008 def get_platform(self):
1009 """Determine the correct platform label for this host.
1010
1011 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -07001012 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -07001013
1014 @returns a string representing this host's platform.
1015 """
1016 return 'adb'
1017
1018
Gilad Arnolda76bef02015-09-29 13:55:15 -07001019 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -08001020 """Get the OS type of the DUT, e.g., android or brillo.
1021 """
1022 if not self._os_type:
1023 if self.run_output('getprop ro.product.brand') == 'Brillo':
1024 self._os_type = OS_TYPE_BRILLO
1025 else:
1026 self._os_type = OS_TYPE_ANDROID
1027
1028 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001029
1030
1031 def _forward(self, reverse, args):
1032 """Execute a forwarding command.
1033
1034 @param reverse: Whether this is reverse forwarding (Boolean).
1035 @param args: List of command arguments.
1036 """
1037 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001038 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001039
1040
1041 def add_forwarding(self, src, dst, reverse=False, rebind=True):
1042 """Forward a port between the ADB host and device.
1043
1044 Port specifications are any strings accepted as such by ADB, for
1045 example 'tcp:8080'.
1046
1047 @param src: Port specification to forward from.
1048 @param dst: Port specification to forward to.
1049 @param reverse: Do reverse forwarding from device to host (Boolean).
1050 @param rebind: Allow rebinding an already bound port (Boolean).
1051 """
1052 args = []
1053 if not rebind:
1054 args.append('--no-rebind')
1055 args += [src, dst]
1056 self._forward(reverse, args)
1057
1058
1059 def remove_forwarding(self, src=None, reverse=False):
1060 """Removes forwarding on port.
1061
1062 @param src: Port specification, or None to remove all forwarding.
1063 @param reverse: Whether this is reverse forwarding (Boolean).
1064 """
1065 args = []
1066 if src is None:
1067 args.append('--remove-all')
1068 else:
1069 args += ['--remove', src]
1070 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001071
1072
xixuan6cf6d2f2016-01-29 15:29:00 -08001073 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001074 """
1075 Forwards a port securely through a tunnel process from the server
1076 to the DUT for RPC server connection.
1077 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
1078 to the DUT.
1079
1080 @param port: remote port on the DUT.
1081 @param local_port: local forwarding port.
1082
1083 @return: the tunnel process.
1084 """
1085 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001086 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001087
1088
xixuan6cf6d2f2016-01-29 15:29:00 -08001089 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001090 """
1091 Disconnects a previously forwarded port from the server to the DUT for
1092 RPC server connection.
1093 Remove the previously added 'ADB forward' rule to forward the RPC
1094 packets from the AdbHost to the DUT.
1095
1096 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -08001097 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -07001098 @param port: remote port on the DUT.
1099
1100 """
1101 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001102 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001103
1104
1105 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001106 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001107
1108 @raise: error.AutoservError if the device failed to reboot into
1109 bootloader mode.
1110 """
1111 if self.is_up(command=FASTBOOT_CMD):
1112 return
1113 self.adb_run('reboot bootloader')
1114 if not self.wait_up(command=FASTBOOT_CMD):
1115 raise error.AutoservError(
1116 'The device failed to reboot into bootloader mode.')
1117
1118
Dan Shie4e807b2015-12-10 09:04:03 -08001119 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001120 """Ensure the device is up and can be accessed by adb command.
1121
Dan Shie4e807b2015-12-10 09:04:03 -08001122 @param timeout: Time limit in seconds before returning even if the host
1123 is not up.
1124
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001125 @raise: error.AutoservError if the device failed to reboot into
1126 adb mode.
1127 """
1128 if self.is_up():
1129 return
Dan Shi04980372016-03-22 10:57:47 -07001130 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1131 # check if the device is in adb mode.
1132 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001133 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001134 raise error.AutoservError(
1135 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001136 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001137
1138
1139 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001140 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001141 """Get the Android build information from the build url.
1142
1143 @param build_url: The url to use for downloading Android artifacts.
1144 pattern: http://$devserver:###/static/branch/target/build_id
1145
Dan Shi6450e142016-03-11 11:52:20 -08001146 @return: A dictionary of build information, including keys:
1147 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001148 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001149 """
Dan Shiab999722015-12-04 14:27:08 -08001150 if not build_url:
1151 raise AndroidInstallError('Need build_url to download image files.')
1152
1153 try:
1154 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001155 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001156 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001157 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001158 match.group('BUILD_TYPE'))),
1159 'build_id': match.group('BUILD_ID')}
1160 except (AttributeError, IndexError, ValueError) as e:
1161 raise AndroidInstallError(
1162 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001163
1164
Dan Shia2872172015-10-31 01:16:51 -07001165 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001166 def download_file(self, build_url, file, dest_dir, unzip=False,
1167 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001168 """Download the given file from the build url.
1169
1170 @param build_url: The url to use for downloading Android artifacts.
1171 pattern: http://$devserver:###/static/branch/target/build_id
1172 @param file: Name of the file to be downloaded, e.g., boot.img.
1173 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001174 @param unzip: If True, unzip the downloaded file.
1175 @param unzip_dest: Location to unzip the downloaded file to. If not
1176 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001177 """
Dan Shidb0366c2016-02-19 10:36:18 -08001178 # Append the file name to the url if build_url is linked to the folder
1179 # containing the file.
1180 if not build_url.endswith('/%s' % file):
1181 src_url = os.path.join(build_url, file)
1182 else:
1183 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001184 dest_file = os.path.join(dest_dir, file)
1185 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001186 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001187 if unzip:
1188 unzip_dest = unzip_dest or dest_dir
1189 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1190 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001191 except:
1192 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001193 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001194 raise
1195
1196
Dan Shiab999722015-12-04 14:27:08 -08001197 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001198 """Download required image files from the given build_url to a local
1199 directory in the machine runs fastboot command.
1200
1201 @param build_url: The url to use for downloading Android artifacts.
1202 pattern: http://$devserver:###/static/branch/target/build_id
1203
1204 @return: Path to the directory contains image files.
1205 """
Dan Shi08ff1282016-02-18 19:51:16 -08001206 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001207
1208 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001209 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001210
1211 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001212 self.download_file(build_url, zipped_image_file, image_dir,
1213 unzip=True)
Dan Shi49d451f2016-04-19 09:25:01 -07001214 images = android_utils.AndroidImageFiles.get_standalone_images(
1215 build_info['build_target'])
1216 for image_file in images:
Dan Shidb0366c2016-02-19 10:36:18 -08001217 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001218
Dan Shia2872172015-10-31 01:16:51 -07001219 return image_dir
1220 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001221 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001222 raise
1223
1224
Dan Shiab999722015-12-04 14:27:08 -08001225 def stage_brillo_image_files(self, build_url):
1226 """Download required brillo image files from the given build_url to a
1227 local directory in the machine runs fastboot command.
1228
1229 @param build_url: The url to use for downloading Android artifacts.
1230 pattern: http://$devserver:###/static/branch/target/build_id
1231
1232 @return: Path to the directory contains image files.
1233 """
Dan Shi08ff1282016-02-18 19:51:16 -08001234 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001235
1236 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1237 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1238 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001239
1240 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001241 self.download_file(build_url, zipped_image_file, image_dir,
1242 unzip=True)
1243 self.download_file(build_url, vendor_partitions_file, image_dir,
1244 unzip=True,
1245 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001246 return image_dir
1247 except:
1248 self.teststation.run('rm -rf %s' % image_dir)
1249 raise
1250
1251
Simran Basibeb2bb22016-02-03 15:25:48 -08001252 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001253 """Stage a build on a devserver and return the build_url and devserver.
1254
1255 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001256
Dan Shi225b9042015-11-18 10:25:21 -08001257 @returns a tuple with an update URL like:
1258 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1259 and the devserver instance.
1260 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001261 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001262 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001263 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1264 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001265 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001266 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001267 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001268 devserver.trigger_download(target, build_id, branch,
1269 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001270 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001271
1272
Dan Shie4e807b2015-12-10 09:04:03 -08001273 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001274 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001275 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001276
1277 Following are the steps used here to provision an android device:
1278 1. If build_local_path is not set, download the image zip file, e.g.,
1279 shamu-img-2284311.zip, unzip it.
1280 2. Run fastboot to install following artifacts:
1281 bootloader, radio, boot, system, vendor(only if exists)
1282
1283 Repair is not supported for Android devices yet.
1284
1285 @param build_url: The url to use for downloading Android artifacts.
1286 pattern: http://$devserver:###/static/$build
1287 @param build_local_path: The path to a local folder that contains the
1288 image files needed to provision the device. Note that the folder
1289 is in the machine running adb command, rather than the drone.
1290 @param wipe: If true, userdata will be wiped before flashing.
1291 @param flash_all: If True, all img files found in img_path will be
1292 flashed. Otherwise, only boot and system are flashed.
1293
1294 @raises AndroidInstallError if any error occurs.
1295 """
Dan Shia2872172015-10-31 01:16:51 -07001296 # If the build is not staged in local server yet, clean up the temp
1297 # folder used to store image files after the provision is completed.
1298 delete_build_folder = bool(not build_local_path)
1299
1300 try:
1301 # Download image files needed for provision to a local directory.
1302 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001303 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001304
1305 # Device needs to be in bootloader mode for flashing.
1306 self.ensure_bootloader_mode()
1307
1308 if wipe:
Dan Shi12a4f662016-05-10 14:49:42 -07001309 self._fastboot_run_with_retry('-w')
Dan Shia2872172015-10-31 01:16:51 -07001310
1311 # Get all *.img file in the build_local_path.
1312 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001313 image_files = self.teststation.run(
1314 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001315 images = dict([(os.path.basename(f), f) for f in image_files])
Dan Shi49d451f2016-04-19 09:25:01 -07001316 build_info = self.get_build_info_from_build_url(build_url)
1317 board = build_info['build_target']
1318 all_images = (
1319 android_utils.AndroidImageFiles.get_standalone_images(board)
1320 + android_utils.AndroidImageFiles.get_zipped_images(board))
1321
1322 # Sort images to be flashed, bootloader needs to be the first one.
1323 bootloader = android_utils.AndroidImageFiles.BOOTLOADER
1324 sorted_images = sorted(
1325 images.items(),
1326 key=lambda pair: 0 if pair[0] == bootloader else 1)
1327 for image, image_file in sorted_images:
1328 if image not in all_images:
Dan Shia2872172015-10-31 01:16:51 -07001329 continue
1330 logging.info('Flashing %s...', image_file)
Dan Shi12a4f662016-05-10 14:49:42 -07001331 self._fastboot_run_with_retry('-S 256M flash %s %s' %
1332 (image[:-4], image_file))
Dan Shi49d451f2016-04-19 09:25:01 -07001333 if image == android_utils.AndroidImageFiles.BOOTLOADER:
Dan Shia2872172015-10-31 01:16:51 -07001334 self.fastboot_run('reboot-bootloader')
1335 self.wait_up(command=FASTBOOT_CMD)
1336 except Exception as e:
1337 logging.error('Install Android build failed with error: %s', e)
1338 # Re-raise the exception with type of AndroidInstallError.
1339 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1340 finally:
1341 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001342 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001343 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1344 DEFAULT_WAIT_UP_TIME_SECONDS)
1345 self.ensure_adb_mode(timeout=timeout)
Simran Basiac86aee2016-05-17 17:31:56 -07001346 # Skip the setup wizard.
1347 self.run('am start -n com.google.android.setupwizard/'
1348 '.SetupWizardExitActivity')
Dan Shia2872172015-10-31 01:16:51 -07001349 logging.info('Successfully installed Android build staged at %s.',
1350 build_url)
1351
1352
Dan Shiab999722015-12-04 14:27:08 -08001353 def install_brillo(self, build_url, build_local_path=None):
1354 """Install the Brillo DUT.
1355
1356 Following are the steps used here to provision an android device:
1357 1. If build_local_path is not set, download the image zip file, e.g.,
1358 dragonboard-img-123456.zip, unzip it. And download the vendor
1359 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1360 unzip it to vendor folder.
1361 2. Run provision_device script to install OS images and vendor
1362 partitions.
1363
1364 @param build_url: The url to use for downloading Android artifacts.
1365 pattern: http://$devserver:###/static/$build
1366 @param build_local_path: The path to a local folder that contains the
1367 image files needed to provision the device. Note that the folder
1368 is in the machine running adb command, rather than the drone.
1369
1370 @raises AndroidInstallError if any error occurs.
1371 """
1372 # If the build is not staged in local server yet, clean up the temp
1373 # folder used to store image files after the provision is completed.
1374 delete_build_folder = bool(not build_local_path)
1375
Dan Shiab999722015-12-04 14:27:08 -08001376 try:
1377 # Download image files needed for provision to a local directory.
1378 if not build_local_path:
1379 build_local_path = self.stage_brillo_image_files(build_url)
1380
1381 # Device needs to be in bootloader mode for flashing.
1382 self.ensure_bootloader_mode()
1383
1384 # Run provision_device command to install image files and vendor
1385 # partitions.
1386 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1387 cmd = (BRILLO_PROVISION_CMD %
1388 {'os_image_dir': build_local_path,
1389 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001390 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001391 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001392 self.teststation.run(cmd)
1393 except Exception as e:
1394 logging.error('Install Brillo build failed with error: %s', e)
1395 # Re-raise the exception with type of AndroidInstallError.
1396 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1397 finally:
1398 if delete_build_folder:
1399 self.teststation.run('rm -rf %s' % build_local_path)
1400 self.ensure_adb_mode()
1401 logging.info('Successfully installed Android build staged at %s.',
1402 build_url)
1403
1404
Dan Shibe3636a2016-02-14 22:48:01 -08001405 @property
1406 def job_repo_url_attribute(self):
1407 """Get the host attribute name for job_repo_url, which should append the
1408 adb serial.
1409 """
1410 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1411
1412
Dan Shie4e807b2015-12-10 09:04:03 -08001413 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001414 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001415 """Install the DUT.
1416
1417 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001418 pattern: http://$devserver:###/static/$build. If build_url is
1419 set to None, the code may try _parser.options.image to do the
1420 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001421 @param build_local_path: The path to a local directory that contains the
1422 image files needed to provision the device.
1423 @param wipe: If true, userdata will be wiped before flashing.
1424 @param flash_all: If True, all img files found in img_path will be
1425 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001426
Dan Shibe3636a2016-02-14 22:48:01 -08001427 @returns A tuple of (image_name, host_attributes).
1428 image_name is the name of image installed, e.g.,
1429 git_mnc-release/shamu-userdebug/1234
1430 host_attributes is a dictionary of (attribute, value), which
1431 can be saved to afe_host_attributes table in database. This
1432 method returns a dictionary with a single entry of
1433 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1434 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001435 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001436 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001437 if not build_url and self._parser.options.image:
1438 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001439 self._parser.options.image, os_type=os_type)
1440 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001441 self.install_android(
1442 build_url=build_url, build_local_path=build_local_path,
1443 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001444 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001445 self.install_brillo(
1446 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001447 else:
1448 raise error.InstallError(
1449 'Installation of os type %s is not supported.' %
1450 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001451 return (build_url.split('static/')[-1],
1452 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001453
1454
1455 def list_files_glob(self, path_glob):
1456 """Get a list of files on the device given glob pattern path.
1457
1458 @param path_glob: The path glob that we want to return the list of
1459 files that match the glob. Relative paths will not work as
1460 expected. Supply an absolute path to get the list of files
1461 you're hoping for.
1462
1463 @returns List of files that match the path_glob.
1464 """
1465 # This is just in case path_glob has no path separator.
1466 base_path = os.path.dirname(path_glob) or '.'
1467 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001468 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001469 if result.exit_status != 0:
1470 return []
1471 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001472
1473
Dan Shida995002016-04-25 23:12:58 -07001474 def install_apk(self, apk, force_reinstall=True):
Kevin Cheng31355942016-01-05 14:23:35 -08001475 """Install the specified apk.
1476
1477 This will install the apk and override it if it's already installed and
1478 will also allow for downgraded apks.
1479
1480 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001481 @param force_reinstall: True to reinstall the apk even if it's already
Dan Shida995002016-04-25 23:12:58 -07001482 installed. Default is set to True.
Dan Shidb0366c2016-02-19 10:36:18 -08001483
1484 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001485 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001486 client_utils.poll_for_condition(
1487 lambda: self.run('pm list packages',
1488 ignore_status=True).exit_status == 0,
1489 timeout=120)
Dan Shi043c45b2016-04-11 17:18:49 -07001490 client_utils.poll_for_condition(
1491 lambda: self.run('service list | grep mount',
1492 ignore_status=True).exit_status == 0,
1493 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001494 return self.adb_run('install %s -d %s' %
1495 ('-r' if force_reinstall else '', apk))
1496
1497
1498 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1499 def _confirm_apk_installed(self, package_name):
1500 """Confirm if apk is already installed with the given name.
1501
1502 `pm list packages` command is not reliable some time. The retry helps to
1503 reduce the chance of false negative.
1504
1505 @param package_name: Name of the package, e.g., com.android.phone.
1506
1507 @raise AutoservRunError: If the package is not found or pm list command
1508 failed for any reason.
1509 """
1510 name = 'package:%s' % package_name
1511 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1512
1513
1514 def is_apk_installed(self, package_name):
1515 """Check if apk is already installed with the given name.
1516
1517 @param package_name: Name of the package, e.g., com.android.phone.
1518
1519 @return: True if package is installed. False otherwise.
1520 """
1521 try:
1522 self._confirm_apk_installed(package_name)
1523 return True
1524 except:
1525 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001526
1527
1528 def get_attributes_to_clear_before_provision(self):
1529 """Get a list of attributes to be cleared before machine_install starts.
1530 """
1531 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001532
1533
1534 def get_labels(self):
1535 """Return a list of the labels gathered from the devices connected.
1536
1537 @return: A list of strings that denote the labels from all the devices
1538 connected.
1539 """
1540 return self.labels.get_labels(self)
1541
1542
1543 def update_labels(self):
1544 """Update the labels for this testbed."""
1545 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001546
1547
1548 def stage_server_side_package(self, image=None):
1549 """Stage autotest server-side package on devserver.
1550
1551 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1552
1553 @return: A url to the autotest server-side package. Return None if
1554 server-side package is not supported.
1555 @raise: error.AutoservError if fail to locate the build to test with.
1556 """
1557 if image:
1558 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1559 else:
1560 job_repo_url = afe_utils.get_host_attribute(
1561 self, self.job_repo_url_attribute)
1562 if job_repo_url:
1563 devserver_url, image = (
1564 tools.get_devserver_build_from_package_url(
1565 job_repo_url, True))
1566 ds = dev_server.AndroidBuildServer(devserver_url)
1567 else:
1568 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1569 if not labels:
1570 raise error.AutoservError(
1571 'Failed to stage server-side package. The host has '
1572 'no job_report_url attribute or version label.')
1573 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1574 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1575
1576 branch, target, build_id = utils.parse_launch_control_build(image)
1577 build_target, _ = utils.parse_launch_control_target(target)
1578
1579 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1580 # packaging is not supported.
1581 try:
1582 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1583 logging.warn('Build %s is older than %s. Server side packaging '
1584 'is disabled.', image,
1585 self.MIN_VERSION_SUPPORT_SSP)
1586 return None
1587 except ValueError:
1588 logging.warn('Failed to compare build id in %s with the minimum '
1589 'version that supports server side packaging. Server '
1590 'side packaging is disabled.', image)
1591 return None
1592
1593 ds.stage_artifacts(target, build_id, branch,
1594 artifacts=['autotest_server_package'])
1595 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1596 {'build_target': build_target,
1597 'build_id': build_id})
1598 return '%s/static/%s/%s' % (ds.url(), image,
1599 autotest_server_package_name)