blob: fd01a247b8069448f8fde69a6f2afb8faca42202 [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
Simran Basi431010f2013-09-04 10:42:41 -070015from autotest_lib.client.common_lib import error
Dan Shi6450e142016-03-11 11:52:20 -080016from autotest_lib.client.common_lib import global_config
Dan Shi225b9042015-11-18 10:25:21 -080017from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070018from autotest_lib.client.common_lib.cros import retry
Dan Shi6450e142016-03-11 11:52:20 -080019from autotest_lib.server import afe_utils
Dan Shi225b9042015-11-18 10:25:21 -080020from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070021from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080022from autotest_lib.server import utils
Simran Basi5ace6f22016-01-06 17:30:44 -080023from autotest_lib.server.cros import provision
Dan Shi6450e142016-03-11 11:52:20 -080024from autotest_lib.server.cros.dynamic_suite import tools
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070025from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070026from autotest_lib.server.hosts import abstract_ssh
Kevin Chengc6a645a2015-12-18 11:15:10 -080027from autotest_lib.server.hosts import adb_label
28from autotest_lib.server.hosts import base_label
Kevin Cheng85e864a2015-11-30 11:49:34 -080029from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070030
31
Dan Shi6450e142016-03-11 11:52:20 -080032CONFIG = global_config.global_config
33
Dan Shi6ea3e1c2015-10-28 15:19:04 -070034ADB_CMD = 'adb'
35FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070036SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070037# Some devices have no serial, then `adb serial` has output such as:
38# (no serial number) device
39# ?????????? device
40DEVICE_NO_SERIAL_MSG = '(no serial number)'
41DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070042# Regex to find an adb device. Examples:
43# 0146B5580B01801B device
44# 018e0ecb20c97a62 device
45# 172.22.75.141:5555 device
Mike Frysinger5d7a7092016-02-23 15:14:42 -050046DEVICE_FINDER_REGEX = (r'^(?P<SERIAL>([\w-]+)|(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})|' +
Filipe Brandenburger34363392015-08-13 14:57:45 -070047 re.escape(DEVICE_NO_SERIAL_MSG) +
Mike Frysinger5d7a7092016-02-23 15:14:42 -050048 r')([:]5555)?[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070049CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
50CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
51 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070052RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070053BOARD_FILE = 'ro.product.device'
Simran Basi38f7ddf2015-09-18 12:25:03 -070054TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070055# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080056# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070057FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
58FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
59# List of the perm stats indexed by the order they are listed in the example
60# supplied above.
61FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
62 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
63 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070064
Dan Shi6ea3e1c2015-10-28 15:19:04 -070065# Default maximum number of seconds to wait for a device to be down.
66DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
67# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080068DEFAULT_WAIT_UP_TIME_SECONDS = 300
69# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080070WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070071
Dan Shia2872172015-10-31 01:16:51 -070072OS_TYPE_ANDROID = 'android'
73OS_TYPE_BRILLO = 'brillo'
74
Dan Shie234dea2016-01-20 17:15:17 -080075# Regex to parse build name to get the detailed build information.
Dan Shi6450e142016-03-11 11:52:20 -080076BUILD_REGEX = ('(?P<BRANCH>([^/]+))/(?P<BUILD_TARGET>([^/]+))-'
Dan Shie234dea2016-01-20 17:15:17 -080077 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))')
Dan Shia2872172015-10-31 01:16:51 -070078# Regex to parse devserver url to get the detailed build information. Sample
79# url: http://$devserver:8080/static/branch/target/build_id
Dan Shie234dea2016-01-20 17:15:17 -080080DEVSERVER_URL_REGEX = '.*/%s/*' % BUILD_REGEX
Dan Shia2872172015-10-31 01:16:51 -070081
Dan Shi6450e142016-03-11 11:52:20 -080082ANDROID_IMAGE_FILE_FMT = '%(build_target)s-img-%(build_id)s.zip'
Dan Shia2872172015-10-31 01:16:51 -070083ANDROID_BOOTLOADER = 'bootloader.img'
84ANDROID_RADIO = 'radio.img'
85ANDROID_BOOT = 'boot.img'
86ANDROID_SYSTEM = 'system.img'
87ANDROID_VENDOR = 'vendor.img'
Dan Shiab999722015-12-04 14:27:08 -080088BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
Dan Shi6450e142016-03-11 11:52:20 -080089 '%(build_target)s-vendor_partitions-%(build_id)s.zip')
90AUTOTEST_SERVER_PACKAGE_FILE_FMT = (
91 '%(build_target)s-autotest_server_package-%(build_id)s.tar.bz2')
Simran Basi9228a6f2016-03-29 12:03:37 -070092ADB_DEVICE_PREFIXES = ['product:', 'model:', 'device:']
Dan Shia2872172015-10-31 01:16:51 -070093
94# Image files not inside the image zip file. These files should be downloaded
95# directly from devserver.
96ANDROID_STANDALONE_IMAGES = [ANDROID_BOOTLOADER, ANDROID_RADIO]
97# Image files that are packaged in a zip file, e.g., shamu-img-123456.zip
98ANDROID_ZIPPED_IMAGES = [ANDROID_BOOT, ANDROID_SYSTEM, ANDROID_VENDOR]
99# All image files to be flashed to an Android device.
100ANDROID_IMAGES = ANDROID_STANDALONE_IMAGES + ANDROID_ZIPPED_IMAGES
101
Simran Basi9c5d3982016-04-01 18:49:44 -0700102# Map of product names to build target name.
103PRODUCT_TARGET_MAP = {'dragon' : 'ryu',
104 'flo' : 'razor',
105 'flo_lte' : 'razorg',
106 'gm4g_sprout' : 'seed_l8150',
107 'flounder' : 'volantis',
108 'flounder_lte' : 'volantisg'}
109
Dan Shiab999722015-12-04 14:27:08 -0800110# Command to provision a Brillo device.
111# os_image_dir: The full path of the directory that contains all the Android image
112# files (from the image zip file).
113# vendor_partition_dir: The full path of the directory that contains all the
114# Brillo vendor partitions, and provision-device script.
115BRILLO_PROVISION_CMD = (
Simran Basi7e52c622016-01-05 15:43:51 -0800116 'sudo ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
Dan Shiab999722015-12-04 14:27:08 -0800117 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
118 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -0700119
120class AndroidInstallError(error.InstallError):
121 """Generic error for Android installation related exceptions."""
122
123
Simran Basi724b8a52013-09-30 11:19:31 -0700124class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700125 """This class represents a host running an ADB server."""
126
Simran Basi5ace6f22016-01-06 17:30:44 -0800127 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700128 _LABEL_FUNCTIONS = []
129 _DETECTABLE_LABELS = []
130 label_decorator = functools.partial(utils.add_label_detector,
131 _LABEL_FUNCTIONS,
132 _DETECTABLE_LABELS)
133
Dan Shi225b9042015-11-18 10:25:21 -0800134 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700135
Dan Shi6450e142016-03-11 11:52:20 -0800136 # Minimum build id that supports server side packaging. Older builds may
137 # not have server side package built or with Autotest code change to support
138 # server-side packaging.
139 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
140 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
141
beeps46dadc92013-11-07 14:07:10 -0800142 @staticmethod
143 def check_host(host, timeout=10):
144 """
145 Check if the given host is an adb host.
146
Simran Basi14622bb2015-11-25 13:23:40 -0800147 If SSH connectivity can't be established, check_host will try to use
148 user 'adb' as well. If SSH connectivity still can't be established
149 then the original SSH user is restored.
150
beeps46dadc92013-11-07 14:07:10 -0800151 @param host: An ssh host representing a device.
152 @param timeout: The timeout for the run command.
153
154
155 @return: True if the host device has adb.
156
157 @raises AutoservRunError: If the command failed.
158 @raises AutoservSSHTimeout: Ssh connection has timed out.
159 """
Dan Shi64e130f2015-12-16 14:45:44 -0800160 # host object may not have user attribute if it's a LocalHost object.
161 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800162 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800163 if not (host.hostname == 'localhost' or
164 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700165 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700166 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700167 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700168 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800169 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800170 if current_user is not None:
171 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800172 return False
173 return result.exit_status == 0
174
175
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700176 # TODO(garnold) Remove the 'serials' argument once all clients are made to
177 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700178 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700179 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700180 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700181 """Initialize an ADB Host.
182
183 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700184 test station connected to an Android DUT. This will be the DUT
185 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700186 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700187
188 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700189 @param serials: DEPRECATED (to be removed)
190 @param adb_serial: An ADB device serial. If None, assume a single
191 device is attached (and fail otherwise).
192 @param fastboot_serial: A fastboot device serial. If None, defaults to
193 the ADB serial (or assumes a single device if
194 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800195 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700196 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800197 # Sets up the is_client_install_supported field.
198 super(ADBHost, self)._initialize(hostname=hostname,
199 is_client_install_supported=False,
200 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800201
Kevin Chengd19e6c62015-10-28 16:39:39 -0700202 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800203 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi1bf60eb2015-12-01 16:39:29 -0800204 # TODO (sbasi/kevcheng): Once the teststation host is committed,
205 # refactor the serial retrieval.
206 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800207 self.adb_serial = adb_serial
208 self.fastboot_serial = fastboot_serial or adb_serial
Kevin Cheng85e864a2015-11-30 11:49:34 -0800209 self.teststation = (teststation if teststation
210 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700211
212 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800213 if self.adb_serial:
214 msg += ', ADB serial: %s' % self.adb_serial
215 if self.fastboot_serial:
216 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700217 logging.debug(msg)
218
Simran Basi9228a6f2016-03-29 12:03:37 -0700219 adb_prefix = any(adb_serial.startswith(p) for p in ADB_DEVICE_PREFIXES)
220 self._use_tcpip = ':' in adb_serial and not adb_prefix
Simran Basibeb2bb22016-02-03 15:25:48 -0800221 # Try resetting the ADB daemon on the device, however if we are
222 # creating the host to do a repair job, the device maybe inaccesible
223 # via ADB.
224 try:
225 self._reset_adbd_connection()
226 except (error.AutotestHostRunError, error.AutoservRunError) as e:
227 logging.error('Unable to reset the device adb daemon connection: '
228 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800229 self._os_type = None
230
Simran Basi431010f2013-09-04 10:42:41 -0700231
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700232 def _connect_over_tcpip_as_needed(self):
233 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700234 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700235 return
236 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700237 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700238
239
Roshan Pius4d7540c2015-12-16 13:30:32 -0800240 def _restart_adbd_with_root_permissions(self):
241 """Restarts the adb daemon with root permissions."""
242 self.adb_run('root')
243 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
244 time.sleep(1)
245 self.adb_run('wait-for-device')
246
247
Simran Basi9228a6f2016-03-29 12:03:37 -0700248 def _set_tcp_port(self):
249 """Ensure the device remains in tcp/ip mode after a reboot."""
250 if not self._use_tcpip:
251 return
252 port = self.adb_serial.split(':')[-1]
253 self.run('setprop persist.adb.tcp.port %s' % port)
254
255
Roshan Pius4d7540c2015-12-16 13:30:32 -0800256 def _reset_adbd_connection(self):
257 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800258 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700259 self._restart_adbd_with_root_permissions()
260 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800261
262
Kevin Cheng85e864a2015-11-30 11:49:34 -0800263 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800264 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700265 """Runs an adb command.
266
Kevin Chengd19e6c62015-10-28 16:39:39 -0700267 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700268
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700269 Refer to _device_run method for docstring for parameters.
270 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800271 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700272
273
Kevin Cheng85e864a2015-11-30 11:49:34 -0800274 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800275 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700276 """Runs an fastboot command.
277
Kevin Chengd19e6c62015-10-28 16:39:39 -0700278 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700279
280 Refer to _device_run method for docstring for parameters.
281 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800282 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700283
284
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700285 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700286 timeout=3600, ignore_status=False, ignore_timeout=False,
287 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
288 connect_timeout=30, options='', stdin=None, verbose=True,
289 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700290 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700291
Kevin Chengd19e6c62015-10-28 16:39:39 -0700292 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700293
Simran Basi431010f2013-09-04 10:42:41 -0700294 @param command: Command to run.
295 @param shell: If true the command runs in the adb shell otherwise if
296 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700297 reboot with shell=False will call 'adb reboot'. This
298 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700299 @param timeout: Time limit in seconds before attempting to
300 kill the running process. The run() function
301 will take a few seconds longer than 'timeout'
302 to complete if it has to kill the process.
303 @param ignore_status: Do not raise an exception, no matter
304 what the exit code of the command is.
305 @param ignore_timeout: Bool True if command timeouts should be
306 ignored. Will return None on command timeout.
307 @param stdout: Redirect stdout.
308 @param stderr: Redirect stderr.
309 @param connect_timeout: Connection timeout (in seconds)
310 @param options: String with additional ssh command options
311 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700312 @param require_sudo: True to require sudo to run the command. Default is
313 False.
Simran Basi431010f2013-09-04 10:42:41 -0700314 @param args: Sequence of strings to pass as arguments to command by
315 quoting them in " and escaping their contents if
316 necessary.
317
318 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700319 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700320 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800321 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700322 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800323 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700324 else:
325 raise NotImplementedError('Mode %s is not supported' % function)
326
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700327 if function != ADB_CMD and shell:
328 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700329
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700330 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700331
332 if serial:
333 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700334
Simran Basi431010f2013-09-04 10:42:41 -0700335 if shell:
336 cmd += '%s ' % SHELL_CMD
337 cmd += command
338
Roshan Pius58e5dd32015-10-16 15:16:42 -0700339 if verbose:
340 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700341
Kevin Cheng85e864a2015-11-30 11:49:34 -0800342 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400343 ignore_status=ignore_status,
344 ignore_timeout=ignore_timeout, stdout_tee=stdout,
345 stderr_tee=stderr, options=options, stdin=stdin,
346 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700347
348
Dan Shie234dea2016-01-20 17:15:17 -0800349 def get_board_name(self):
350 """Get the name of the board, e.g., shamu, dragonboard etc.
351 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700352 product = self.run_output('getprop %s' % BOARD_FILE)
353 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800354
355
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700356 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700357 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700358 """Determine the correct board label for the device.
359
360 @returns a string representing this device's board.
361 """
Dan Shie234dea2016-01-20 17:15:17 -0800362 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700363 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800364 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700365
366
Christopher Wiley08849d52013-11-22 08:57:58 -0800367 def job_start(self):
368 """
369 Disable log collection on adb_hosts.
370
371 TODO(sbasi): crbug.com/305427
Christopher Wiley08849d52013-11-22 08:57:58 -0800372 """
373
374
Simran Basi431010f2013-09-04 10:42:41 -0700375 def run(self, command, timeout=3600, ignore_status=False,
376 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
377 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700378 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700379 """Run a command on the adb device.
380
381 The command given will be ran directly on the adb device; for example
382 'ls' will be ran as: 'abd shell ls'
383
384 @param command: The command line string.
385 @param timeout: Time limit in seconds before attempting to
386 kill the running process. The run() function
387 will take a few seconds longer than 'timeout'
388 to complete if it has to kill the process.
389 @param ignore_status: Do not raise an exception, no matter
390 what the exit code of the command is.
391 @param ignore_timeout: Bool True if command timeouts should be
392 ignored. Will return None on command timeout.
393 @param stdout_tee: Redirect stdout.
394 @param stderr_tee: Redirect stderr.
395 @param connect_timeout: Connection timeout (in seconds).
396 @param options: String with additional ssh command options.
397 @param stdin: Stdin to pass (a string) to the executed command
398 @param args: Sequence of strings to pass as arguments to command by
399 quoting them in " and escaping their contents if
400 necessary.
401
402 @returns A CMDResult object or None if the call timed out and
403 ignore_timeout is True.
404
405 @raises AutoservRunError: If the command failed.
406 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700407 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700408 command = ('"%s; echo %s:\$?"' %
409 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700410 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700411 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700412 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
413 stdout=stdout_tee, stderr=stderr_tee,
414 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700415 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700416 if not result:
417 # In case of timeouts.
418 return None
419
420 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700421 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700422 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700423 'Failed to parse the exit code for command: %s' %
424 command, result)
425 elif parse_output:
426 result.stdout = parse_output.group('OUTPUT')
427 result.exit_status = int(parse_output.group('EXIT_CODE'))
428 if result.exit_status != 0 and not ignore_status:
429 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700430 return result
431
432
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700433 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
434 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700435
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700436 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700437
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700438 @param timeout: Time limit in seconds before returning even if the host
439 is not up.
440 @param command: The command used to test if a device is up, i.e.,
441 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700442
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700443 @returns True if the host was found to be up before the timeout expires,
444 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700445 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700446 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
447 delay_sec=1)
448 def _wait_up():
449 if not self.is_up(command=command):
450 raise error.TimeoutException('Device is still down.')
451 return True
452
453 try:
454 _wait_up()
455 logging.debug('Host %s is now up, and can be accessed by %s.',
456 self.hostname, command)
457 return True
458 except error.TimeoutException:
459 logging.debug('Host %s is still down after waiting %d seconds',
460 self.hostname, timeout)
461 return False
Simran Basi431010f2013-09-04 10:42:41 -0700462
463
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700464 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
465 warning_timer=None, old_boot_id=None, command=ADB_CMD):
466 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700467
468 Overrides wait_down from AbstractSSHHost.
469
470 @param timeout: Time in seconds to wait for the host to go down.
471 @param warning_timer: Time limit in seconds that will generate
472 a warning if the host is not down yet.
473 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700474 @param old_boot_id: Not applicable for adb_host.
475 @param command: `adb`, test if the device can be accessed by adb
476 command, or `fastboot`, test if the device can be accessed by
477 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700478
479 @returns True if the device goes down before the timeout, False
480 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700481 """
482 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
483 delay_sec=1)
484 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700485 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700486 raise error.TimeoutException('Device is still up.')
487 return True
488
489 try:
490 _wait_down()
491 logging.debug('Host %s is now down', self.hostname)
492 return True
493 except error.TimeoutException:
494 logging.debug('Host %s is still up after waiting %d seconds',
495 self.hostname, timeout)
496 return False
497
498
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700499 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700500 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700501
502 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700503 """
504 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700505 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700506 self.adb_run('reboot', timeout=10, ignore_timeout=True)
507 if not self.wait_down():
508 raise error.AutoservRebootError(
509 'ADB Device is still up after reboot')
510 if not self.wait_up():
511 raise error.AutoservRebootError(
512 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800513 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800514
515
Ralph Nathanb45eb672015-11-18 20:04:39 -0800516 def remount(self):
517 """Remounts paritions on the device read-write.
518
519 Specifically, the /system, /vendor (if present) and /oem (if present)
520 partitions on the device are remounted read-write.
521 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800522 self.adb_run('remount')
523
524
Kevin Cheng549beb42015-11-18 11:42:25 -0800525 @staticmethod
526 def parse_device_serials(devices_output):
527 """Return a list of parsed serials from the output.
528
529 @param devices_output: Output from either an adb or fastboot command.
530
531 @returns List of device serials
532 """
533 devices = []
534 for line in devices_output.splitlines():
535 match = re.search(DEVICE_FINDER_REGEX, line)
536 if match:
537 serial = match.group('SERIAL')
538 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
539 serial = DEVICE_NO_SERIAL_TAG
540 logging.debug('Found Device: %s', serial)
541 devices.append(serial)
542 return devices
543
544
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700545 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700546 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700547
548 @params use_adb: True to get adb accessible devices. Set to False to
549 get fastboot accessible devices.
550
Kevin Chengd19e6c62015-10-28 16:39:39 -0700551 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700552 """
553 if use_adb:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700554 result = self.adb_run('devices')
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700555 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700556 result = self.fastboot_run('devices')
Kevin Cheng549beb42015-11-18 11:42:25 -0800557 return self.parse_device_serials(result.stdout)
Simran Basi431010f2013-09-04 10:42:41 -0700558
559
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700560 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700561 """Get a list of devices currently attached to the test station and
562 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700563 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800564 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700565 raise error.AutoservError(
566 'Not given ADB serial but multiple devices detected')
567 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700568
569
570 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700571 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700572 accessible by fastboot command.
573 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700574 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800575 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700576 raise error.AutoservError(
577 'Not given fastboot serial but multiple devices detected')
578 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700579
580
581 def is_up(self, timeout=0, command=ADB_CMD):
582 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700583
584 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700585 @param command: `adb`, the device can be accessed by adb command,
586 or `fastboot`, the device can be accessed by fastboot command.
587 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700588
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700589 @returns True if the device is detectable by given command, False
590 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700591
592 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700593 if command == ADB_CMD:
594 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800595 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800596 # ADB has a device state, if the device is not online, no
597 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800598 # DUT with single device connected may not have adb_serial set.
599 # Therefore, skip checking if serial is in the list of adb devices
600 # if self.adb_serial is not set.
601 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800602 logging.debug('Waiting for device to enter the ready state.')
603 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700604 elif command == FASTBOOT_CMD:
605 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800606 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700607 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700608 raise NotImplementedError('Mode %s is not supported' % command)
609
610 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700611
612
613 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700614 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700615
616 Called as the test ends. Will return the device to USB mode and kill
617 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700618 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800619 # TODO(sbasi) Originally, we would kill the server after each test to
620 # reduce the opportunity for bad server state to hang around.
621 # Unfortunately, there is a period of time after each kill during which
622 # the Android device becomes unusable, and if we start the next test
623 # too quickly, we'll get an error complaining about no ADB device
624 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700625 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800626 # |close| the associated teststation as well.
627 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700628 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700629
630
631 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700632 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700633
634 @param message String message to log into syslog
635 @param tag String tag prefix for syslog
636
637 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700638 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700639
640
641 def get_autodir(self):
642 """Return the directory to install autotest for client side tests."""
643 return '/data/autotest'
644
Kevin Cheng018db352015-09-20 02:22:08 -0700645
Kris Rambishde8f9d12015-12-16 12:42:41 -0800646 def is_device_ready(self):
647 """Return the if the device is ready for ADB commands."""
648 dev_state = self.adb_run('get-state').stdout.strip()
649 logging.debug('Current device state: %s', dev_state)
650 return dev_state == 'device'
651
652
Kevin Chengd19e6c62015-10-28 16:39:39 -0700653 def verify_connectivity(self):
654 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800655 if not self.is_device_ready():
656 raise error.AutoservHostError('device state is not in the '
657 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700658
659
Simran Basid3ba3fb2015-09-11 14:35:07 -0700660 def verify_software(self):
661 """Verify working software on an adb_host.
662
Simran Basi38f7ddf2015-09-18 12:25:03 -0700663 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700664 """
Dan Shiab999722015-12-04 14:27:08 -0800665 # Check if adb and fastboot are present.
666 self.teststation.run('which adb')
667 self.teststation.run('which fastboot')
668 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700669
Kevin Cheng018db352015-09-20 02:22:08 -0700670
Simran Basid3ba3fb2015-09-11 14:35:07 -0700671 def verify_job_repo_url(self, tag=''):
672 """Make sure job_repo_url of this host is valid.
673
Simran Basi38f7ddf2015-09-18 12:25:03 -0700674 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700675
676 @param tag: The tag from the server job, in the format
677 <job_id>-<user>/<hostname>, or <hostless> for a server job.
678 """
679 return
Kevin Cheng018db352015-09-20 02:22:08 -0700680
681
Simran Basibeb2bb22016-02-03 15:25:48 -0800682 def repair(self):
683 """Attempt to get the DUT to pass `self.verify()`."""
684 try:
685 self.ensure_adb_mode(timeout=30)
686 return
687 except error.AutoservError as e:
688 logging.error(e)
689 logging.debug('Verifying the device is accessible via fastboot.')
690 self.ensure_bootloader_mode()
691 if not self.job.run_test(
692 'provision_AndroidUpdate', host=self, value=None,
693 force=True, repair=True):
694 raise error.AutoservRepairTotalFailure(
695 'Unable to repair the device.')
696
697
Simran Basi1b023762015-09-25 12:12:20 -0700698 def send_file(self, source, dest, delete_dest=False,
699 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700700 """Copy files from the drone to the device.
701
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400702 Just a note, there is the possibility the test station is localhost
703 which makes some of these steps redundant (e.g. creating tmp dir) but
704 that scenario will undoubtedly be a development scenario (test station
705 is also the moblab) and not the typical live test running scenario so
706 the redundancy I think is harmless.
707
Kevin Cheng018db352015-09-20 02:22:08 -0700708 @param source: The file/directory on the drone to send to the device.
709 @param dest: The destination path on the device to copy to.
710 @param delete_dest: A flag set to choose whether or not to delete
711 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700712 @param preserve_symlinks: Controls if symlinks on the source will be
713 copied as such on the destination or
714 transformed into the referenced
715 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700716 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700717 # If we need to preserve symlinks, let's check if the source is a
718 # symlink itself and if so, just create it on the device.
719 if preserve_symlinks:
720 symlink_target = None
721 try:
722 symlink_target = os.readlink(source)
723 except OSError:
724 # Guess it's not a symlink.
725 pass
726
727 if symlink_target is not None:
728 # Once we create the symlink, let's get out of here.
729 self.run('ln -s %s %s' % (symlink_target, dest))
730 return
731
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400732 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700733 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400734 src_path = os.path.join(tmp_dir, os.path.basename(dest))
735 # Now copy the file over to the test station so you can reference the
736 # file in the push command.
737 self.teststation.send_file(source, src_path,
738 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700739
740 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400741 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700742
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700743 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700744
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400745 # Cleanup the test station.
746 try:
747 self.teststation.run('rm -rf %s' % tmp_dir)
748 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
749 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700750
751
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700752 def _get_file_info(self, dest):
753 """Get permission and possible symlink info about file on the device.
754
755 These files are on the device so we only have shell commands (via adb)
756 to get the info we want. We'll use 'ls' to get it all.
757
758 @param dest: File to get info about.
759
760 @returns a dict of the file permissions and symlink.
761 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800762 # Grab file info.
763 file_info = self.run_output('ls -l %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700764 symlink = None
765 perms = 0
766 match = re.match(FILE_INFO_REGEX, file_info)
767 if match:
768 # Check if it's a symlink and grab the linked dest if it is.
769 if match.group('TYPE') == 'l':
770 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
771 if symlink_match:
772 symlink = symlink_match.group('SYMLINK')
773
774 # Set the perms.
775 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
776 if perm != '-':
777 perms |= perm_flag
778
779 return {'perms': perms,
780 'symlink': symlink}
781
782
Simran Basi1b023762015-09-25 12:12:20 -0700783 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
784 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700785 """Copy files from the device to the drone.
786
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400787 Just a note, there is the possibility the test station is localhost
788 which makes some of these steps redundant (e.g. creating tmp dir) but
789 that scenario will undoubtedly be a development scenario (test station
790 is also the moblab) and not the typical live test running scenario so
791 the redundancy I think is harmless.
792
Kevin Cheng018db352015-09-20 02:22:08 -0700793 @param source: The file/directory on the device to copy back to the
794 drone.
795 @param dest: The destination path on the drone to copy to.
796 @param delete_dest: A flag set to choose whether or not to delete
797 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700798 @param preserve_perm: Tells get_file() to try to preserve the sources
799 permissions on files and dirs.
800 @param preserve_symlinks: Try to preserve symlinks instead of
801 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700802 """
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400803 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700804 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400805 dest_path = os.path.join(tmp_dir, os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700806
807 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400808 self.teststation.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700809
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700810 source_info = {}
811 if preserve_symlinks or preserve_perm:
812 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700813
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700814 # If we want to preserve symlinks, just create it here, otherwise pull
815 # the file off the device.
816 if preserve_symlinks and source_info['symlink']:
817 os.symlink(source_info['symlink'], dest)
818 else:
Roshan Pius95567142015-11-03 09:56:08 -0800819 self.adb_run('pull %s %s' % (source, dest_path))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700820
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400821 # Copy over the file from the test station and clean up.
822 self.teststation.get_file(dest_path, dest)
823 try:
824 self.teststation.run('rm -rf %s' % tmp_dir)
825 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
826 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700827
828 if preserve_perm:
829 os.chmod(dest, source_info['perms'])
Kevin Cheng018db352015-09-20 02:22:08 -0700830
831
832 def get_release_version(self):
833 """Get the release version from the RELEASE_FILE on the device.
834
835 @returns The release string in the RELEASE_FILE.
836
837 """
838 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700839
840
841 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700842 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700843
Kevin Chengd19e6c62015-10-28 16:39:39 -0700844 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700845
846 @param parent: Parent directory of the returned tmp dir.
847
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700848 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700849 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700850 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
851 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700852 if not parent.startswith(TMP_DIR):
853 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700854 self.run('mkdir -p %s' % parent)
855 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
856 self.tmp_dirs.append(tmp_dir)
857 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700858
859
860 def get_platform(self):
861 """Determine the correct platform label for this host.
862
863 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700864 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700865
866 @returns a string representing this host's platform.
867 """
868 return 'adb'
869
870
Gilad Arnolda76bef02015-09-29 13:55:15 -0700871 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800872 """Get the OS type of the DUT, e.g., android or brillo.
873 """
874 if not self._os_type:
875 if self.run_output('getprop ro.product.brand') == 'Brillo':
876 self._os_type = OS_TYPE_BRILLO
877 else:
878 self._os_type = OS_TYPE_ANDROID
879
880 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700881
882
883 def _forward(self, reverse, args):
884 """Execute a forwarding command.
885
886 @param reverse: Whether this is reverse forwarding (Boolean).
887 @param args: List of command arguments.
888 """
889 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700890 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700891
892
893 def add_forwarding(self, src, dst, reverse=False, rebind=True):
894 """Forward a port between the ADB host and device.
895
896 Port specifications are any strings accepted as such by ADB, for
897 example 'tcp:8080'.
898
899 @param src: Port specification to forward from.
900 @param dst: Port specification to forward to.
901 @param reverse: Do reverse forwarding from device to host (Boolean).
902 @param rebind: Allow rebinding an already bound port (Boolean).
903 """
904 args = []
905 if not rebind:
906 args.append('--no-rebind')
907 args += [src, dst]
908 self._forward(reverse, args)
909
910
911 def remove_forwarding(self, src=None, reverse=False):
912 """Removes forwarding on port.
913
914 @param src: Port specification, or None to remove all forwarding.
915 @param reverse: Whether this is reverse forwarding (Boolean).
916 """
917 args = []
918 if src is None:
919 args.append('--remove-all')
920 else:
921 args += ['--remove', src]
922 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700923
924
xixuan6cf6d2f2016-01-29 15:29:00 -0800925 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700926 """
927 Forwards a port securely through a tunnel process from the server
928 to the DUT for RPC server connection.
929 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
930 to the DUT.
931
932 @param port: remote port on the DUT.
933 @param local_port: local forwarding port.
934
935 @return: the tunnel process.
936 """
937 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800938 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700939
940
xixuan6cf6d2f2016-01-29 15:29:00 -0800941 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700942 """
943 Disconnects a previously forwarded port from the server to the DUT for
944 RPC server connection.
945 Remove the previously added 'ADB forward' rule to forward the RPC
946 packets from the AdbHost to the DUT.
947
948 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -0800949 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -0700950 @param port: remote port on the DUT.
951
952 """
953 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800954 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700955
956
957 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700958 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700959
960 @raise: error.AutoservError if the device failed to reboot into
961 bootloader mode.
962 """
963 if self.is_up(command=FASTBOOT_CMD):
964 return
965 self.adb_run('reboot bootloader')
966 if not self.wait_up(command=FASTBOOT_CMD):
967 raise error.AutoservError(
968 'The device failed to reboot into bootloader mode.')
969
970
Dan Shie4e807b2015-12-10 09:04:03 -0800971 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700972 """Ensure the device is up and can be accessed by adb command.
973
Dan Shie4e807b2015-12-10 09:04:03 -0800974 @param timeout: Time limit in seconds before returning even if the host
975 is not up.
976
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700977 @raise: error.AutoservError if the device failed to reboot into
978 adb mode.
979 """
980 if self.is_up():
981 return
Dan Shi04980372016-03-22 10:57:47 -0700982 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
983 # check if the device is in adb mode.
984 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -0800985 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700986 raise error.AutoservError(
987 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800988 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -0700989
990
991 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -0800992 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -0700993 """Get the Android build information from the build url.
994
995 @param build_url: The url to use for downloading Android artifacts.
996 pattern: http://$devserver:###/static/branch/target/build_id
997
Dan Shi6450e142016-03-11 11:52:20 -0800998 @return: A dictionary of build information, including keys:
999 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001000 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001001 """
Dan Shiab999722015-12-04 14:27:08 -08001002 if not build_url:
1003 raise AndroidInstallError('Need build_url to download image files.')
1004
1005 try:
1006 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001007 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001008 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001009 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001010 match.group('BUILD_TYPE'))),
1011 'build_id': match.group('BUILD_ID')}
1012 except (AttributeError, IndexError, ValueError) as e:
1013 raise AndroidInstallError(
1014 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001015
1016
Dan Shia2872172015-10-31 01:16:51 -07001017 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001018 def download_file(self, build_url, file, dest_dir, unzip=False,
1019 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001020 """Download the given file from the build url.
1021
1022 @param build_url: The url to use for downloading Android artifacts.
1023 pattern: http://$devserver:###/static/branch/target/build_id
1024 @param file: Name of the file to be downloaded, e.g., boot.img.
1025 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001026 @param unzip: If True, unzip the downloaded file.
1027 @param unzip_dest: Location to unzip the downloaded file to. If not
1028 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001029 """
Dan Shidb0366c2016-02-19 10:36:18 -08001030 # Append the file name to the url if build_url is linked to the folder
1031 # containing the file.
1032 if not build_url.endswith('/%s' % file):
1033 src_url = os.path.join(build_url, file)
1034 else:
1035 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001036 dest_file = os.path.join(dest_dir, file)
1037 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001038 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001039 if unzip:
1040 unzip_dest = unzip_dest or dest_dir
1041 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1042 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001043 except:
1044 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001045 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001046 raise
1047
1048
Dan Shiab999722015-12-04 14:27:08 -08001049 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001050 """Download required image files from the given build_url to a local
1051 directory in the machine runs fastboot command.
1052
1053 @param build_url: The url to use for downloading Android artifacts.
1054 pattern: http://$devserver:###/static/branch/target/build_id
1055
1056 @return: Path to the directory contains image files.
1057 """
Dan Shi08ff1282016-02-18 19:51:16 -08001058 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001059
1060 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001061 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001062
1063 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001064 self.download_file(build_url, zipped_image_file, image_dir,
1065 unzip=True)
1066 for image_file in ANDROID_STANDALONE_IMAGES:
Dan Shidb0366c2016-02-19 10:36:18 -08001067 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001068
Dan Shia2872172015-10-31 01:16:51 -07001069 return image_dir
1070 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001071 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001072 raise
1073
1074
Dan Shiab999722015-12-04 14:27:08 -08001075 def stage_brillo_image_files(self, build_url):
1076 """Download required brillo image files from the given build_url to a
1077 local directory in the machine runs fastboot command.
1078
1079 @param build_url: The url to use for downloading Android artifacts.
1080 pattern: http://$devserver:###/static/branch/target/build_id
1081
1082 @return: Path to the directory contains image files.
1083 """
Dan Shi08ff1282016-02-18 19:51:16 -08001084 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001085
1086 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1087 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1088 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001089
1090 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001091 self.download_file(build_url, zipped_image_file, image_dir,
1092 unzip=True)
1093 self.download_file(build_url, vendor_partitions_file, image_dir,
1094 unzip=True,
1095 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001096 return image_dir
1097 except:
1098 self.teststation.run('rm -rf %s' % image_dir)
1099 raise
1100
1101
Simran Basibeb2bb22016-02-03 15:25:48 -08001102 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001103 """Stage a build on a devserver and return the build_url and devserver.
1104
1105 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001106
Dan Shi225b9042015-11-18 10:25:21 -08001107 @returns a tuple with an update URL like:
1108 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1109 and the devserver instance.
1110 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001111 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001112 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001113 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1114 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001115 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001116 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001117 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001118 devserver.trigger_download(target, build_id, branch,
1119 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001120 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001121
1122
Dan Shie4e807b2015-12-10 09:04:03 -08001123 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001124 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001125 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001126
1127 Following are the steps used here to provision an android device:
1128 1. If build_local_path is not set, download the image zip file, e.g.,
1129 shamu-img-2284311.zip, unzip it.
1130 2. Run fastboot to install following artifacts:
1131 bootloader, radio, boot, system, vendor(only if exists)
1132
1133 Repair is not supported for Android devices yet.
1134
1135 @param build_url: The url to use for downloading Android artifacts.
1136 pattern: http://$devserver:###/static/$build
1137 @param build_local_path: The path to a local folder that contains the
1138 image files needed to provision the device. Note that the folder
1139 is in the machine running adb command, rather than the drone.
1140 @param wipe: If true, userdata will be wiped before flashing.
1141 @param flash_all: If True, all img files found in img_path will be
1142 flashed. Otherwise, only boot and system are flashed.
1143
1144 @raises AndroidInstallError if any error occurs.
1145 """
Dan Shia2872172015-10-31 01:16:51 -07001146 # If the build is not staged in local server yet, clean up the temp
1147 # folder used to store image files after the provision is completed.
1148 delete_build_folder = bool(not build_local_path)
1149
1150 try:
1151 # Download image files needed for provision to a local directory.
1152 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001153 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001154
1155 # Device needs to be in bootloader mode for flashing.
1156 self.ensure_bootloader_mode()
1157
1158 if wipe:
Dan Shie4e807b2015-12-10 09:04:03 -08001159 self.fastboot_run('-w')
Dan Shia2872172015-10-31 01:16:51 -07001160
1161 # Get all *.img file in the build_local_path.
1162 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001163 image_files = self.teststation.run(
1164 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001165 images = dict([(os.path.basename(f), f) for f in image_files])
1166 for image, image_file in images.items():
1167 if image not in ANDROID_IMAGES:
1168 continue
1169 logging.info('Flashing %s...', image_file)
Dan Shi70c30192016-03-22 23:14:12 -07001170 self.fastboot_run('-S 256M flash %s %s' %
Dan Shie9913d32016-03-09 14:17:26 -08001171 (image[:-4], image_file))
Dan Shia2872172015-10-31 01:16:51 -07001172 if image == ANDROID_BOOTLOADER:
1173 self.fastboot_run('reboot-bootloader')
1174 self.wait_up(command=FASTBOOT_CMD)
1175 except Exception as e:
1176 logging.error('Install Android build failed with error: %s', e)
1177 # Re-raise the exception with type of AndroidInstallError.
1178 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1179 finally:
1180 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001181 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001182 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1183 DEFAULT_WAIT_UP_TIME_SECONDS)
1184 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001185 logging.info('Successfully installed Android build staged at %s.',
1186 build_url)
1187
1188
Dan Shiab999722015-12-04 14:27:08 -08001189 def install_brillo(self, build_url, build_local_path=None):
1190 """Install the Brillo DUT.
1191
1192 Following are the steps used here to provision an android device:
1193 1. If build_local_path is not set, download the image zip file, e.g.,
1194 dragonboard-img-123456.zip, unzip it. And download the vendor
1195 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1196 unzip it to vendor folder.
1197 2. Run provision_device script to install OS images and vendor
1198 partitions.
1199
1200 @param build_url: The url to use for downloading Android artifacts.
1201 pattern: http://$devserver:###/static/$build
1202 @param build_local_path: The path to a local folder that contains the
1203 image files needed to provision the device. Note that the folder
1204 is in the machine running adb command, rather than the drone.
1205
1206 @raises AndroidInstallError if any error occurs.
1207 """
1208 # If the build is not staged in local server yet, clean up the temp
1209 # folder used to store image files after the provision is completed.
1210 delete_build_folder = bool(not build_local_path)
1211
Dan Shiab999722015-12-04 14:27:08 -08001212 try:
1213 # Download image files needed for provision to a local directory.
1214 if not build_local_path:
1215 build_local_path = self.stage_brillo_image_files(build_url)
1216
1217 # Device needs to be in bootloader mode for flashing.
1218 self.ensure_bootloader_mode()
1219
1220 # Run provision_device command to install image files and vendor
1221 # partitions.
1222 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1223 cmd = (BRILLO_PROVISION_CMD %
1224 {'os_image_dir': build_local_path,
1225 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001226 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001227 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001228 self.teststation.run(cmd)
1229 except Exception as e:
1230 logging.error('Install Brillo build failed with error: %s', e)
1231 # Re-raise the exception with type of AndroidInstallError.
1232 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1233 finally:
1234 if delete_build_folder:
1235 self.teststation.run('rm -rf %s' % build_local_path)
1236 self.ensure_adb_mode()
1237 logging.info('Successfully installed Android build staged at %s.',
1238 build_url)
1239
1240
Dan Shibe3636a2016-02-14 22:48:01 -08001241 @property
1242 def job_repo_url_attribute(self):
1243 """Get the host attribute name for job_repo_url, which should append the
1244 adb serial.
1245 """
1246 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1247
1248
Dan Shie4e807b2015-12-10 09:04:03 -08001249 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001250 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001251 """Install the DUT.
1252
1253 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001254 pattern: http://$devserver:###/static/$build. If build_url is
1255 set to None, the code may try _parser.options.image to do the
1256 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001257 @param build_local_path: The path to a local directory that contains the
1258 image files needed to provision the device.
1259 @param wipe: If true, userdata will be wiped before flashing.
1260 @param flash_all: If True, all img files found in img_path will be
1261 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001262
Dan Shibe3636a2016-02-14 22:48:01 -08001263 @returns A tuple of (image_name, host_attributes).
1264 image_name is the name of image installed, e.g.,
1265 git_mnc-release/shamu-userdebug/1234
1266 host_attributes is a dictionary of (attribute, value), which
1267 can be saved to afe_host_attributes table in database. This
1268 method returns a dictionary with a single entry of
1269 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1270 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001271 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001272 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001273 if not build_url and self._parser.options.image:
1274 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001275 self._parser.options.image, os_type=os_type)
1276 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001277 self.install_android(
1278 build_url=build_url, build_local_path=build_local_path,
1279 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001280 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001281 self.install_brillo(
1282 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001283 else:
1284 raise error.InstallError(
1285 'Installation of os type %s is not supported.' %
1286 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001287 return (build_url.split('static/')[-1],
1288 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001289
1290
1291 def list_files_glob(self, path_glob):
1292 """Get a list of files on the device given glob pattern path.
1293
1294 @param path_glob: The path glob that we want to return the list of
1295 files that match the glob. Relative paths will not work as
1296 expected. Supply an absolute path to get the list of files
1297 you're hoping for.
1298
1299 @returns List of files that match the path_glob.
1300 """
1301 # This is just in case path_glob has no path separator.
1302 base_path = os.path.dirname(path_glob) or '.'
1303 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001304 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001305 if result.exit_status != 0:
1306 return []
1307 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001308
1309
Dan Shidb0366c2016-02-19 10:36:18 -08001310 def install_apk(self, apk, force_reinstall=False):
Kevin Cheng31355942016-01-05 14:23:35 -08001311 """Install the specified apk.
1312
1313 This will install the apk and override it if it's already installed and
1314 will also allow for downgraded apks.
1315
1316 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001317 @param force_reinstall: True to reinstall the apk even if it's already
1318 installed. Default is set to False.
1319
1320 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001321 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001322 client_utils.poll_for_condition(
1323 lambda: self.run('pm list packages',
1324 ignore_status=True).exit_status == 0,
1325 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001326 return self.adb_run('install %s -d %s' %
1327 ('-r' if force_reinstall else '', apk))
1328
1329
1330 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1331 def _confirm_apk_installed(self, package_name):
1332 """Confirm if apk is already installed with the given name.
1333
1334 `pm list packages` command is not reliable some time. The retry helps to
1335 reduce the chance of false negative.
1336
1337 @param package_name: Name of the package, e.g., com.android.phone.
1338
1339 @raise AutoservRunError: If the package is not found or pm list command
1340 failed for any reason.
1341 """
1342 name = 'package:%s' % package_name
1343 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1344
1345
1346 def is_apk_installed(self, package_name):
1347 """Check if apk is already installed with the given name.
1348
1349 @param package_name: Name of the package, e.g., com.android.phone.
1350
1351 @return: True if package is installed. False otherwise.
1352 """
1353 try:
1354 self._confirm_apk_installed(package_name)
1355 return True
1356 except:
1357 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001358
1359
1360 def get_attributes_to_clear_before_provision(self):
1361 """Get a list of attributes to be cleared before machine_install starts.
1362 """
1363 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001364
1365
1366 def get_labels(self):
1367 """Return a list of the labels gathered from the devices connected.
1368
1369 @return: A list of strings that denote the labels from all the devices
1370 connected.
1371 """
1372 return self.labels.get_labels(self)
1373
1374
1375 def update_labels(self):
1376 """Update the labels for this testbed."""
1377 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001378
1379
1380 def stage_server_side_package(self, image=None):
1381 """Stage autotest server-side package on devserver.
1382
1383 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1384
1385 @return: A url to the autotest server-side package. Return None if
1386 server-side package is not supported.
1387 @raise: error.AutoservError if fail to locate the build to test with.
1388 """
1389 if image:
1390 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1391 else:
1392 job_repo_url = afe_utils.get_host_attribute(
1393 self, self.job_repo_url_attribute)
1394 if job_repo_url:
1395 devserver_url, image = (
1396 tools.get_devserver_build_from_package_url(
1397 job_repo_url, True))
1398 ds = dev_server.AndroidBuildServer(devserver_url)
1399 else:
1400 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1401 if not labels:
1402 raise error.AutoservError(
1403 'Failed to stage server-side package. The host has '
1404 'no job_report_url attribute or version label.')
1405 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1406 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1407
1408 branch, target, build_id = utils.parse_launch_control_build(image)
1409 build_target, _ = utils.parse_launch_control_target(target)
1410
1411 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1412 # packaging is not supported.
1413 try:
1414 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1415 logging.warn('Build %s is older than %s. Server side packaging '
1416 'is disabled.', image,
1417 self.MIN_VERSION_SUPPORT_SSP)
1418 return None
1419 except ValueError:
1420 logging.warn('Failed to compare build id in %s with the minimum '
1421 'version that supports server side packaging. Server '
1422 'side packaging is disabled.', image)
1423 return None
1424
1425 ds.stage_artifacts(target, build_id, branch,
1426 artifacts=['autotest_server_package'])
1427 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1428 {'build_target': build_target,
1429 'build_id': build_id})
1430 return '%s/static/%s/%s' % (ds.url(), image,
1431 autotest_server_package_name)