blob: 0a491764a1f9fc49ee6e6470c2fb81afe0041057 [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)
Dan Shi50a412a2016-01-05 10:52:40 -0800212 self.adb_serial = adb_serial
Dan Shi3a011ed2016-04-26 12:26:53 -0700213 if adb_serial:
214 adb_prefix = any(adb_serial.startswith(p)
215 for p in ADB_DEVICE_PREFIXES)
216 self.fastboot_serial = (fastboot_serial or
217 ('tcp:%s' % adb_serial.split(':')[0] if
218 ':' in adb_serial and not adb_prefix else adb_serial))
219 self._use_tcpip = ':' in adb_serial and not adb_prefix
220 else:
221 self.fastboot_serial = fastboot_serial or adb_serial
222 self._use_tcpip = False
Kevin Cheng85e864a2015-11-30 11:49:34 -0800223 self.teststation = (teststation if teststation
224 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700225
226 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800227 if self.adb_serial:
228 msg += ', ADB serial: %s' % self.adb_serial
229 if self.fastboot_serial:
230 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700231 logging.debug(msg)
232
Simran Basibeb2bb22016-02-03 15:25:48 -0800233 # Try resetting the ADB daemon on the device, however if we are
234 # creating the host to do a repair job, the device maybe inaccesible
235 # via ADB.
236 try:
237 self._reset_adbd_connection()
238 except (error.AutotestHostRunError, error.AutoservRunError) as e:
239 logging.error('Unable to reset the device adb daemon connection: '
240 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800241 self._os_type = None
242
Simran Basi431010f2013-09-04 10:42:41 -0700243
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700244 def _connect_over_tcpip_as_needed(self):
245 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700246 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700247 return
248 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700249 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700250
251
Roshan Pius4d7540c2015-12-16 13:30:32 -0800252 def _restart_adbd_with_root_permissions(self):
253 """Restarts the adb daemon with root permissions."""
Dan Shi922de302016-04-22 15:19:18 -0700254 @retry.retry(error.AutoservRunError, timeout_min=20/60.0, delay_sec=1)
255 def run_adb_root():
256 """Run command `adb root`."""
257 self.adb_run('root')
258
259 # adb command may flake with error "device not found". Retry the root
260 # command to reduce the chance of flake.
261 run_adb_root()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800262 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
263 time.sleep(1)
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300264 self._connect_over_tcpip_as_needed()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800265 self.adb_run('wait-for-device')
266
267
Simran Basi9228a6f2016-03-29 12:03:37 -0700268 def _set_tcp_port(self):
269 """Ensure the device remains in tcp/ip mode after a reboot."""
270 if not self._use_tcpip:
271 return
272 port = self.adb_serial.split(':')[-1]
273 self.run('setprop persist.adb.tcp.port %s' % port)
274
275
Roshan Pius4d7540c2015-12-16 13:30:32 -0800276 def _reset_adbd_connection(self):
277 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800278 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700279 self._restart_adbd_with_root_permissions()
280 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800281
282
Kevin Cheng85e864a2015-11-30 11:49:34 -0800283 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800284 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700285 """Runs an adb command.
286
Kevin Chengd19e6c62015-10-28 16:39:39 -0700287 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700288
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700289 Refer to _device_run method for docstring for parameters.
290 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800291 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700292
293
Kevin Cheng85e864a2015-11-30 11:49:34 -0800294 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800295 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700296 """Runs an fastboot command.
297
Kevin Chengd19e6c62015-10-28 16:39:39 -0700298 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700299
300 Refer to _device_run method for docstring for parameters.
301 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800302 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700303
304
Dan Shi12a4f662016-05-10 14:49:42 -0700305 # pylint: disable=missing-docstring
306 @retry.retry(error.AutoservRunError,
307 timeout_min=DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN)
308 def _fastboot_run_with_retry(self, command, **kwargs):
309 """Runs an fastboot command with retry.
310
311 This command will launch on the test station.
312
313 Refer to _device_run method for docstring for parameters.
314 """
315 return self.fastboot_run(command, **kwargs)
316
317
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700318 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700319 timeout=3600, ignore_status=False, ignore_timeout=False,
320 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
321 connect_timeout=30, options='', stdin=None, verbose=True,
322 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700323 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700324
Kevin Chengd19e6c62015-10-28 16:39:39 -0700325 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700326
Simran Basi431010f2013-09-04 10:42:41 -0700327 @param command: Command to run.
328 @param shell: If true the command runs in the adb shell otherwise if
329 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700330 reboot with shell=False will call 'adb reboot'. This
331 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700332 @param timeout: Time limit in seconds before attempting to
333 kill the running process. The run() function
334 will take a few seconds longer than 'timeout'
335 to complete if it has to kill the process.
336 @param ignore_status: Do not raise an exception, no matter
337 what the exit code of the command is.
338 @param ignore_timeout: Bool True if command timeouts should be
339 ignored. Will return None on command timeout.
340 @param stdout: Redirect stdout.
341 @param stderr: Redirect stderr.
342 @param connect_timeout: Connection timeout (in seconds)
343 @param options: String with additional ssh command options
344 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700345 @param require_sudo: True to require sudo to run the command. Default is
346 False.
Simran Basi431010f2013-09-04 10:42:41 -0700347 @param args: Sequence of strings to pass as arguments to command by
348 quoting them in " and escaping their contents if
349 necessary.
350
351 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700352 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700353 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800354 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700355 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800356 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700357 else:
358 raise NotImplementedError('Mode %s is not supported' % function)
359
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700360 if function != ADB_CMD and shell:
361 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700362
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700363 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700364
365 if serial:
366 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700367
Simran Basi431010f2013-09-04 10:42:41 -0700368 if shell:
369 cmd += '%s ' % SHELL_CMD
370 cmd += command
371
Roshan Pius58e5dd32015-10-16 15:16:42 -0700372 if verbose:
373 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700374
Kevin Cheng85e864a2015-11-30 11:49:34 -0800375 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400376 ignore_status=ignore_status,
377 ignore_timeout=ignore_timeout, stdout_tee=stdout,
378 stderr_tee=stderr, options=options, stdin=stdin,
379 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700380
381
Dan Shi8c51bda2016-05-26 12:21:02 -0700382 def _run_output_with_retry(self, cmd):
383 """Call run_output method for the given command with retry.
384
385 adb command can be flaky some time and return empty string. It may take
386 several retries until a value can be returned.
387
388 @param cmd: The command to run.
389
390 @return: Return value from the command after retry.
391 """
392 try:
393 return client_utils.poll_for_condition(
394 lambda: self.run_output(cmd),
395 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS,
396 sleep_interval=0.5,
397 desc='Get return value for command `%s`' % cmd)
398 except client_utils.TimeoutError:
399 return ''
400
401
Dan Shie234dea2016-01-20 17:15:17 -0800402 def get_board_name(self):
403 """Get the name of the board, e.g., shamu, dragonboard etc.
404 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700405 product = self.run_output('getprop %s' % BOARD_FILE)
406 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800407
408
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700409 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700410 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700411 """Determine the correct board label for the device.
412
413 @returns a string representing this device's board.
414 """
Dan Shie234dea2016-01-20 17:15:17 -0800415 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700416 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800417 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700418
419
Christopher Wiley08849d52013-11-22 08:57:58 -0800420 def job_start(self):
Christopher Wiley08849d52013-11-22 08:57:58 -0800421 """
Dan Shi2d279cf2016-05-27 22:06:10 +0000422 Disable log collection on adb_hosts.
423
424 TODO(sbasi): crbug.com/305427
425 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800426
427
Simran Basi431010f2013-09-04 10:42:41 -0700428 def run(self, command, timeout=3600, ignore_status=False,
429 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
430 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700431 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700432 """Run a command on the adb device.
433
434 The command given will be ran directly on the adb device; for example
435 'ls' will be ran as: 'abd shell ls'
436
437 @param command: The command line string.
438 @param timeout: Time limit in seconds before attempting to
439 kill the running process. The run() function
440 will take a few seconds longer than 'timeout'
441 to complete if it has to kill the process.
442 @param ignore_status: Do not raise an exception, no matter
443 what the exit code of the command is.
444 @param ignore_timeout: Bool True if command timeouts should be
445 ignored. Will return None on command timeout.
446 @param stdout_tee: Redirect stdout.
447 @param stderr_tee: Redirect stderr.
448 @param connect_timeout: Connection timeout (in seconds).
449 @param options: String with additional ssh command options.
450 @param stdin: Stdin to pass (a string) to the executed command
451 @param args: Sequence of strings to pass as arguments to command by
452 quoting them in " and escaping their contents if
453 necessary.
454
455 @returns A CMDResult object or None if the call timed out and
456 ignore_timeout is True.
457
458 @raises AutoservRunError: If the command failed.
459 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700460 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700461 command = ('"%s; echo %s:\$?"' %
462 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700463 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700464 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700465 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
466 stdout=stdout_tee, stderr=stderr_tee,
467 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700468 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700469 if not result:
470 # In case of timeouts.
471 return None
472
473 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700474 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700475 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700476 'Failed to parse the exit code for command: %s' %
477 command, result)
478 elif parse_output:
479 result.stdout = parse_output.group('OUTPUT')
480 result.exit_status = int(parse_output.group('EXIT_CODE'))
481 if result.exit_status != 0 and not ignore_status:
482 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700483 return result
484
485
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700486 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
487 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700488
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700489 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700490
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700491 @param timeout: Time limit in seconds before returning even if the host
492 is not up.
493 @param command: The command used to test if a device is up, i.e.,
494 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700495
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700496 @returns True if the host was found to be up before the timeout expires,
497 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700498 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700499 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
500 delay_sec=1)
501 def _wait_up():
502 if not self.is_up(command=command):
503 raise error.TimeoutException('Device is still down.')
504 return True
505
506 try:
507 _wait_up()
508 logging.debug('Host %s is now up, and can be accessed by %s.',
509 self.hostname, command)
510 return True
511 except error.TimeoutException:
512 logging.debug('Host %s is still down after waiting %d seconds',
513 self.hostname, timeout)
514 return False
Simran Basi431010f2013-09-04 10:42:41 -0700515
516
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700517 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
518 warning_timer=None, old_boot_id=None, command=ADB_CMD):
519 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700520
521 Overrides wait_down from AbstractSSHHost.
522
523 @param timeout: Time in seconds to wait for the host to go down.
524 @param warning_timer: Time limit in seconds that will generate
525 a warning if the host is not down yet.
526 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700527 @param old_boot_id: Not applicable for adb_host.
528 @param command: `adb`, test if the device can be accessed by adb
529 command, or `fastboot`, test if the device can be accessed by
530 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700531
532 @returns True if the device goes down before the timeout, False
533 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700534 """
535 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
536 delay_sec=1)
537 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700538 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700539 raise error.TimeoutException('Device is still up.')
540 return True
541
542 try:
543 _wait_down()
544 logging.debug('Host %s is now down', self.hostname)
545 return True
546 except error.TimeoutException:
547 logging.debug('Host %s is still up after waiting %d seconds',
548 self.hostname, timeout)
549 return False
550
551
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700552 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700553 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700554
555 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700556 """
557 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700558 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700559 self.adb_run('reboot', timeout=10, ignore_timeout=True)
560 if not self.wait_down():
561 raise error.AutoservRebootError(
562 'ADB Device is still up after reboot')
563 if not self.wait_up():
564 raise error.AutoservRebootError(
565 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800566 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800567
568
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300569 def fastboot_reboot(self):
570 """Do a fastboot reboot to go back to adb.
571
572 @raises AutoservRebootError if reboot failed.
573 """
574 self.fastboot_run('reboot')
575 if not self.wait_down(command=FASTBOOT_CMD):
576 raise error.AutoservRebootError(
577 'Device is still in fastboot mode after reboot')
578 if not self.wait_up():
579 raise error.AutoservRebootError(
580 'Device failed to boot to adb after fastboot reboot.')
581 self._reset_adbd_connection()
582
583
Ralph Nathanb45eb672015-11-18 20:04:39 -0800584 def remount(self):
585 """Remounts paritions on the device read-write.
586
587 Specifically, the /system, /vendor (if present) and /oem (if present)
588 partitions on the device are remounted read-write.
589 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800590 self.adb_run('remount')
591
592
Kevin Cheng549beb42015-11-18 11:42:25 -0800593 @staticmethod
594 def parse_device_serials(devices_output):
595 """Return a list of parsed serials from the output.
596
597 @param devices_output: Output from either an adb or fastboot command.
598
599 @returns List of device serials
600 """
601 devices = []
602 for line in devices_output.splitlines():
603 match = re.search(DEVICE_FINDER_REGEX, line)
604 if match:
605 serial = match.group('SERIAL')
606 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
607 serial = DEVICE_NO_SERIAL_TAG
608 logging.debug('Found Device: %s', serial)
609 devices.append(serial)
610 return devices
611
612
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700613 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700614 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700615
616 @params use_adb: True to get adb accessible devices. Set to False to
617 get fastboot accessible devices.
618
Kevin Chengd19e6c62015-10-28 16:39:39 -0700619 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700620 """
621 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300622 result = self.adb_run('devices').stdout
623 if self.adb_serial and self.adb_serial not in result:
624 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700625 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300626 result = self.fastboot_run('devices').stdout
627 if (self.fastboot_serial and
628 self.fastboot_serial not in result):
629 # fastboot devices won't list the devices using TCP
630 try:
631 if 'product' in self.fastboot_run('getvar product',
632 timeout=2).stderr:
633 result += '\n%s\tfastboot' % self.fastboot_serial
Kevin Chengcfcb2cf2016-04-13 10:04:36 -0700634 # The main reason we do a general Exception catch here instead
635 # of setting ignore_timeout/status to True is because even when
636 # the fastboot process has been nuked, it still stays around and
637 # so bgjob wants to warn us of this and tries to read the
638 # /proc/<pid>/stack file which then promptly returns an
639 # 'Operation not permitted' error since we're running as moblab
640 # and we don't have permission to read those files.
641 except Exception:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300642 pass
643 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700644
645
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700646 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700647 """Get a list of devices currently attached to the test station and
648 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700649 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800650 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700651 raise error.AutoservError(
652 'Not given ADB serial but multiple devices detected')
653 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700654
655
656 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700657 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700658 accessible by fastboot command.
659 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700660 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800661 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700662 raise error.AutoservError(
663 'Not given fastboot serial but multiple devices detected')
664 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700665
666
667 def is_up(self, timeout=0, command=ADB_CMD):
668 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700669
670 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700671 @param command: `adb`, the device can be accessed by adb command,
672 or `fastboot`, the device can be accessed by fastboot command.
673 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700674
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700675 @returns True if the device is detectable by given command, False
676 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700677
678 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700679 if command == ADB_CMD:
680 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800681 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800682 # ADB has a device state, if the device is not online, no
683 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800684 # DUT with single device connected may not have adb_serial set.
685 # Therefore, skip checking if serial is in the list of adb devices
686 # if self.adb_serial is not set.
687 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800688 logging.debug('Waiting for device to enter the ready state.')
689 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700690 elif command == FASTBOOT_CMD:
691 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800692 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700693 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700694 raise NotImplementedError('Mode %s is not supported' % command)
695
696 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700697
698
699 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700700 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700701
702 Called as the test ends. Will return the device to USB mode and kill
703 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700704 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800705 # TODO(sbasi) Originally, we would kill the server after each test to
706 # reduce the opportunity for bad server state to hang around.
707 # Unfortunately, there is a period of time after each kill during which
708 # the Android device becomes unusable, and if we start the next test
709 # too quickly, we'll get an error complaining about no ADB device
710 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700711 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800712 # |close| the associated teststation as well.
713 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700714 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700715
716
717 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700718 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700719
720 @param message String message to log into syslog
721 @param tag String tag prefix for syslog
722
723 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700724 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700725
726
727 def get_autodir(self):
728 """Return the directory to install autotest for client side tests."""
729 return '/data/autotest'
730
Kevin Cheng018db352015-09-20 02:22:08 -0700731
Kris Rambishde8f9d12015-12-16 12:42:41 -0800732 def is_device_ready(self):
733 """Return the if the device is ready for ADB commands."""
Dan Shi7075f552016-04-21 15:42:41 -0700734 try:
735 # Retry to avoid possible flakes.
736 is_ready = client_utils.poll_for_condition(
737 lambda: self.adb_run('get-state').stdout.strip() == 'device',
738 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS, sleep_interval=1,
739 desc='Waiting for device state to be `device`')
740 except client_utils.TimeoutError:
741 is_ready = False
742
743 logging.debug('Device state is %sready', '' if is_ready else 'NOT ')
744 return is_ready
Kris Rambishde8f9d12015-12-16 12:42:41 -0800745
746
Kevin Chengd19e6c62015-10-28 16:39:39 -0700747 def verify_connectivity(self):
748 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800749 if not self.is_device_ready():
750 raise error.AutoservHostError('device state is not in the '
751 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700752
753
Simran Basid3ba3fb2015-09-11 14:35:07 -0700754 def verify_software(self):
755 """Verify working software on an adb_host.
756
Simran Basi38f7ddf2015-09-18 12:25:03 -0700757 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700758 """
Dan Shiab999722015-12-04 14:27:08 -0800759 # Check if adb and fastboot are present.
760 self.teststation.run('which adb')
761 self.teststation.run('which fastboot')
762 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700763
Dan Shi626d5412016-05-16 16:05:13 -0700764 # Apply checks only for Android device.
Dan Shi1e2a98a2016-05-18 12:08:08 -0700765 if self.get_os_type() == OS_TYPE_ANDROID:
Dan Shi626d5412016-05-16 16:05:13 -0700766 # Make sure ro.boot.hardware and ro.build.product match.
Dan Shi8c51bda2016-05-26 12:21:02 -0700767 hardware = self._run_output_with_retry('getprop ro.boot.hardware')
768 product = self._run_output_with_retry('getprop ro.build.product')
Dan Shi1e2a98a2016-05-18 12:08:08 -0700769 if hardware != product:
770 raise error.AutoservHostError('ro.boot.hardware: %s does not '
771 'match to ro.build.product: %s' %
772 (hardware, product))
773
Dan Shi626d5412016-05-16 16:05:13 -0700774 # Check the bootloader is not locked. sys.oem_unlock_allowed is not
775 # applicable to Brillo devices.
Dan Shi8c51bda2016-05-26 12:21:02 -0700776 result = self._run_output_with_retry(
777 'getprop sys.oem_unlock_allowed')
Dan Shi626d5412016-05-16 16:05:13 -0700778 if result != PROPERTY_VALUE_TRUE:
779 raise error.AutoservHostError(
780 'The bootloader is locked. sys.oem_unlock_allowed: %s.'
781 % result)
782
Kevin Cheng018db352015-09-20 02:22:08 -0700783
Simran Basid3ba3fb2015-09-11 14:35:07 -0700784 def verify_job_repo_url(self, tag=''):
785 """Make sure job_repo_url of this host is valid.
786
Simran Basi38f7ddf2015-09-18 12:25:03 -0700787 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700788
789 @param tag: The tag from the server job, in the format
790 <job_id>-<user>/<hostname>, or <hostless> for a server job.
791 """
792 return
Kevin Cheng018db352015-09-20 02:22:08 -0700793
794
Simran Basibeb2bb22016-02-03 15:25:48 -0800795 def repair(self):
796 """Attempt to get the DUT to pass `self.verify()`."""
797 try:
798 self.ensure_adb_mode(timeout=30)
799 return
800 except error.AutoservError as e:
801 logging.error(e)
802 logging.debug('Verifying the device is accessible via fastboot.')
803 self.ensure_bootloader_mode()
804 if not self.job.run_test(
805 'provision_AndroidUpdate', host=self, value=None,
806 force=True, repair=True):
807 raise error.AutoservRepairTotalFailure(
808 'Unable to repair the device.')
809
810
Simran Basi1b023762015-09-25 12:12:20 -0700811 def send_file(self, source, dest, delete_dest=False,
812 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700813 """Copy files from the drone to the device.
814
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400815 Just a note, there is the possibility the test station is localhost
816 which makes some of these steps redundant (e.g. creating tmp dir) but
817 that scenario will undoubtedly be a development scenario (test station
818 is also the moblab) and not the typical live test running scenario so
819 the redundancy I think is harmless.
820
Kevin Cheng018db352015-09-20 02:22:08 -0700821 @param source: The file/directory on the drone to send to the device.
822 @param dest: The destination path on the device to copy to.
823 @param delete_dest: A flag set to choose whether or not to delete
824 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700825 @param preserve_symlinks: Controls if symlinks on the source will be
826 copied as such on the destination or
827 transformed into the referenced
828 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700829 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700830 # If we need to preserve symlinks, let's check if the source is a
831 # symlink itself and if so, just create it on the device.
832 if preserve_symlinks:
833 symlink_target = None
834 try:
835 symlink_target = os.readlink(source)
836 except OSError:
837 # Guess it's not a symlink.
838 pass
839
840 if symlink_target is not None:
841 # Once we create the symlink, let's get out of here.
842 self.run('ln -s %s %s' % (symlink_target, dest))
843 return
844
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400845 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700846 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400847 src_path = os.path.join(tmp_dir, os.path.basename(dest))
848 # Now copy the file over to the test station so you can reference the
849 # file in the push command.
850 self.teststation.send_file(source, src_path,
851 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700852
853 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400854 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700855
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700856 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700857
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400858 # Cleanup the test station.
859 try:
860 self.teststation.run('rm -rf %s' % tmp_dir)
861 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
862 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700863
864
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700865 def _get_file_info(self, dest):
866 """Get permission and possible symlink info about file on the device.
867
868 These files are on the device so we only have shell commands (via adb)
869 to get the info we want. We'll use 'ls' to get it all.
870
871 @param dest: File to get info about.
872
873 @returns a dict of the file permissions and symlink.
874 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800875 # Grab file info.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700876 file_info = self.run_output('ls -ld %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700877 symlink = None
878 perms = 0
879 match = re.match(FILE_INFO_REGEX, file_info)
880 if match:
881 # Check if it's a symlink and grab the linked dest if it is.
882 if match.group('TYPE') == 'l':
883 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
884 if symlink_match:
885 symlink = symlink_match.group('SYMLINK')
886
887 # Set the perms.
888 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
889 if perm != '-':
890 perms |= perm_flag
891
892 return {'perms': perms,
893 'symlink': symlink}
894
895
Simran Basi1b023762015-09-25 12:12:20 -0700896 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
897 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700898 """Copy files from the device to the drone.
899
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400900 Just a note, there is the possibility the test station is localhost
901 which makes some of these steps redundant (e.g. creating tmp dir) but
902 that scenario will undoubtedly be a development scenario (test station
903 is also the moblab) and not the typical live test running scenario so
904 the redundancy I think is harmless.
905
Kevin Cheng018db352015-09-20 02:22:08 -0700906 @param source: The file/directory on the device to copy back to the
907 drone.
908 @param dest: The destination path on the drone to copy to.
909 @param delete_dest: A flag set to choose whether or not to delete
910 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700911 @param preserve_perm: Tells get_file() to try to preserve the sources
912 permissions on files and dirs.
913 @param preserve_symlinks: Try to preserve symlinks instead of
914 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700915 """
David Purselle01548b2016-05-11 10:00:42 -0700916 # Stage the files on the test station under teststation_temp_dir.
917 teststation_temp_dir = self.teststation.get_tmp_dir()
918 teststation_dest = os.path.join(teststation_temp_dir,
919 os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700920
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700921 source_info = {}
922 if preserve_symlinks or preserve_perm:
923 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700924
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700925 # If we want to preserve symlinks, just create it here, otherwise pull
926 # the file off the device.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700927 #
928 # TODO(sadmac): Directories containing symlinks won't behave as
929 # expected.
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700930 if preserve_symlinks and source_info['symlink']:
931 os.symlink(source_info['symlink'], dest)
932 else:
David Purselle01548b2016-05-11 10:00:42 -0700933 self.adb_run('pull %s %s' % (source, teststation_temp_dir))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700934
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400935 # Copy over the file from the test station and clean up.
David Purselle01548b2016-05-11 10:00:42 -0700936 self.teststation.get_file(teststation_dest, dest,
937 delete_dest=delete_dest)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400938 try:
David Purselle01548b2016-05-11 10:00:42 -0700939 self.teststation.run('rm -rf %s' % teststation_temp_dir)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400940 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
David Purselle01548b2016-05-11 10:00:42 -0700941 logging.warn('failed to remove dir %s: %s',
942 teststation_temp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700943
David Pursell788b1b52016-05-19 09:03:31 -0700944 # Source will be copied under dest if either:
945 # 1. Source is a directory and doesn't end with /.
946 # 2. Source is a file and dest is a directory.
947 source_is_dir = self.run('[ -d "$${%s} ]',
948 ignore_status=True).exit_status == 0
949 if ((source_is_dir and not source.endswith(os.sep)) or
950 (not source_is_dir and os.path.isdir(dest))):
951 receive_path = os.path.join(dest, os.path.basename(source))
952 else:
953 receive_path = dest
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700954
David Pursell788b1b52016-05-19 09:03:31 -0700955 # Set the permissions of the received file/dirs.
956 if os.path.isdir(receive_path):
957 for root, _dirs, files in os.walk(receive_path):
958 def process(rel_path, default_perm):
959 info = self._get_file_info(os.path.join(source,
960 rel_path))
961 if info['perms'] != 0:
962 target = os.path.join(receive_path, rel_path)
963 if preserve_perm:
964 os.chmod(target, info['perms'])
965 else:
966 os.chmod(target, default_perm)
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700967
David Pursell788b1b52016-05-19 09:03:31 -0700968 rel_root = os.path.relpath(root, receive_path)
969 process(rel_root, _DEFAULT_DIR_PERMS)
970 for f in files:
971 process(os.path.join(rel_root, f), _DEFAULT_FILE_PERMS)
972 elif preserve_perm:
973 os.chmod(receive_path, source_info['perms'])
974 else:
975 os.chmod(receive_path, _DEFAULT_FILE_PERMS)
Kevin Cheng018db352015-09-20 02:22:08 -0700976
977
978 def get_release_version(self):
979 """Get the release version from the RELEASE_FILE on the device.
980
981 @returns The release string in the RELEASE_FILE.
982
983 """
984 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700985
986
987 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700988 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700989
Kevin Chengd19e6c62015-10-28 16:39:39 -0700990 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700991
992 @param parent: Parent directory of the returned tmp dir.
993
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700994 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700995 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700996 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
997 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700998 if not parent.startswith(TMP_DIR):
999 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -07001000 self.run('mkdir -p %s' % parent)
1001 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
1002 self.tmp_dirs.append(tmp_dir)
1003 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -07001004
1005
1006 def get_platform(self):
1007 """Determine the correct platform label for this host.
1008
1009 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -07001010 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -07001011
1012 @returns a string representing this host's platform.
1013 """
1014 return 'adb'
1015
1016
Gilad Arnolda76bef02015-09-29 13:55:15 -07001017 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -08001018 """Get the OS type of the DUT, e.g., android or brillo.
1019 """
1020 if not self._os_type:
1021 if self.run_output('getprop ro.product.brand') == 'Brillo':
1022 self._os_type = OS_TYPE_BRILLO
1023 else:
1024 self._os_type = OS_TYPE_ANDROID
1025
1026 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001027
1028
1029 def _forward(self, reverse, args):
1030 """Execute a forwarding command.
1031
1032 @param reverse: Whether this is reverse forwarding (Boolean).
1033 @param args: List of command arguments.
1034 """
1035 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001036 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001037
1038
1039 def add_forwarding(self, src, dst, reverse=False, rebind=True):
1040 """Forward a port between the ADB host and device.
1041
1042 Port specifications are any strings accepted as such by ADB, for
1043 example 'tcp:8080'.
1044
1045 @param src: Port specification to forward from.
1046 @param dst: Port specification to forward to.
1047 @param reverse: Do reverse forwarding from device to host (Boolean).
1048 @param rebind: Allow rebinding an already bound port (Boolean).
1049 """
1050 args = []
1051 if not rebind:
1052 args.append('--no-rebind')
1053 args += [src, dst]
1054 self._forward(reverse, args)
1055
1056
1057 def remove_forwarding(self, src=None, reverse=False):
1058 """Removes forwarding on port.
1059
1060 @param src: Port specification, or None to remove all forwarding.
1061 @param reverse: Whether this is reverse forwarding (Boolean).
1062 """
1063 args = []
1064 if src is None:
1065 args.append('--remove-all')
1066 else:
1067 args += ['--remove', src]
1068 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001069
1070
xixuan6cf6d2f2016-01-29 15:29:00 -08001071 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001072 """
1073 Forwards a port securely through a tunnel process from the server
1074 to the DUT for RPC server connection.
1075 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
1076 to the DUT.
1077
1078 @param port: remote port on the DUT.
1079 @param local_port: local forwarding port.
1080
1081 @return: the tunnel process.
1082 """
1083 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001084 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001085
1086
xixuan6cf6d2f2016-01-29 15:29:00 -08001087 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001088 """
1089 Disconnects a previously forwarded port from the server to the DUT for
1090 RPC server connection.
1091 Remove the previously added 'ADB forward' rule to forward the RPC
1092 packets from the AdbHost to the DUT.
1093
1094 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -08001095 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -07001096 @param port: remote port on the DUT.
1097
1098 """
1099 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001100 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001101
1102
1103 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001104 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001105
1106 @raise: error.AutoservError if the device failed to reboot into
1107 bootloader mode.
1108 """
1109 if self.is_up(command=FASTBOOT_CMD):
1110 return
1111 self.adb_run('reboot bootloader')
1112 if not self.wait_up(command=FASTBOOT_CMD):
1113 raise error.AutoservError(
1114 'The device failed to reboot into bootloader mode.')
1115
1116
Dan Shie4e807b2015-12-10 09:04:03 -08001117 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001118 """Ensure the device is up and can be accessed by adb command.
1119
Dan Shie4e807b2015-12-10 09:04:03 -08001120 @param timeout: Time limit in seconds before returning even if the host
1121 is not up.
1122
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001123 @raise: error.AutoservError if the device failed to reboot into
1124 adb mode.
1125 """
1126 if self.is_up():
1127 return
Dan Shi04980372016-03-22 10:57:47 -07001128 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1129 # check if the device is in adb mode.
1130 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001131 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001132 raise error.AutoservError(
1133 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001134 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001135
1136
1137 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001138 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001139 """Get the Android build information from the build url.
1140
1141 @param build_url: The url to use for downloading Android artifacts.
1142 pattern: http://$devserver:###/static/branch/target/build_id
1143
Dan Shi6450e142016-03-11 11:52:20 -08001144 @return: A dictionary of build information, including keys:
1145 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001146 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001147 """
Dan Shiab999722015-12-04 14:27:08 -08001148 if not build_url:
1149 raise AndroidInstallError('Need build_url to download image files.')
1150
1151 try:
1152 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001153 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001154 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001155 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001156 match.group('BUILD_TYPE'))),
1157 'build_id': match.group('BUILD_ID')}
1158 except (AttributeError, IndexError, ValueError) as e:
1159 raise AndroidInstallError(
1160 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001161
1162
Dan Shia2872172015-10-31 01:16:51 -07001163 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001164 def download_file(self, build_url, file, dest_dir, unzip=False,
1165 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001166 """Download the given file from the build url.
1167
1168 @param build_url: The url to use for downloading Android artifacts.
1169 pattern: http://$devserver:###/static/branch/target/build_id
1170 @param file: Name of the file to be downloaded, e.g., boot.img.
1171 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001172 @param unzip: If True, unzip the downloaded file.
1173 @param unzip_dest: Location to unzip the downloaded file to. If not
1174 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001175 """
Dan Shidb0366c2016-02-19 10:36:18 -08001176 # Append the file name to the url if build_url is linked to the folder
1177 # containing the file.
1178 if not build_url.endswith('/%s' % file):
1179 src_url = os.path.join(build_url, file)
1180 else:
1181 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001182 dest_file = os.path.join(dest_dir, file)
1183 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001184 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001185 if unzip:
1186 unzip_dest = unzip_dest or dest_dir
1187 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1188 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001189 except:
1190 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001191 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001192 raise
1193
1194
Dan Shiab999722015-12-04 14:27:08 -08001195 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001196 """Download required image files from the given build_url to a local
1197 directory in the machine runs fastboot command.
1198
1199 @param build_url: The url to use for downloading Android artifacts.
1200 pattern: http://$devserver:###/static/branch/target/build_id
1201
1202 @return: Path to the directory contains image files.
1203 """
Dan Shi08ff1282016-02-18 19:51:16 -08001204 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001205
1206 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001207 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001208
1209 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001210 self.download_file(build_url, zipped_image_file, image_dir,
1211 unzip=True)
Dan Shi49d451f2016-04-19 09:25:01 -07001212 images = android_utils.AndroidImageFiles.get_standalone_images(
1213 build_info['build_target'])
1214 for image_file in images:
Dan Shidb0366c2016-02-19 10:36:18 -08001215 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001216
Dan Shia2872172015-10-31 01:16:51 -07001217 return image_dir
1218 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001219 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001220 raise
1221
1222
Dan Shiab999722015-12-04 14:27:08 -08001223 def stage_brillo_image_files(self, build_url):
1224 """Download required brillo image files from the given build_url to a
1225 local directory in the machine runs fastboot command.
1226
1227 @param build_url: The url to use for downloading Android artifacts.
1228 pattern: http://$devserver:###/static/branch/target/build_id
1229
1230 @return: Path to the directory contains image files.
1231 """
Dan Shi08ff1282016-02-18 19:51:16 -08001232 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001233
1234 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1235 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1236 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001237
1238 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001239 self.download_file(build_url, zipped_image_file, image_dir,
1240 unzip=True)
1241 self.download_file(build_url, vendor_partitions_file, image_dir,
1242 unzip=True,
1243 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001244 return image_dir
1245 except:
1246 self.teststation.run('rm -rf %s' % image_dir)
1247 raise
1248
1249
Simran Basibeb2bb22016-02-03 15:25:48 -08001250 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001251 """Stage a build on a devserver and return the build_url and devserver.
1252
1253 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001254
Dan Shi225b9042015-11-18 10:25:21 -08001255 @returns a tuple with an update URL like:
1256 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1257 and the devserver instance.
1258 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001259 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001260 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001261 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1262 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001263 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001264 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001265 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001266 devserver.trigger_download(target, build_id, branch,
1267 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001268 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001269
1270
Dan Shie4e807b2015-12-10 09:04:03 -08001271 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001272 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001273 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001274
1275 Following are the steps used here to provision an android device:
1276 1. If build_local_path is not set, download the image zip file, e.g.,
1277 shamu-img-2284311.zip, unzip it.
1278 2. Run fastboot to install following artifacts:
1279 bootloader, radio, boot, system, vendor(only if exists)
1280
1281 Repair is not supported for Android devices yet.
1282
1283 @param build_url: The url to use for downloading Android artifacts.
1284 pattern: http://$devserver:###/static/$build
1285 @param build_local_path: The path to a local folder that contains the
1286 image files needed to provision the device. Note that the folder
1287 is in the machine running adb command, rather than the drone.
1288 @param wipe: If true, userdata will be wiped before flashing.
1289 @param flash_all: If True, all img files found in img_path will be
1290 flashed. Otherwise, only boot and system are flashed.
1291
1292 @raises AndroidInstallError if any error occurs.
1293 """
Dan Shia2872172015-10-31 01:16:51 -07001294 # If the build is not staged in local server yet, clean up the temp
1295 # folder used to store image files after the provision is completed.
1296 delete_build_folder = bool(not build_local_path)
1297
1298 try:
1299 # Download image files needed for provision to a local directory.
1300 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001301 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001302
1303 # Device needs to be in bootloader mode for flashing.
1304 self.ensure_bootloader_mode()
1305
1306 if wipe:
Dan Shi12a4f662016-05-10 14:49:42 -07001307 self._fastboot_run_with_retry('-w')
Dan Shia2872172015-10-31 01:16:51 -07001308
1309 # Get all *.img file in the build_local_path.
1310 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001311 image_files = self.teststation.run(
1312 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001313 images = dict([(os.path.basename(f), f) for f in image_files])
Dan Shi49d451f2016-04-19 09:25:01 -07001314 build_info = self.get_build_info_from_build_url(build_url)
1315 board = build_info['build_target']
1316 all_images = (
1317 android_utils.AndroidImageFiles.get_standalone_images(board)
1318 + android_utils.AndroidImageFiles.get_zipped_images(board))
1319
1320 # Sort images to be flashed, bootloader needs to be the first one.
1321 bootloader = android_utils.AndroidImageFiles.BOOTLOADER
1322 sorted_images = sorted(
1323 images.items(),
1324 key=lambda pair: 0 if pair[0] == bootloader else 1)
1325 for image, image_file in sorted_images:
1326 if image not in all_images:
Dan Shia2872172015-10-31 01:16:51 -07001327 continue
1328 logging.info('Flashing %s...', image_file)
Dan Shi12a4f662016-05-10 14:49:42 -07001329 self._fastboot_run_with_retry('-S 256M flash %s %s' %
1330 (image[:-4], image_file))
Dan Shi49d451f2016-04-19 09:25:01 -07001331 if image == android_utils.AndroidImageFiles.BOOTLOADER:
Dan Shia2872172015-10-31 01:16:51 -07001332 self.fastboot_run('reboot-bootloader')
1333 self.wait_up(command=FASTBOOT_CMD)
1334 except Exception as e:
1335 logging.error('Install Android build failed with error: %s', e)
1336 # Re-raise the exception with type of AndroidInstallError.
1337 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1338 finally:
1339 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001340 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001341 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1342 DEFAULT_WAIT_UP_TIME_SECONDS)
1343 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001344 logging.info('Successfully installed Android build staged at %s.',
1345 build_url)
1346
1347
Dan Shiab999722015-12-04 14:27:08 -08001348 def install_brillo(self, build_url, build_local_path=None):
1349 """Install the Brillo DUT.
1350
1351 Following are the steps used here to provision an android device:
1352 1. If build_local_path is not set, download the image zip file, e.g.,
1353 dragonboard-img-123456.zip, unzip it. And download the vendor
1354 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1355 unzip it to vendor folder.
1356 2. Run provision_device script to install OS images and vendor
1357 partitions.
1358
1359 @param build_url: The url to use for downloading Android artifacts.
1360 pattern: http://$devserver:###/static/$build
1361 @param build_local_path: The path to a local folder that contains the
1362 image files needed to provision the device. Note that the folder
1363 is in the machine running adb command, rather than the drone.
1364
1365 @raises AndroidInstallError if any error occurs.
1366 """
1367 # If the build is not staged in local server yet, clean up the temp
1368 # folder used to store image files after the provision is completed.
1369 delete_build_folder = bool(not build_local_path)
1370
Dan Shiab999722015-12-04 14:27:08 -08001371 try:
1372 # Download image files needed for provision to a local directory.
1373 if not build_local_path:
1374 build_local_path = self.stage_brillo_image_files(build_url)
1375
1376 # Device needs to be in bootloader mode for flashing.
1377 self.ensure_bootloader_mode()
1378
1379 # Run provision_device command to install image files and vendor
1380 # partitions.
1381 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1382 cmd = (BRILLO_PROVISION_CMD %
1383 {'os_image_dir': build_local_path,
1384 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001385 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001386 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001387 self.teststation.run(cmd)
1388 except Exception as e:
1389 logging.error('Install Brillo build failed with error: %s', e)
1390 # Re-raise the exception with type of AndroidInstallError.
1391 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1392 finally:
1393 if delete_build_folder:
1394 self.teststation.run('rm -rf %s' % build_local_path)
1395 self.ensure_adb_mode()
1396 logging.info('Successfully installed Android build staged at %s.',
1397 build_url)
1398
1399
Dan Shibe3636a2016-02-14 22:48:01 -08001400 @property
1401 def job_repo_url_attribute(self):
1402 """Get the host attribute name for job_repo_url, which should append the
1403 adb serial.
1404 """
1405 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1406
1407
Dan Shie4e807b2015-12-10 09:04:03 -08001408 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001409 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001410 """Install the DUT.
1411
1412 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001413 pattern: http://$devserver:###/static/$build. If build_url is
1414 set to None, the code may try _parser.options.image to do the
1415 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001416 @param build_local_path: The path to a local directory that contains the
1417 image files needed to provision the device.
1418 @param wipe: If true, userdata will be wiped before flashing.
1419 @param flash_all: If True, all img files found in img_path will be
1420 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001421
Dan Shibe3636a2016-02-14 22:48:01 -08001422 @returns A tuple of (image_name, host_attributes).
1423 image_name is the name of image installed, e.g.,
1424 git_mnc-release/shamu-userdebug/1234
1425 host_attributes is a dictionary of (attribute, value), which
1426 can be saved to afe_host_attributes table in database. This
1427 method returns a dictionary with a single entry of
1428 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1429 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001430 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001431 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001432 if not build_url and self._parser.options.image:
1433 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001434 self._parser.options.image, os_type=os_type)
1435 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001436 self.install_android(
1437 build_url=build_url, build_local_path=build_local_path,
1438 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001439 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001440 self.install_brillo(
1441 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001442 else:
1443 raise error.InstallError(
1444 'Installation of os type %s is not supported.' %
1445 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001446 return (build_url.split('static/')[-1],
1447 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001448
1449
1450 def list_files_glob(self, path_glob):
1451 """Get a list of files on the device given glob pattern path.
1452
1453 @param path_glob: The path glob that we want to return the list of
1454 files that match the glob. Relative paths will not work as
1455 expected. Supply an absolute path to get the list of files
1456 you're hoping for.
1457
1458 @returns List of files that match the path_glob.
1459 """
1460 # This is just in case path_glob has no path separator.
1461 base_path = os.path.dirname(path_glob) or '.'
1462 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001463 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001464 if result.exit_status != 0:
1465 return []
1466 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001467
1468
Dan Shida995002016-04-25 23:12:58 -07001469 def install_apk(self, apk, force_reinstall=True):
Kevin Cheng31355942016-01-05 14:23:35 -08001470 """Install the specified apk.
1471
1472 This will install the apk and override it if it's already installed and
1473 will also allow for downgraded apks.
1474
1475 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001476 @param force_reinstall: True to reinstall the apk even if it's already
Dan Shida995002016-04-25 23:12:58 -07001477 installed. Default is set to True.
Dan Shidb0366c2016-02-19 10:36:18 -08001478
1479 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001480 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001481 client_utils.poll_for_condition(
1482 lambda: self.run('pm list packages',
1483 ignore_status=True).exit_status == 0,
1484 timeout=120)
Dan Shi043c45b2016-04-11 17:18:49 -07001485 client_utils.poll_for_condition(
1486 lambda: self.run('service list | grep mount',
1487 ignore_status=True).exit_status == 0,
1488 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001489 return self.adb_run('install %s -d %s' %
1490 ('-r' if force_reinstall else '', apk))
1491
1492
1493 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1494 def _confirm_apk_installed(self, package_name):
1495 """Confirm if apk is already installed with the given name.
1496
1497 `pm list packages` command is not reliable some time. The retry helps to
1498 reduce the chance of false negative.
1499
1500 @param package_name: Name of the package, e.g., com.android.phone.
1501
1502 @raise AutoservRunError: If the package is not found or pm list command
1503 failed for any reason.
1504 """
1505 name = 'package:%s' % package_name
1506 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1507
1508
1509 def is_apk_installed(self, package_name):
1510 """Check if apk is already installed with the given name.
1511
1512 @param package_name: Name of the package, e.g., com.android.phone.
1513
1514 @return: True if package is installed. False otherwise.
1515 """
1516 try:
1517 self._confirm_apk_installed(package_name)
1518 return True
1519 except:
1520 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001521
1522
1523 def get_attributes_to_clear_before_provision(self):
1524 """Get a list of attributes to be cleared before machine_install starts.
1525 """
1526 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001527
1528
1529 def get_labels(self):
1530 """Return a list of the labels gathered from the devices connected.
1531
1532 @return: A list of strings that denote the labels from all the devices
1533 connected.
1534 """
1535 return self.labels.get_labels(self)
1536
1537
1538 def update_labels(self):
1539 """Update the labels for this testbed."""
1540 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001541
1542
1543 def stage_server_side_package(self, image=None):
1544 """Stage autotest server-side package on devserver.
1545
1546 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1547
1548 @return: A url to the autotest server-side package. Return None if
1549 server-side package is not supported.
1550 @raise: error.AutoservError if fail to locate the build to test with.
1551 """
1552 if image:
1553 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1554 else:
1555 job_repo_url = afe_utils.get_host_attribute(
1556 self, self.job_repo_url_attribute)
1557 if job_repo_url:
1558 devserver_url, image = (
1559 tools.get_devserver_build_from_package_url(
1560 job_repo_url, True))
1561 ds = dev_server.AndroidBuildServer(devserver_url)
1562 else:
1563 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1564 if not labels:
1565 raise error.AutoservError(
1566 'Failed to stage server-side package. The host has '
1567 'no job_report_url attribute or version label.')
1568 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1569 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1570
1571 branch, target, build_id = utils.parse_launch_control_build(image)
1572 build_target, _ = utils.parse_launch_control_target(target)
1573
1574 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1575 # packaging is not supported.
1576 try:
1577 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1578 logging.warn('Build %s is older than %s. Server side packaging '
1579 'is disabled.', image,
1580 self.MIN_VERSION_SUPPORT_SSP)
1581 return None
1582 except ValueError:
1583 logging.warn('Failed to compare build id in %s with the minimum '
1584 'version that supports server side packaging. Server '
1585 'side packaging is disabled.', image)
1586 return None
1587
1588 ds.stage_artifacts(target, build_id, branch,
1589 artifacts=['autotest_server_package'])
1590 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1591 {'build_target': build_target,
1592 'build_id': build_id})
1593 return '%s/static/%s/%s' % (ds.url(), image,
1594 autotest_server_package_name)