blob: 282d3d4b0d6994042195050a7e72a27ce38cf2a2 [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 Shie234dea2016-01-20 17:15:17 -0800382 def get_board_name(self):
383 """Get the name of the board, e.g., shamu, dragonboard etc.
384 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700385 product = self.run_output('getprop %s' % BOARD_FILE)
386 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800387
388
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700389 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700390 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700391 """Determine the correct board label for the device.
392
393 @returns a string representing this device's board.
394 """
Dan Shie234dea2016-01-20 17:15:17 -0800395 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700396 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800397 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700398
399
Christopher Wiley08849d52013-11-22 08:57:58 -0800400 def job_start(self):
Christopher Wiley08849d52013-11-22 08:57:58 -0800401 """
Dan Shi2d279cf2016-05-27 22:06:10 +0000402 Disable log collection on adb_hosts.
403
404 TODO(sbasi): crbug.com/305427
405 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800406
407
Simran Basi431010f2013-09-04 10:42:41 -0700408 def run(self, command, timeout=3600, ignore_status=False,
409 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
410 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700411 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700412 """Run a command on the adb device.
413
414 The command given will be ran directly on the adb device; for example
415 'ls' will be ran as: 'abd shell ls'
416
417 @param command: The command line string.
418 @param timeout: Time limit in seconds before attempting to
419 kill the running process. The run() function
420 will take a few seconds longer than 'timeout'
421 to complete if it has to kill the process.
422 @param ignore_status: Do not raise an exception, no matter
423 what the exit code of the command is.
424 @param ignore_timeout: Bool True if command timeouts should be
425 ignored. Will return None on command timeout.
426 @param stdout_tee: Redirect stdout.
427 @param stderr_tee: Redirect stderr.
428 @param connect_timeout: Connection timeout (in seconds).
429 @param options: String with additional ssh command options.
430 @param stdin: Stdin to pass (a string) to the executed command
431 @param args: Sequence of strings to pass as arguments to command by
432 quoting them in " and escaping their contents if
433 necessary.
434
435 @returns A CMDResult object or None if the call timed out and
436 ignore_timeout is True.
437
438 @raises AutoservRunError: If the command failed.
439 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700440 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700441 command = ('"%s; echo %s:\$?"' %
442 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700443 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700444 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700445 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
446 stdout=stdout_tee, stderr=stderr_tee,
447 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700448 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700449 if not result:
450 # In case of timeouts.
451 return None
452
453 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700454 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700455 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700456 'Failed to parse the exit code for command: %s' %
457 command, result)
458 elif parse_output:
459 result.stdout = parse_output.group('OUTPUT')
460 result.exit_status = int(parse_output.group('EXIT_CODE'))
461 if result.exit_status != 0 and not ignore_status:
462 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700463 return result
464
465
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700466 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
467 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700468
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700469 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700470
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700471 @param timeout: Time limit in seconds before returning even if the host
472 is not up.
473 @param command: The command used to test if a device is up, i.e.,
474 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700475
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700476 @returns True if the host was found to be up before the timeout expires,
477 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700478 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700479 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
480 delay_sec=1)
481 def _wait_up():
482 if not self.is_up(command=command):
483 raise error.TimeoutException('Device is still down.')
484 return True
485
486 try:
487 _wait_up()
488 logging.debug('Host %s is now up, and can be accessed by %s.',
489 self.hostname, command)
490 return True
491 except error.TimeoutException:
492 logging.debug('Host %s is still down after waiting %d seconds',
493 self.hostname, timeout)
494 return False
Simran Basi431010f2013-09-04 10:42:41 -0700495
496
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700497 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
498 warning_timer=None, old_boot_id=None, command=ADB_CMD):
499 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700500
501 Overrides wait_down from AbstractSSHHost.
502
503 @param timeout: Time in seconds to wait for the host to go down.
504 @param warning_timer: Time limit in seconds that will generate
505 a warning if the host is not down yet.
506 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700507 @param old_boot_id: Not applicable for adb_host.
508 @param command: `adb`, test if the device can be accessed by adb
509 command, or `fastboot`, test if the device can be accessed by
510 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700511
512 @returns True if the device goes down before the timeout, False
513 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700514 """
515 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
516 delay_sec=1)
517 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700518 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700519 raise error.TimeoutException('Device is still up.')
520 return True
521
522 try:
523 _wait_down()
524 logging.debug('Host %s is now down', self.hostname)
525 return True
526 except error.TimeoutException:
527 logging.debug('Host %s is still up after waiting %d seconds',
528 self.hostname, timeout)
529 return False
530
531
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700532 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700533 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700534
535 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700536 """
537 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700538 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700539 self.adb_run('reboot', timeout=10, ignore_timeout=True)
540 if not self.wait_down():
541 raise error.AutoservRebootError(
542 'ADB Device is still up after reboot')
543 if not self.wait_up():
544 raise error.AutoservRebootError(
545 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800546 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800547
548
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300549 def fastboot_reboot(self):
550 """Do a fastboot reboot to go back to adb.
551
552 @raises AutoservRebootError if reboot failed.
553 """
554 self.fastboot_run('reboot')
555 if not self.wait_down(command=FASTBOOT_CMD):
556 raise error.AutoservRebootError(
557 'Device is still in fastboot mode after reboot')
558 if not self.wait_up():
559 raise error.AutoservRebootError(
560 'Device failed to boot to adb after fastboot reboot.')
561 self._reset_adbd_connection()
562
563
Ralph Nathanb45eb672015-11-18 20:04:39 -0800564 def remount(self):
565 """Remounts paritions on the device read-write.
566
567 Specifically, the /system, /vendor (if present) and /oem (if present)
568 partitions on the device are remounted read-write.
569 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800570 self.adb_run('remount')
571
572
Kevin Cheng549beb42015-11-18 11:42:25 -0800573 @staticmethod
574 def parse_device_serials(devices_output):
575 """Return a list of parsed serials from the output.
576
577 @param devices_output: Output from either an adb or fastboot command.
578
579 @returns List of device serials
580 """
581 devices = []
582 for line in devices_output.splitlines():
583 match = re.search(DEVICE_FINDER_REGEX, line)
584 if match:
585 serial = match.group('SERIAL')
586 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
587 serial = DEVICE_NO_SERIAL_TAG
588 logging.debug('Found Device: %s', serial)
589 devices.append(serial)
590 return devices
591
592
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700593 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700594 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700595
596 @params use_adb: True to get adb accessible devices. Set to False to
597 get fastboot accessible devices.
598
Kevin Chengd19e6c62015-10-28 16:39:39 -0700599 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700600 """
601 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300602 result = self.adb_run('devices').stdout
603 if self.adb_serial and self.adb_serial not in result:
604 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700605 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300606 result = self.fastboot_run('devices').stdout
607 if (self.fastboot_serial and
608 self.fastboot_serial not in result):
609 # fastboot devices won't list the devices using TCP
610 try:
611 if 'product' in self.fastboot_run('getvar product',
612 timeout=2).stderr:
613 result += '\n%s\tfastboot' % self.fastboot_serial
Kevin Chengcfcb2cf2016-04-13 10:04:36 -0700614 # The main reason we do a general Exception catch here instead
615 # of setting ignore_timeout/status to True is because even when
616 # the fastboot process has been nuked, it still stays around and
617 # so bgjob wants to warn us of this and tries to read the
618 # /proc/<pid>/stack file which then promptly returns an
619 # 'Operation not permitted' error since we're running as moblab
620 # and we don't have permission to read those files.
621 except Exception:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300622 pass
623 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700624
625
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700626 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700627 """Get a list of devices currently attached to the test station and
628 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700629 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800630 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700631 raise error.AutoservError(
632 'Not given ADB serial but multiple devices detected')
633 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700634
635
636 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700637 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700638 accessible by fastboot command.
639 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700640 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800641 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700642 raise error.AutoservError(
643 'Not given fastboot serial but multiple devices detected')
644 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700645
646
647 def is_up(self, timeout=0, command=ADB_CMD):
648 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700649
650 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700651 @param command: `adb`, the device can be accessed by adb command,
652 or `fastboot`, the device can be accessed by fastboot command.
653 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700654
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700655 @returns True if the device is detectable by given command, False
656 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700657
658 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700659 if command == ADB_CMD:
660 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800661 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800662 # ADB has a device state, if the device is not online, no
663 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800664 # DUT with single device connected may not have adb_serial set.
665 # Therefore, skip checking if serial is in the list of adb devices
666 # if self.adb_serial is not set.
667 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800668 logging.debug('Waiting for device to enter the ready state.')
669 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700670 elif command == FASTBOOT_CMD:
671 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800672 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700673 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700674 raise NotImplementedError('Mode %s is not supported' % command)
675
676 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700677
678
679 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700680 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700681
682 Called as the test ends. Will return the device to USB mode and kill
683 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700684 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800685 # TODO(sbasi) Originally, we would kill the server after each test to
686 # reduce the opportunity for bad server state to hang around.
687 # Unfortunately, there is a period of time after each kill during which
688 # the Android device becomes unusable, and if we start the next test
689 # too quickly, we'll get an error complaining about no ADB device
690 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700691 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800692 # |close| the associated teststation as well.
693 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700694 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700695
696
697 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700698 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700699
700 @param message String message to log into syslog
701 @param tag String tag prefix for syslog
702
703 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700704 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700705
706
707 def get_autodir(self):
708 """Return the directory to install autotest for client side tests."""
709 return '/data/autotest'
710
Kevin Cheng018db352015-09-20 02:22:08 -0700711
Kris Rambishde8f9d12015-12-16 12:42:41 -0800712 def is_device_ready(self):
713 """Return the if the device is ready for ADB commands."""
Dan Shi7075f552016-04-21 15:42:41 -0700714 try:
715 # Retry to avoid possible flakes.
716 is_ready = client_utils.poll_for_condition(
717 lambda: self.adb_run('get-state').stdout.strip() == 'device',
718 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS, sleep_interval=1,
719 desc='Waiting for device state to be `device`')
720 except client_utils.TimeoutError:
721 is_ready = False
722
723 logging.debug('Device state is %sready', '' if is_ready else 'NOT ')
724 return is_ready
Kris Rambishde8f9d12015-12-16 12:42:41 -0800725
726
Kevin Chengd19e6c62015-10-28 16:39:39 -0700727 def verify_connectivity(self):
728 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800729 if not self.is_device_ready():
730 raise error.AutoservHostError('device state is not in the '
731 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700732
733
Simran Basid3ba3fb2015-09-11 14:35:07 -0700734 def verify_software(self):
735 """Verify working software on an adb_host.
736
Simran Basi38f7ddf2015-09-18 12:25:03 -0700737 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700738 """
Dan Shiab999722015-12-04 14:27:08 -0800739 # Check if adb and fastboot are present.
740 self.teststation.run('which adb')
741 self.teststation.run('which fastboot')
742 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700743
Dan Shi626d5412016-05-16 16:05:13 -0700744 # Apply checks only for Android device.
Dan Shi1e2a98a2016-05-18 12:08:08 -0700745 if self.get_os_type() == OS_TYPE_ANDROID:
Dan Shi626d5412016-05-16 16:05:13 -0700746 # Make sure ro.boot.hardware and ro.build.product match.
Dan Shi1e2a98a2016-05-18 12:08:08 -0700747 hardware = self.run_output('getprop ro.boot.hardware')
748 product = self.run_output('getprop ro.build.product')
749 if hardware != product:
750 raise error.AutoservHostError('ro.boot.hardware: %s does not '
751 'match to ro.build.product: %s' %
752 (hardware, product))
753
Dan Shi626d5412016-05-16 16:05:13 -0700754 # Check the bootloader is not locked. sys.oem_unlock_allowed is not
755 # applicable to Brillo devices.
756 result = self.run_output('getprop sys.oem_unlock_allowed')
757 if result != PROPERTY_VALUE_TRUE:
758 raise error.AutoservHostError(
759 'The bootloader is locked. sys.oem_unlock_allowed: %s.'
760 % result)
761
Kevin Cheng018db352015-09-20 02:22:08 -0700762
Simran Basid3ba3fb2015-09-11 14:35:07 -0700763 def verify_job_repo_url(self, tag=''):
764 """Make sure job_repo_url of this host is valid.
765
Simran Basi38f7ddf2015-09-18 12:25:03 -0700766 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700767
768 @param tag: The tag from the server job, in the format
769 <job_id>-<user>/<hostname>, or <hostless> for a server job.
770 """
771 return
Kevin Cheng018db352015-09-20 02:22:08 -0700772
773
Simran Basibeb2bb22016-02-03 15:25:48 -0800774 def repair(self):
775 """Attempt to get the DUT to pass `self.verify()`."""
776 try:
777 self.ensure_adb_mode(timeout=30)
778 return
779 except error.AutoservError as e:
780 logging.error(e)
781 logging.debug('Verifying the device is accessible via fastboot.')
782 self.ensure_bootloader_mode()
783 if not self.job.run_test(
784 'provision_AndroidUpdate', host=self, value=None,
785 force=True, repair=True):
786 raise error.AutoservRepairTotalFailure(
787 'Unable to repair the device.')
788
789
Simran Basi1b023762015-09-25 12:12:20 -0700790 def send_file(self, source, dest, delete_dest=False,
791 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700792 """Copy files from the drone to the device.
793
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400794 Just a note, there is the possibility the test station is localhost
795 which makes some of these steps redundant (e.g. creating tmp dir) but
796 that scenario will undoubtedly be a development scenario (test station
797 is also the moblab) and not the typical live test running scenario so
798 the redundancy I think is harmless.
799
Kevin Cheng018db352015-09-20 02:22:08 -0700800 @param source: The file/directory on the drone to send to the device.
801 @param dest: The destination path on the device to copy to.
802 @param delete_dest: A flag set to choose whether or not to delete
803 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700804 @param preserve_symlinks: Controls if symlinks on the source will be
805 copied as such on the destination or
806 transformed into the referenced
807 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700808 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700809 # If we need to preserve symlinks, let's check if the source is a
810 # symlink itself and if so, just create it on the device.
811 if preserve_symlinks:
812 symlink_target = None
813 try:
814 symlink_target = os.readlink(source)
815 except OSError:
816 # Guess it's not a symlink.
817 pass
818
819 if symlink_target is not None:
820 # Once we create the symlink, let's get out of here.
821 self.run('ln -s %s %s' % (symlink_target, dest))
822 return
823
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400824 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700825 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400826 src_path = os.path.join(tmp_dir, os.path.basename(dest))
827 # Now copy the file over to the test station so you can reference the
828 # file in the push command.
829 self.teststation.send_file(source, src_path,
830 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700831
832 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400833 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700834
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700835 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700836
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400837 # Cleanup the test station.
838 try:
839 self.teststation.run('rm -rf %s' % tmp_dir)
840 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
841 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700842
843
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700844 def _get_file_info(self, dest):
845 """Get permission and possible symlink info about file on the device.
846
847 These files are on the device so we only have shell commands (via adb)
848 to get the info we want. We'll use 'ls' to get it all.
849
850 @param dest: File to get info about.
851
852 @returns a dict of the file permissions and symlink.
853 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800854 # Grab file info.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700855 file_info = self.run_output('ls -ld %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700856 symlink = None
857 perms = 0
858 match = re.match(FILE_INFO_REGEX, file_info)
859 if match:
860 # Check if it's a symlink and grab the linked dest if it is.
861 if match.group('TYPE') == 'l':
862 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
863 if symlink_match:
864 symlink = symlink_match.group('SYMLINK')
865
866 # Set the perms.
867 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
868 if perm != '-':
869 perms |= perm_flag
870
871 return {'perms': perms,
872 'symlink': symlink}
873
874
Simran Basi1b023762015-09-25 12:12:20 -0700875 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
876 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700877 """Copy files from the device to the drone.
878
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400879 Just a note, there is the possibility the test station is localhost
880 which makes some of these steps redundant (e.g. creating tmp dir) but
881 that scenario will undoubtedly be a development scenario (test station
882 is also the moblab) and not the typical live test running scenario so
883 the redundancy I think is harmless.
884
Kevin Cheng018db352015-09-20 02:22:08 -0700885 @param source: The file/directory on the device to copy back to the
886 drone.
887 @param dest: The destination path on the drone to copy to.
888 @param delete_dest: A flag set to choose whether or not to delete
889 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700890 @param preserve_perm: Tells get_file() to try to preserve the sources
891 permissions on files and dirs.
892 @param preserve_symlinks: Try to preserve symlinks instead of
893 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700894 """
David Purselle01548b2016-05-11 10:00:42 -0700895 # Stage the files on the test station under teststation_temp_dir.
896 teststation_temp_dir = self.teststation.get_tmp_dir()
897 teststation_dest = os.path.join(teststation_temp_dir,
898 os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700899
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700900 source_info = {}
901 if preserve_symlinks or preserve_perm:
902 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700903
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700904 # If we want to preserve symlinks, just create it here, otherwise pull
905 # the file off the device.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700906 #
907 # TODO(sadmac): Directories containing symlinks won't behave as
908 # expected.
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700909 if preserve_symlinks and source_info['symlink']:
910 os.symlink(source_info['symlink'], dest)
911 else:
David Purselle01548b2016-05-11 10:00:42 -0700912 self.adb_run('pull %s %s' % (source, teststation_temp_dir))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700913
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400914 # Copy over the file from the test station and clean up.
David Purselle01548b2016-05-11 10:00:42 -0700915 self.teststation.get_file(teststation_dest, dest,
916 delete_dest=delete_dest)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400917 try:
David Purselle01548b2016-05-11 10:00:42 -0700918 self.teststation.run('rm -rf %s' % teststation_temp_dir)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400919 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
David Purselle01548b2016-05-11 10:00:42 -0700920 logging.warn('failed to remove dir %s: %s',
921 teststation_temp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700922
David Pursell788b1b52016-05-19 09:03:31 -0700923 # Source will be copied under dest if either:
924 # 1. Source is a directory and doesn't end with /.
925 # 2. Source is a file and dest is a directory.
926 source_is_dir = self.run('[ -d "$${%s} ]',
927 ignore_status=True).exit_status == 0
928 if ((source_is_dir and not source.endswith(os.sep)) or
929 (not source_is_dir and os.path.isdir(dest))):
930 receive_path = os.path.join(dest, os.path.basename(source))
931 else:
932 receive_path = dest
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700933
David Pursell788b1b52016-05-19 09:03:31 -0700934 # Set the permissions of the received file/dirs.
935 if os.path.isdir(receive_path):
936 for root, _dirs, files in os.walk(receive_path):
937 def process(rel_path, default_perm):
938 info = self._get_file_info(os.path.join(source,
939 rel_path))
940 if info['perms'] != 0:
941 target = os.path.join(receive_path, rel_path)
942 if preserve_perm:
943 os.chmod(target, info['perms'])
944 else:
945 os.chmod(target, default_perm)
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700946
David Pursell788b1b52016-05-19 09:03:31 -0700947 rel_root = os.path.relpath(root, receive_path)
948 process(rel_root, _DEFAULT_DIR_PERMS)
949 for f in files:
950 process(os.path.join(rel_root, f), _DEFAULT_FILE_PERMS)
951 elif preserve_perm:
952 os.chmod(receive_path, source_info['perms'])
953 else:
954 os.chmod(receive_path, _DEFAULT_FILE_PERMS)
Kevin Cheng018db352015-09-20 02:22:08 -0700955
956
957 def get_release_version(self):
958 """Get the release version from the RELEASE_FILE on the device.
959
960 @returns The release string in the RELEASE_FILE.
961
962 """
963 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700964
965
966 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700967 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700968
Kevin Chengd19e6c62015-10-28 16:39:39 -0700969 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700970
971 @param parent: Parent directory of the returned tmp dir.
972
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700973 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700974 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700975 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
976 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700977 if not parent.startswith(TMP_DIR):
978 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700979 self.run('mkdir -p %s' % parent)
980 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
981 self.tmp_dirs.append(tmp_dir)
982 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700983
984
985 def get_platform(self):
986 """Determine the correct platform label for this host.
987
988 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700989 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700990
991 @returns a string representing this host's platform.
992 """
993 return 'adb'
994
995
Gilad Arnolda76bef02015-09-29 13:55:15 -0700996 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800997 """Get the OS type of the DUT, e.g., android or brillo.
998 """
999 if not self._os_type:
1000 if self.run_output('getprop ro.product.brand') == 'Brillo':
1001 self._os_type = OS_TYPE_BRILLO
1002 else:
1003 self._os_type = OS_TYPE_ANDROID
1004
1005 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001006
1007
1008 def _forward(self, reverse, args):
1009 """Execute a forwarding command.
1010
1011 @param reverse: Whether this is reverse forwarding (Boolean).
1012 @param args: List of command arguments.
1013 """
1014 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001015 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001016
1017
1018 def add_forwarding(self, src, dst, reverse=False, rebind=True):
1019 """Forward a port between the ADB host and device.
1020
1021 Port specifications are any strings accepted as such by ADB, for
1022 example 'tcp:8080'.
1023
1024 @param src: Port specification to forward from.
1025 @param dst: Port specification to forward to.
1026 @param reverse: Do reverse forwarding from device to host (Boolean).
1027 @param rebind: Allow rebinding an already bound port (Boolean).
1028 """
1029 args = []
1030 if not rebind:
1031 args.append('--no-rebind')
1032 args += [src, dst]
1033 self._forward(reverse, args)
1034
1035
1036 def remove_forwarding(self, src=None, reverse=False):
1037 """Removes forwarding on port.
1038
1039 @param src: Port specification, or None to remove all forwarding.
1040 @param reverse: Whether this is reverse forwarding (Boolean).
1041 """
1042 args = []
1043 if src is None:
1044 args.append('--remove-all')
1045 else:
1046 args += ['--remove', src]
1047 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001048
1049
xixuan6cf6d2f2016-01-29 15:29:00 -08001050 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001051 """
1052 Forwards a port securely through a tunnel process from the server
1053 to the DUT for RPC server connection.
1054 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
1055 to the DUT.
1056
1057 @param port: remote port on the DUT.
1058 @param local_port: local forwarding port.
1059
1060 @return: the tunnel process.
1061 """
1062 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001063 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001064
1065
xixuan6cf6d2f2016-01-29 15:29:00 -08001066 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001067 """
1068 Disconnects a previously forwarded port from the server to the DUT for
1069 RPC server connection.
1070 Remove the previously added 'ADB forward' rule to forward the RPC
1071 packets from the AdbHost to the DUT.
1072
1073 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -08001074 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -07001075 @param port: remote port on the DUT.
1076
1077 """
1078 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001079 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001080
1081
1082 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001083 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001084
1085 @raise: error.AutoservError if the device failed to reboot into
1086 bootloader mode.
1087 """
1088 if self.is_up(command=FASTBOOT_CMD):
1089 return
1090 self.adb_run('reboot bootloader')
1091 if not self.wait_up(command=FASTBOOT_CMD):
1092 raise error.AutoservError(
1093 'The device failed to reboot into bootloader mode.')
1094
1095
Dan Shie4e807b2015-12-10 09:04:03 -08001096 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001097 """Ensure the device is up and can be accessed by adb command.
1098
Dan Shie4e807b2015-12-10 09:04:03 -08001099 @param timeout: Time limit in seconds before returning even if the host
1100 is not up.
1101
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001102 @raise: error.AutoservError if the device failed to reboot into
1103 adb mode.
1104 """
1105 if self.is_up():
1106 return
Dan Shi04980372016-03-22 10:57:47 -07001107 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1108 # check if the device is in adb mode.
1109 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001110 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001111 raise error.AutoservError(
1112 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001113 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001114
1115
1116 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001117 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001118 """Get the Android build information from the build url.
1119
1120 @param build_url: The url to use for downloading Android artifacts.
1121 pattern: http://$devserver:###/static/branch/target/build_id
1122
Dan Shi6450e142016-03-11 11:52:20 -08001123 @return: A dictionary of build information, including keys:
1124 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001125 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001126 """
Dan Shiab999722015-12-04 14:27:08 -08001127 if not build_url:
1128 raise AndroidInstallError('Need build_url to download image files.')
1129
1130 try:
1131 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001132 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001133 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001134 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001135 match.group('BUILD_TYPE'))),
1136 'build_id': match.group('BUILD_ID')}
1137 except (AttributeError, IndexError, ValueError) as e:
1138 raise AndroidInstallError(
1139 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001140
1141
Dan Shia2872172015-10-31 01:16:51 -07001142 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001143 def download_file(self, build_url, file, dest_dir, unzip=False,
1144 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001145 """Download the given file from the build url.
1146
1147 @param build_url: The url to use for downloading Android artifacts.
1148 pattern: http://$devserver:###/static/branch/target/build_id
1149 @param file: Name of the file to be downloaded, e.g., boot.img.
1150 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001151 @param unzip: If True, unzip the downloaded file.
1152 @param unzip_dest: Location to unzip the downloaded file to. If not
1153 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001154 """
Dan Shidb0366c2016-02-19 10:36:18 -08001155 # Append the file name to the url if build_url is linked to the folder
1156 # containing the file.
1157 if not build_url.endswith('/%s' % file):
1158 src_url = os.path.join(build_url, file)
1159 else:
1160 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001161 dest_file = os.path.join(dest_dir, file)
1162 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001163 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001164 if unzip:
1165 unzip_dest = unzip_dest or dest_dir
1166 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1167 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001168 except:
1169 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001170 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001171 raise
1172
1173
Dan Shiab999722015-12-04 14:27:08 -08001174 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001175 """Download required image files from the given build_url to a local
1176 directory in the machine runs fastboot command.
1177
1178 @param build_url: The url to use for downloading Android artifacts.
1179 pattern: http://$devserver:###/static/branch/target/build_id
1180
1181 @return: Path to the directory contains image files.
1182 """
Dan Shi08ff1282016-02-18 19:51:16 -08001183 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001184
1185 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001186 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001187
1188 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001189 self.download_file(build_url, zipped_image_file, image_dir,
1190 unzip=True)
Dan Shi49d451f2016-04-19 09:25:01 -07001191 images = android_utils.AndroidImageFiles.get_standalone_images(
1192 build_info['build_target'])
1193 for image_file in images:
Dan Shidb0366c2016-02-19 10:36:18 -08001194 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001195
Dan Shia2872172015-10-31 01:16:51 -07001196 return image_dir
1197 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001198 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001199 raise
1200
1201
Dan Shiab999722015-12-04 14:27:08 -08001202 def stage_brillo_image_files(self, build_url):
1203 """Download required brillo image files from the given build_url to a
1204 local directory in the machine runs fastboot command.
1205
1206 @param build_url: The url to use for downloading Android artifacts.
1207 pattern: http://$devserver:###/static/branch/target/build_id
1208
1209 @return: Path to the directory contains image files.
1210 """
Dan Shi08ff1282016-02-18 19:51:16 -08001211 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001212
1213 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1214 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1215 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001216
1217 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001218 self.download_file(build_url, zipped_image_file, image_dir,
1219 unzip=True)
1220 self.download_file(build_url, vendor_partitions_file, image_dir,
1221 unzip=True,
1222 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001223 return image_dir
1224 except:
1225 self.teststation.run('rm -rf %s' % image_dir)
1226 raise
1227
1228
Simran Basibeb2bb22016-02-03 15:25:48 -08001229 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001230 """Stage a build on a devserver and return the build_url and devserver.
1231
1232 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001233
Dan Shi225b9042015-11-18 10:25:21 -08001234 @returns a tuple with an update URL like:
1235 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1236 and the devserver instance.
1237 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001238 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001239 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001240 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1241 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001242 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001243 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001244 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001245 devserver.trigger_download(target, build_id, branch,
1246 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001247 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001248
1249
Dan Shie4e807b2015-12-10 09:04:03 -08001250 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001251 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001252 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001253
1254 Following are the steps used here to provision an android device:
1255 1. If build_local_path is not set, download the image zip file, e.g.,
1256 shamu-img-2284311.zip, unzip it.
1257 2. Run fastboot to install following artifacts:
1258 bootloader, radio, boot, system, vendor(only if exists)
1259
1260 Repair is not supported for Android devices yet.
1261
1262 @param build_url: The url to use for downloading Android artifacts.
1263 pattern: http://$devserver:###/static/$build
1264 @param build_local_path: The path to a local folder that contains the
1265 image files needed to provision the device. Note that the folder
1266 is in the machine running adb command, rather than the drone.
1267 @param wipe: If true, userdata will be wiped before flashing.
1268 @param flash_all: If True, all img files found in img_path will be
1269 flashed. Otherwise, only boot and system are flashed.
1270
1271 @raises AndroidInstallError if any error occurs.
1272 """
Dan Shia2872172015-10-31 01:16:51 -07001273 # If the build is not staged in local server yet, clean up the temp
1274 # folder used to store image files after the provision is completed.
1275 delete_build_folder = bool(not build_local_path)
1276
1277 try:
1278 # Download image files needed for provision to a local directory.
1279 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001280 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001281
1282 # Device needs to be in bootloader mode for flashing.
1283 self.ensure_bootloader_mode()
1284
1285 if wipe:
Dan Shi12a4f662016-05-10 14:49:42 -07001286 self._fastboot_run_with_retry('-w')
Dan Shia2872172015-10-31 01:16:51 -07001287
1288 # Get all *.img file in the build_local_path.
1289 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001290 image_files = self.teststation.run(
1291 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001292 images = dict([(os.path.basename(f), f) for f in image_files])
Dan Shi49d451f2016-04-19 09:25:01 -07001293 build_info = self.get_build_info_from_build_url(build_url)
1294 board = build_info['build_target']
1295 all_images = (
1296 android_utils.AndroidImageFiles.get_standalone_images(board)
1297 + android_utils.AndroidImageFiles.get_zipped_images(board))
1298
1299 # Sort images to be flashed, bootloader needs to be the first one.
1300 bootloader = android_utils.AndroidImageFiles.BOOTLOADER
1301 sorted_images = sorted(
1302 images.items(),
1303 key=lambda pair: 0 if pair[0] == bootloader else 1)
1304 for image, image_file in sorted_images:
1305 if image not in all_images:
Dan Shia2872172015-10-31 01:16:51 -07001306 continue
1307 logging.info('Flashing %s...', image_file)
Dan Shi12a4f662016-05-10 14:49:42 -07001308 self._fastboot_run_with_retry('-S 256M flash %s %s' %
1309 (image[:-4], image_file))
Dan Shi49d451f2016-04-19 09:25:01 -07001310 if image == android_utils.AndroidImageFiles.BOOTLOADER:
Dan Shia2872172015-10-31 01:16:51 -07001311 self.fastboot_run('reboot-bootloader')
1312 self.wait_up(command=FASTBOOT_CMD)
1313 except Exception as e:
1314 logging.error('Install Android build failed with error: %s', e)
1315 # Re-raise the exception with type of AndroidInstallError.
1316 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1317 finally:
1318 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001319 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001320 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1321 DEFAULT_WAIT_UP_TIME_SECONDS)
1322 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001323 logging.info('Successfully installed Android build staged at %s.',
1324 build_url)
1325
1326
Dan Shiab999722015-12-04 14:27:08 -08001327 def install_brillo(self, build_url, build_local_path=None):
1328 """Install the Brillo DUT.
1329
1330 Following are the steps used here to provision an android device:
1331 1. If build_local_path is not set, download the image zip file, e.g.,
1332 dragonboard-img-123456.zip, unzip it. And download the vendor
1333 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1334 unzip it to vendor folder.
1335 2. Run provision_device script to install OS images and vendor
1336 partitions.
1337
1338 @param build_url: The url to use for downloading Android artifacts.
1339 pattern: http://$devserver:###/static/$build
1340 @param build_local_path: The path to a local folder that contains the
1341 image files needed to provision the device. Note that the folder
1342 is in the machine running adb command, rather than the drone.
1343
1344 @raises AndroidInstallError if any error occurs.
1345 """
1346 # If the build is not staged in local server yet, clean up the temp
1347 # folder used to store image files after the provision is completed.
1348 delete_build_folder = bool(not build_local_path)
1349
Dan Shiab999722015-12-04 14:27:08 -08001350 try:
1351 # Download image files needed for provision to a local directory.
1352 if not build_local_path:
1353 build_local_path = self.stage_brillo_image_files(build_url)
1354
1355 # Device needs to be in bootloader mode for flashing.
1356 self.ensure_bootloader_mode()
1357
1358 # Run provision_device command to install image files and vendor
1359 # partitions.
1360 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1361 cmd = (BRILLO_PROVISION_CMD %
1362 {'os_image_dir': build_local_path,
1363 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001364 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001365 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001366 self.teststation.run(cmd)
1367 except Exception as e:
1368 logging.error('Install Brillo build failed with error: %s', e)
1369 # Re-raise the exception with type of AndroidInstallError.
1370 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1371 finally:
1372 if delete_build_folder:
1373 self.teststation.run('rm -rf %s' % build_local_path)
1374 self.ensure_adb_mode()
1375 logging.info('Successfully installed Android build staged at %s.',
1376 build_url)
1377
1378
Dan Shibe3636a2016-02-14 22:48:01 -08001379 @property
1380 def job_repo_url_attribute(self):
1381 """Get the host attribute name for job_repo_url, which should append the
1382 adb serial.
1383 """
1384 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1385
1386
Dan Shie4e807b2015-12-10 09:04:03 -08001387 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001388 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001389 """Install the DUT.
1390
1391 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001392 pattern: http://$devserver:###/static/$build. If build_url is
1393 set to None, the code may try _parser.options.image to do the
1394 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001395 @param build_local_path: The path to a local directory that contains the
1396 image files needed to provision the device.
1397 @param wipe: If true, userdata will be wiped before flashing.
1398 @param flash_all: If True, all img files found in img_path will be
1399 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001400
Dan Shibe3636a2016-02-14 22:48:01 -08001401 @returns A tuple of (image_name, host_attributes).
1402 image_name is the name of image installed, e.g.,
1403 git_mnc-release/shamu-userdebug/1234
1404 host_attributes is a dictionary of (attribute, value), which
1405 can be saved to afe_host_attributes table in database. This
1406 method returns a dictionary with a single entry of
1407 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1408 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001409 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001410 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001411 if not build_url and self._parser.options.image:
1412 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001413 self._parser.options.image, os_type=os_type)
1414 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001415 self.install_android(
1416 build_url=build_url, build_local_path=build_local_path,
1417 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001418 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001419 self.install_brillo(
1420 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001421 else:
1422 raise error.InstallError(
1423 'Installation of os type %s is not supported.' %
1424 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001425 return (build_url.split('static/')[-1],
1426 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001427
1428
1429 def list_files_glob(self, path_glob):
1430 """Get a list of files on the device given glob pattern path.
1431
1432 @param path_glob: The path glob that we want to return the list of
1433 files that match the glob. Relative paths will not work as
1434 expected. Supply an absolute path to get the list of files
1435 you're hoping for.
1436
1437 @returns List of files that match the path_glob.
1438 """
1439 # This is just in case path_glob has no path separator.
1440 base_path = os.path.dirname(path_glob) or '.'
1441 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001442 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001443 if result.exit_status != 0:
1444 return []
1445 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001446
1447
Dan Shida995002016-04-25 23:12:58 -07001448 def install_apk(self, apk, force_reinstall=True):
Kevin Cheng31355942016-01-05 14:23:35 -08001449 """Install the specified apk.
1450
1451 This will install the apk and override it if it's already installed and
1452 will also allow for downgraded apks.
1453
1454 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001455 @param force_reinstall: True to reinstall the apk even if it's already
Dan Shida995002016-04-25 23:12:58 -07001456 installed. Default is set to True.
Dan Shidb0366c2016-02-19 10:36:18 -08001457
1458 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001459 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001460 client_utils.poll_for_condition(
1461 lambda: self.run('pm list packages',
1462 ignore_status=True).exit_status == 0,
1463 timeout=120)
Dan Shi043c45b2016-04-11 17:18:49 -07001464 client_utils.poll_for_condition(
1465 lambda: self.run('service list | grep mount',
1466 ignore_status=True).exit_status == 0,
1467 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001468 return self.adb_run('install %s -d %s' %
1469 ('-r' if force_reinstall else '', apk))
1470
1471
1472 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1473 def _confirm_apk_installed(self, package_name):
1474 """Confirm if apk is already installed with the given name.
1475
1476 `pm list packages` command is not reliable some time. The retry helps to
1477 reduce the chance of false negative.
1478
1479 @param package_name: Name of the package, e.g., com.android.phone.
1480
1481 @raise AutoservRunError: If the package is not found or pm list command
1482 failed for any reason.
1483 """
1484 name = 'package:%s' % package_name
1485 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1486
1487
1488 def is_apk_installed(self, package_name):
1489 """Check if apk is already installed with the given name.
1490
1491 @param package_name: Name of the package, e.g., com.android.phone.
1492
1493 @return: True if package is installed. False otherwise.
1494 """
1495 try:
1496 self._confirm_apk_installed(package_name)
1497 return True
1498 except:
1499 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001500
1501
1502 def get_attributes_to_clear_before_provision(self):
1503 """Get a list of attributes to be cleared before machine_install starts.
1504 """
1505 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001506
1507
1508 def get_labels(self):
1509 """Return a list of the labels gathered from the devices connected.
1510
1511 @return: A list of strings that denote the labels from all the devices
1512 connected.
1513 """
1514 return self.labels.get_labels(self)
1515
1516
1517 def update_labels(self):
1518 """Update the labels for this testbed."""
1519 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001520
1521
1522 def stage_server_side_package(self, image=None):
1523 """Stage autotest server-side package on devserver.
1524
1525 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1526
1527 @return: A url to the autotest server-side package. Return None if
1528 server-side package is not supported.
1529 @raise: error.AutoservError if fail to locate the build to test with.
1530 """
1531 if image:
1532 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1533 else:
1534 job_repo_url = afe_utils.get_host_attribute(
1535 self, self.job_repo_url_attribute)
1536 if job_repo_url:
1537 devserver_url, image = (
1538 tools.get_devserver_build_from_package_url(
1539 job_repo_url, True))
1540 ds = dev_server.AndroidBuildServer(devserver_url)
1541 else:
1542 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1543 if not labels:
1544 raise error.AutoservError(
1545 'Failed to stage server-side package. The host has '
1546 'no job_report_url attribute or version label.')
1547 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1548 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1549
1550 branch, target, build_id = utils.parse_launch_control_build(image)
1551 build_target, _ = utils.parse_launch_control_target(target)
1552
1553 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1554 # packaging is not supported.
1555 try:
1556 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1557 logging.warn('Build %s is older than %s. Server side packaging '
1558 'is disabled.', image,
1559 self.MIN_VERSION_SUPPORT_SSP)
1560 return None
1561 except ValueError:
1562 logging.warn('Failed to compare build id in %s with the minimum '
1563 'version that supports server side packaging. Server '
1564 'side packaging is disabled.', image)
1565 return None
1566
1567 ds.stage_artifacts(target, build_id, branch,
1568 artifacts=['autotest_server_package'])
1569 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1570 {'build_target': build_target,
1571 'build_id': build_id})
1572 return '%s/static/%s/%s' % (ds.url(), image,
1573 autotest_server_package_name)