blob: 6b1fffcac757c043aee599d6b5553b849aff07e5 [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
14from autotest_lib.client.common_lib import error
Dan Shi6450e142016-03-11 11:52:20 -080015from autotest_lib.client.common_lib import global_config
Dan Shi225b9042015-11-18 10:25:21 -080016from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070017from autotest_lib.client.common_lib.cros import retry
Dan Shi6450e142016-03-11 11:52:20 -080018from autotest_lib.server import afe_utils
Dan Shi225b9042015-11-18 10:25:21 -080019from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070020from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080021from autotest_lib.server import utils
Simran Basi5ace6f22016-01-06 17:30:44 -080022from autotest_lib.server.cros import provision
Dan Shi6450e142016-03-11 11:52:20 -080023from autotest_lib.server.cros.dynamic_suite import tools
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070024from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070025from autotest_lib.server.hosts import abstract_ssh
Kevin Chengc6a645a2015-12-18 11:15:10 -080026from autotest_lib.server.hosts import adb_label
27from autotest_lib.server.hosts import base_label
Kevin Cheng85e864a2015-11-30 11:49:34 -080028from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070029
30
Dan Shi6450e142016-03-11 11:52:20 -080031CONFIG = global_config.global_config
32
Dan Shi6ea3e1c2015-10-28 15:19:04 -070033ADB_CMD = 'adb'
34FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070035SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070036# Some devices have no serial, then `adb serial` has output such as:
37# (no serial number) device
38# ?????????? device
39DEVICE_NO_SERIAL_MSG = '(no serial number)'
40DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070041# Regex to find an adb device. Examples:
42# 0146B5580B01801B device
43# 018e0ecb20c97a62 device
44# 172.22.75.141:5555 device
Mike Frysinger5d7a7092016-02-23 15:14:42 -050045DEVICE_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 -070046 re.escape(DEVICE_NO_SERIAL_MSG) +
Mike Frysinger5d7a7092016-02-23 15:14:42 -050047 r')([:]5555)?[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070048CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
49CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
50 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070051RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070052BOARD_FILE = 'ro.product.device'
Simran Basi38f7ddf2015-09-18 12:25:03 -070053TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070054# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080055# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070056FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
57FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
58# List of the perm stats indexed by the order they are listed in the example
59# supplied above.
60FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
61 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
62 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070063
Dan Shi6ea3e1c2015-10-28 15:19:04 -070064# Default maximum number of seconds to wait for a device to be down.
65DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
66# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080067DEFAULT_WAIT_UP_TIME_SECONDS = 300
68# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080069WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070070
Dan Shia2872172015-10-31 01:16:51 -070071OS_TYPE_ANDROID = 'android'
72OS_TYPE_BRILLO = 'brillo'
73
Dan Shie234dea2016-01-20 17:15:17 -080074# Regex to parse build name to get the detailed build information.
Dan Shi6450e142016-03-11 11:52:20 -080075BUILD_REGEX = ('(?P<BRANCH>([^/]+))/(?P<BUILD_TARGET>([^/]+))-'
Dan Shie234dea2016-01-20 17:15:17 -080076 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))')
Dan Shia2872172015-10-31 01:16:51 -070077# Regex to parse devserver url to get the detailed build information. Sample
78# url: http://$devserver:8080/static/branch/target/build_id
Dan Shie234dea2016-01-20 17:15:17 -080079DEVSERVER_URL_REGEX = '.*/%s/*' % BUILD_REGEX
Dan Shia2872172015-10-31 01:16:51 -070080
Dan Shi6450e142016-03-11 11:52:20 -080081ANDROID_IMAGE_FILE_FMT = '%(build_target)s-img-%(build_id)s.zip'
Dan Shia2872172015-10-31 01:16:51 -070082ANDROID_BOOTLOADER = 'bootloader.img'
83ANDROID_RADIO = 'radio.img'
84ANDROID_BOOT = 'boot.img'
85ANDROID_SYSTEM = 'system.img'
86ANDROID_VENDOR = 'vendor.img'
Dan Shiab999722015-12-04 14:27:08 -080087BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
Dan Shi6450e142016-03-11 11:52:20 -080088 '%(build_target)s-vendor_partitions-%(build_id)s.zip')
89AUTOTEST_SERVER_PACKAGE_FILE_FMT = (
90 '%(build_target)s-autotest_server_package-%(build_id)s.tar.bz2')
Dan Shia2872172015-10-31 01:16:51 -070091
92# Image files not inside the image zip file. These files should be downloaded
93# directly from devserver.
94ANDROID_STANDALONE_IMAGES = [ANDROID_BOOTLOADER, ANDROID_RADIO]
95# Image files that are packaged in a zip file, e.g., shamu-img-123456.zip
96ANDROID_ZIPPED_IMAGES = [ANDROID_BOOT, ANDROID_SYSTEM, ANDROID_VENDOR]
97# All image files to be flashed to an Android device.
98ANDROID_IMAGES = ANDROID_STANDALONE_IMAGES + ANDROID_ZIPPED_IMAGES
99
Dan Shiab999722015-12-04 14:27:08 -0800100# Command to provision a Brillo device.
101# os_image_dir: The full path of the directory that contains all the Android image
102# files (from the image zip file).
103# vendor_partition_dir: The full path of the directory that contains all the
104# Brillo vendor partitions, and provision-device script.
105BRILLO_PROVISION_CMD = (
Simran Basi7e52c622016-01-05 15:43:51 -0800106 'sudo ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
Dan Shiab999722015-12-04 14:27:08 -0800107 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
108 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -0700109
110class AndroidInstallError(error.InstallError):
111 """Generic error for Android installation related exceptions."""
112
113
Simran Basi724b8a52013-09-30 11:19:31 -0700114class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700115 """This class represents a host running an ADB server."""
116
Simran Basi5ace6f22016-01-06 17:30:44 -0800117 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700118 _LABEL_FUNCTIONS = []
119 _DETECTABLE_LABELS = []
120 label_decorator = functools.partial(utils.add_label_detector,
121 _LABEL_FUNCTIONS,
122 _DETECTABLE_LABELS)
123
Dan Shi225b9042015-11-18 10:25:21 -0800124 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700125
Dan Shi6450e142016-03-11 11:52:20 -0800126 # Minimum build id that supports server side packaging. Older builds may
127 # not have server side package built or with Autotest code change to support
128 # server-side packaging.
129 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
130 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
131
beeps46dadc92013-11-07 14:07:10 -0800132 @staticmethod
133 def check_host(host, timeout=10):
134 """
135 Check if the given host is an adb host.
136
Simran Basi14622bb2015-11-25 13:23:40 -0800137 If SSH connectivity can't be established, check_host will try to use
138 user 'adb' as well. If SSH connectivity still can't be established
139 then the original SSH user is restored.
140
beeps46dadc92013-11-07 14:07:10 -0800141 @param host: An ssh host representing a device.
142 @param timeout: The timeout for the run command.
143
144
145 @return: True if the host device has adb.
146
147 @raises AutoservRunError: If the command failed.
148 @raises AutoservSSHTimeout: Ssh connection has timed out.
149 """
Dan Shi64e130f2015-12-16 14:45:44 -0800150 # host object may not have user attribute if it's a LocalHost object.
151 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800152 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800153 if not (host.hostname == 'localhost' or
154 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700155 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700156 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700157 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700158 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800159 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800160 if current_user is not None:
161 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800162 return False
163 return result.exit_status == 0
164
165
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700166 # TODO(garnold) Remove the 'serials' argument once all clients are made to
167 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700168 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700169 adb_serial=None, fastboot_serial=None,
Kevin Cheng549beb42015-11-18 11:42:25 -0800170 device_hostname=None, teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700171 """Initialize an ADB Host.
172
173 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700174 test station connected to an Android DUT. This will be the DUT
175 to test with. If there are multiple, serial must be specified or an
176 exception will be raised. If device_hostname is supplied then all
177 ADB commands will run over TCP/IP.
Simran Basi431010f2013-09-04 10:42:41 -0700178
179 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700180 @param serials: DEPRECATED (to be removed)
181 @param adb_serial: An ADB device serial. If None, assume a single
182 device is attached (and fail otherwise).
183 @param fastboot_serial: A fastboot device serial. If None, defaults to
184 the ADB serial (or assumes a single device if
185 the latter is None).
Simran Basi431010f2013-09-04 10:42:41 -0700186 @param device_hostname: Hostname or IP of the android device we want to
187 interact with. If supplied all ADB interactions
188 run over TCP/IP.
Kevin Cheng549beb42015-11-18 11:42:25 -0800189 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700190 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800191 # Sets up the is_client_install_supported field.
192 super(ADBHost, self)._initialize(hostname=hostname,
193 is_client_install_supported=False,
194 *args, **dargs)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700195 if device_hostname and (adb_serial or fastboot_serial):
196 raise error.AutoservError(
197 'TCP/IP and USB modes are mutually exclusive')
198
Kevin Cheng85e864a2015-11-30 11:49:34 -0800199
Kevin Chengd19e6c62015-10-28 16:39:39 -0700200 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800201 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi431010f2013-09-04 10:42:41 -0700202 self._device_hostname = device_hostname
203 self._use_tcpip = False
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
213 if self._device_hostname:
214 msg += ', device hostname: %s' % self._device_hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800215 if self.adb_serial:
216 msg += ', ADB serial: %s' % self.adb_serial
217 if self.fastboot_serial:
218 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700219 logging.debug(msg)
220
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."""
234 if not self._device_hostname:
235 return
236 logging.debug('Connecting to device over TCP/IP')
Dan Shi50a412a2016-01-05 10:52:40 -0800237 if self._device_hostname == self.adb_serial:
Simran Basi431010f2013-09-04 10:42:41 -0700238 # We previously had a connection to this device, restart the ADB
239 # server.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700240 self.adb_run('kill-server')
Simran Basi431010f2013-09-04 10:42:41 -0700241 # Ensure that connection commands don't run over TCP/IP.
242 self._use_tcpip = False
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700243 self.adb_run('tcpip 5555', timeout=10, ignore_timeout=True)
Simran Basi431010f2013-09-04 10:42:41 -0700244 time.sleep(2)
245 try:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700246 self.adb_run('connect %s' % self._device_hostname)
Simran Basi431010f2013-09-04 10:42:41 -0700247 except (error.AutoservRunError, error.CmdError) as e:
248 raise error.AutoservError('Failed to connect via TCP/IP: %s' % e)
249 # Allow ADB a bit of time after connecting before interacting with the
250 # device.
251 time.sleep(5)
252 # Switch back to using TCP/IP.
253 self._use_tcpip = True
254
255
Roshan Pius4d7540c2015-12-16 13:30:32 -0800256 def _restart_adbd_with_root_permissions(self):
257 """Restarts the adb daemon with root permissions."""
258 self.adb_run('root')
259 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
260 time.sleep(1)
261 self.adb_run('wait-for-device')
262
263
264 def _reset_adbd_connection(self):
265 """Resets adbd connection to the device after a reboot/initialization"""
266 self._restart_adbd_with_root_permissions()
267 self._connect_over_tcpip_as_needed()
268
269
Kevin Cheng85e864a2015-11-30 11:49:34 -0800270 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800271 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700272 """Runs an adb command.
273
Kevin Chengd19e6c62015-10-28 16:39:39 -0700274 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700275
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700276 Refer to _device_run method for docstring for parameters.
277 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800278 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700279
280
Kevin Cheng85e864a2015-11-30 11:49:34 -0800281 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800282 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700283 """Runs an fastboot command.
284
Kevin Chengd19e6c62015-10-28 16:39:39 -0700285 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700286
287 Refer to _device_run method for docstring for parameters.
288 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800289 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700290
291
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700292 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700293 timeout=3600, ignore_status=False, ignore_timeout=False,
294 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
295 connect_timeout=30, options='', stdin=None, verbose=True,
296 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700297 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700298
Kevin Chengd19e6c62015-10-28 16:39:39 -0700299 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700300
Simran Basi431010f2013-09-04 10:42:41 -0700301 @param command: Command to run.
302 @param shell: If true the command runs in the adb shell otherwise if
303 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700304 reboot with shell=False will call 'adb reboot'. This
305 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700306 @param timeout: Time limit in seconds before attempting to
307 kill the running process. The run() function
308 will take a few seconds longer than 'timeout'
309 to complete if it has to kill the process.
310 @param ignore_status: Do not raise an exception, no matter
311 what the exit code of the command is.
312 @param ignore_timeout: Bool True if command timeouts should be
313 ignored. Will return None on command timeout.
314 @param stdout: Redirect stdout.
315 @param stderr: Redirect stderr.
316 @param connect_timeout: Connection timeout (in seconds)
317 @param options: String with additional ssh command options
318 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700319 @param require_sudo: True to require sudo to run the command. Default is
320 False.
Simran Basi431010f2013-09-04 10:42:41 -0700321 @param args: Sequence of strings to pass as arguments to command by
322 quoting them in " and escaping their contents if
323 necessary.
324
325 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700326 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700327 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800328 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700329 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800330 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700331 else:
332 raise NotImplementedError('Mode %s is not supported' % function)
333
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700334 if function != ADB_CMD and shell:
335 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700336
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700337 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700338
339 if serial:
340 cmd += '-s %s ' % serial
341 elif self._use_tcpip:
Simran Basi431010f2013-09-04 10:42:41 -0700342 cmd += '-s %s:5555 ' % self._device_hostname
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700343
Simran Basi431010f2013-09-04 10:42:41 -0700344 if shell:
345 cmd += '%s ' % SHELL_CMD
346 cmd += command
347
Roshan Pius58e5dd32015-10-16 15:16:42 -0700348 if verbose:
349 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700350
Kevin Cheng85e864a2015-11-30 11:49:34 -0800351 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400352 ignore_status=ignore_status,
353 ignore_timeout=ignore_timeout, stdout_tee=stdout,
354 stderr_tee=stderr, options=options, stdin=stdin,
355 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700356
357
Dan Shie234dea2016-01-20 17:15:17 -0800358 def get_board_name(self):
359 """Get the name of the board, e.g., shamu, dragonboard etc.
360 """
361 return self.run_output('getprop %s' % BOARD_FILE)
362
363
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700364 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700365 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700366 """Determine the correct board label for the device.
367
368 @returns a string representing this device's board.
369 """
Dan Shie234dea2016-01-20 17:15:17 -0800370 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700371 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800372 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700373
374
Christopher Wiley08849d52013-11-22 08:57:58 -0800375 def job_start(self):
376 """
377 Disable log collection on adb_hosts.
378
379 TODO(sbasi): crbug.com/305427
Christopher Wiley08849d52013-11-22 08:57:58 -0800380 """
381
382
Simran Basi431010f2013-09-04 10:42:41 -0700383 def run(self, command, timeout=3600, ignore_status=False,
384 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
385 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700386 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700387 """Run a command on the adb device.
388
389 The command given will be ran directly on the adb device; for example
390 'ls' will be ran as: 'abd shell ls'
391
392 @param command: The command line string.
393 @param timeout: Time limit in seconds before attempting to
394 kill the running process. The run() function
395 will take a few seconds longer than 'timeout'
396 to complete if it has to kill the process.
397 @param ignore_status: Do not raise an exception, no matter
398 what the exit code of the command is.
399 @param ignore_timeout: Bool True if command timeouts should be
400 ignored. Will return None on command timeout.
401 @param stdout_tee: Redirect stdout.
402 @param stderr_tee: Redirect stderr.
403 @param connect_timeout: Connection timeout (in seconds).
404 @param options: String with additional ssh command options.
405 @param stdin: Stdin to pass (a string) to the executed command
406 @param args: Sequence of strings to pass as arguments to command by
407 quoting them in " and escaping their contents if
408 necessary.
409
410 @returns A CMDResult object or None if the call timed out and
411 ignore_timeout is True.
412
413 @raises AutoservRunError: If the command failed.
414 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700415 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700416 command = ('"%s; echo %s:\$?"' %
417 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700418 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700419 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700420 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
421 stdout=stdout_tee, stderr=stderr_tee,
422 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700423 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700424 if not result:
425 # In case of timeouts.
426 return None
427
428 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700429 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700430 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700431 'Failed to parse the exit code for command: %s' %
432 command, result)
433 elif parse_output:
434 result.stdout = parse_output.group('OUTPUT')
435 result.exit_status = int(parse_output.group('EXIT_CODE'))
436 if result.exit_status != 0 and not ignore_status:
437 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700438 return result
439
440
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700441 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
442 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700443
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700444 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700445
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700446 @param timeout: Time limit in seconds before returning even if the host
447 is not up.
448 @param command: The command used to test if a device is up, i.e.,
449 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700450
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700451 @returns True if the host was found to be up before the timeout expires,
452 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700453 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700454 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
455 delay_sec=1)
456 def _wait_up():
457 if not self.is_up(command=command):
458 raise error.TimeoutException('Device is still down.')
459 return True
460
461 try:
462 _wait_up()
463 logging.debug('Host %s is now up, and can be accessed by %s.',
464 self.hostname, command)
465 return True
466 except error.TimeoutException:
467 logging.debug('Host %s is still down after waiting %d seconds',
468 self.hostname, timeout)
469 return False
Simran Basi431010f2013-09-04 10:42:41 -0700470
471
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700472 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
473 warning_timer=None, old_boot_id=None, command=ADB_CMD):
474 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700475
476 Overrides wait_down from AbstractSSHHost.
477
478 @param timeout: Time in seconds to wait for the host to go down.
479 @param warning_timer: Time limit in seconds that will generate
480 a warning if the host is not down yet.
481 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700482 @param old_boot_id: Not applicable for adb_host.
483 @param command: `adb`, test if the device can be accessed by adb
484 command, or `fastboot`, test if the device can be accessed by
485 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700486
487 @returns True if the device goes down before the timeout, False
488 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700489 """
490 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
491 delay_sec=1)
492 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700493 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700494 raise error.TimeoutException('Device is still up.')
495 return True
496
497 try:
498 _wait_down()
499 logging.debug('Host %s is now down', self.hostname)
500 return True
501 except error.TimeoutException:
502 logging.debug('Host %s is still up after waiting %d seconds',
503 self.hostname, timeout)
504 return False
505
506
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700507 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700508 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700509
510 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700511 """
512 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700513 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700514 self.adb_run('reboot', timeout=10, ignore_timeout=True)
515 if not self.wait_down():
516 raise error.AutoservRebootError(
517 'ADB Device is still up after reboot')
518 if not self.wait_up():
519 raise error.AutoservRebootError(
520 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800521 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800522
523
Ralph Nathanb45eb672015-11-18 20:04:39 -0800524 def remount(self):
525 """Remounts paritions on the device read-write.
526
527 Specifically, the /system, /vendor (if present) and /oem (if present)
528 partitions on the device are remounted read-write.
529 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800530 self.adb_run('remount')
531
532
Kevin Cheng549beb42015-11-18 11:42:25 -0800533 @staticmethod
534 def parse_device_serials(devices_output):
535 """Return a list of parsed serials from the output.
536
537 @param devices_output: Output from either an adb or fastboot command.
538
539 @returns List of device serials
540 """
541 devices = []
542 for line in devices_output.splitlines():
543 match = re.search(DEVICE_FINDER_REGEX, line)
544 if match:
545 serial = match.group('SERIAL')
546 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
547 serial = DEVICE_NO_SERIAL_TAG
548 logging.debug('Found Device: %s', serial)
549 devices.append(serial)
550 return devices
551
552
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700553 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700554 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700555
556 @params use_adb: True to get adb accessible devices. Set to False to
557 get fastboot accessible devices.
558
Kevin Chengd19e6c62015-10-28 16:39:39 -0700559 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700560 """
561 if use_adb:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700562 result = self.adb_run('devices')
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700563 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700564 result = self.fastboot_run('devices')
Kevin Cheng549beb42015-11-18 11:42:25 -0800565 return self.parse_device_serials(result.stdout)
Simran Basi431010f2013-09-04 10:42:41 -0700566
567
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700568 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700569 """Get a list of devices currently attached to the test station and
570 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700571 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800572 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700573 raise error.AutoservError(
574 'Not given ADB serial but multiple devices detected')
575 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700576
577
578 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700579 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700580 accessible by fastboot command.
581 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700582 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800583 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700584 raise error.AutoservError(
585 'Not given fastboot serial but multiple devices detected')
586 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700587
588
589 def is_up(self, timeout=0, command=ADB_CMD):
590 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700591
592 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700593 @param command: `adb`, the device can be accessed by adb command,
594 or `fastboot`, the device can be accessed by fastboot command.
595 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700596
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700597 @returns True if the device is detectable by given command, False
598 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700599
600 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700601 if command == ADB_CMD:
602 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800603 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800604 # ADB has a device state, if the device is not online, no
605 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800606 # DUT with single device connected may not have adb_serial set.
607 # Therefore, skip checking if serial is in the list of adb devices
608 # if self.adb_serial is not set.
609 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800610 logging.debug('Waiting for device to enter the ready state.')
611 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700612 elif command == FASTBOOT_CMD:
613 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800614 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700615 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700616 raise NotImplementedError('Mode %s is not supported' % command)
617
618 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700619
620
621 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700622 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700623
624 Called as the test ends. Will return the device to USB mode and kill
625 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700626 """
627 if self._use_tcpip:
628 # Return the device to usb mode.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400629 self.adb_run('usb')
Christopher Wiley08849d52013-11-22 08:57:58 -0800630 # TODO(sbasi) Originally, we would kill the server after each test to
631 # reduce the opportunity for bad server state to hang around.
632 # Unfortunately, there is a period of time after each kill during which
633 # the Android device becomes unusable, and if we start the next test
634 # too quickly, we'll get an error complaining about no ADB device
635 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700636 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800637 # |close| the associated teststation as well.
638 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700639 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700640
641
642 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700643 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700644
645 @param message String message to log into syslog
646 @param tag String tag prefix for syslog
647
648 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700649 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700650
651
652 def get_autodir(self):
653 """Return the directory to install autotest for client side tests."""
654 return '/data/autotest'
655
Kevin Cheng018db352015-09-20 02:22:08 -0700656
Kris Rambishde8f9d12015-12-16 12:42:41 -0800657 def is_device_ready(self):
658 """Return the if the device is ready for ADB commands."""
659 dev_state = self.adb_run('get-state').stdout.strip()
660 logging.debug('Current device state: %s', dev_state)
661 return dev_state == 'device'
662
663
Kevin Chengd19e6c62015-10-28 16:39:39 -0700664 def verify_connectivity(self):
665 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800666 if not self.is_device_ready():
667 raise error.AutoservHostError('device state is not in the '
668 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700669
670
Simran Basid3ba3fb2015-09-11 14:35:07 -0700671 def verify_software(self):
672 """Verify working software on an adb_host.
673
Simran Basi38f7ddf2015-09-18 12:25:03 -0700674 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700675 """
Dan Shiab999722015-12-04 14:27:08 -0800676 # Check if adb and fastboot are present.
677 self.teststation.run('which adb')
678 self.teststation.run('which fastboot')
679 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700680
Kevin Cheng018db352015-09-20 02:22:08 -0700681
Simran Basid3ba3fb2015-09-11 14:35:07 -0700682 def verify_job_repo_url(self, tag=''):
683 """Make sure job_repo_url of this host is valid.
684
Simran Basi38f7ddf2015-09-18 12:25:03 -0700685 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700686
687 @param tag: The tag from the server job, in the format
688 <job_id>-<user>/<hostname>, or <hostless> for a server job.
689 """
690 return
Kevin Cheng018db352015-09-20 02:22:08 -0700691
692
Simran Basibeb2bb22016-02-03 15:25:48 -0800693 def repair(self):
694 """Attempt to get the DUT to pass `self.verify()`."""
695 try:
696 self.ensure_adb_mode(timeout=30)
697 return
698 except error.AutoservError as e:
699 logging.error(e)
700 logging.debug('Verifying the device is accessible via fastboot.')
701 self.ensure_bootloader_mode()
702 if not self.job.run_test(
703 'provision_AndroidUpdate', host=self, value=None,
704 force=True, repair=True):
705 raise error.AutoservRepairTotalFailure(
706 'Unable to repair the device.')
707
708
Simran Basi1b023762015-09-25 12:12:20 -0700709 def send_file(self, source, dest, delete_dest=False,
710 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700711 """Copy files from the drone to the device.
712
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400713 Just a note, there is the possibility the test station is localhost
714 which makes some of these steps redundant (e.g. creating tmp dir) but
715 that scenario will undoubtedly be a development scenario (test station
716 is also the moblab) and not the typical live test running scenario so
717 the redundancy I think is harmless.
718
Kevin Cheng018db352015-09-20 02:22:08 -0700719 @param source: The file/directory on the drone to send to the device.
720 @param dest: The destination path on the device to copy to.
721 @param delete_dest: A flag set to choose whether or not to delete
722 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700723 @param preserve_symlinks: Controls if symlinks on the source will be
724 copied as such on the destination or
725 transformed into the referenced
726 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700727 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700728 # If we need to preserve symlinks, let's check if the source is a
729 # symlink itself and if so, just create it on the device.
730 if preserve_symlinks:
731 symlink_target = None
732 try:
733 symlink_target = os.readlink(source)
734 except OSError:
735 # Guess it's not a symlink.
736 pass
737
738 if symlink_target is not None:
739 # Once we create the symlink, let's get out of here.
740 self.run('ln -s %s %s' % (symlink_target, dest))
741 return
742
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400743 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700744 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400745 src_path = os.path.join(tmp_dir, os.path.basename(dest))
746 # Now copy the file over to the test station so you can reference the
747 # file in the push command.
748 self.teststation.send_file(source, src_path,
749 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700750
751 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400752 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700753
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700754 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700755
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400756 # Cleanup the test station.
757 try:
758 self.teststation.run('rm -rf %s' % tmp_dir)
759 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
760 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700761
762
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700763 def _get_file_info(self, dest):
764 """Get permission and possible symlink info about file on the device.
765
766 These files are on the device so we only have shell commands (via adb)
767 to get the info we want. We'll use 'ls' to get it all.
768
769 @param dest: File to get info about.
770
771 @returns a dict of the file permissions and symlink.
772 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800773 # Grab file info.
774 file_info = self.run_output('ls -l %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700775 symlink = None
776 perms = 0
777 match = re.match(FILE_INFO_REGEX, file_info)
778 if match:
779 # Check if it's a symlink and grab the linked dest if it is.
780 if match.group('TYPE') == 'l':
781 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
782 if symlink_match:
783 symlink = symlink_match.group('SYMLINK')
784
785 # Set the perms.
786 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
787 if perm != '-':
788 perms |= perm_flag
789
790 return {'perms': perms,
791 'symlink': symlink}
792
793
Simran Basi1b023762015-09-25 12:12:20 -0700794 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
795 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700796 """Copy files from the device to the drone.
797
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400798 Just a note, there is the possibility the test station is localhost
799 which makes some of these steps redundant (e.g. creating tmp dir) but
800 that scenario will undoubtedly be a development scenario (test station
801 is also the moblab) and not the typical live test running scenario so
802 the redundancy I think is harmless.
803
Kevin Cheng018db352015-09-20 02:22:08 -0700804 @param source: The file/directory on the device to copy back to the
805 drone.
806 @param dest: The destination path on the drone to copy to.
807 @param delete_dest: A flag set to choose whether or not to delete
808 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700809 @param preserve_perm: Tells get_file() to try to preserve the sources
810 permissions on files and dirs.
811 @param preserve_symlinks: Try to preserve symlinks instead of
812 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700813 """
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400814 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700815 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400816 dest_path = os.path.join(tmp_dir, os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700817
818 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400819 self.teststation.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700820
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700821 source_info = {}
822 if preserve_symlinks or preserve_perm:
823 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700824
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700825 # If we want to preserve symlinks, just create it here, otherwise pull
826 # the file off the device.
827 if preserve_symlinks and source_info['symlink']:
828 os.symlink(source_info['symlink'], dest)
829 else:
Roshan Pius95567142015-11-03 09:56:08 -0800830 self.adb_run('pull %s %s' % (source, dest_path))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700831
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400832 # Copy over the file from the test station and clean up.
833 self.teststation.get_file(dest_path, dest)
834 try:
835 self.teststation.run('rm -rf %s' % tmp_dir)
836 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
837 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700838
839 if preserve_perm:
840 os.chmod(dest, source_info['perms'])
Kevin Cheng018db352015-09-20 02:22:08 -0700841
842
843 def get_release_version(self):
844 """Get the release version from the RELEASE_FILE on the device.
845
846 @returns The release string in the RELEASE_FILE.
847
848 """
849 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700850
851
852 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700853 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700854
Kevin Chengd19e6c62015-10-28 16:39:39 -0700855 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700856
857 @param parent: Parent directory of the returned tmp dir.
858
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700859 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700860 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700861 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
862 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700863 if not parent.startswith(TMP_DIR):
864 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700865 self.run('mkdir -p %s' % parent)
866 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
867 self.tmp_dirs.append(tmp_dir)
868 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700869
870
871 def get_platform(self):
872 """Determine the correct platform label for this host.
873
874 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700875 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700876
877 @returns a string representing this host's platform.
878 """
879 return 'adb'
880
881
Gilad Arnolda76bef02015-09-29 13:55:15 -0700882 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800883 """Get the OS type of the DUT, e.g., android or brillo.
884 """
885 if not self._os_type:
886 if self.run_output('getprop ro.product.brand') == 'Brillo':
887 self._os_type = OS_TYPE_BRILLO
888 else:
889 self._os_type = OS_TYPE_ANDROID
890
891 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700892
893
894 def _forward(self, reverse, args):
895 """Execute a forwarding command.
896
897 @param reverse: Whether this is reverse forwarding (Boolean).
898 @param args: List of command arguments.
899 """
900 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700901 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700902
903
904 def add_forwarding(self, src, dst, reverse=False, rebind=True):
905 """Forward a port between the ADB host and device.
906
907 Port specifications are any strings accepted as such by ADB, for
908 example 'tcp:8080'.
909
910 @param src: Port specification to forward from.
911 @param dst: Port specification to forward to.
912 @param reverse: Do reverse forwarding from device to host (Boolean).
913 @param rebind: Allow rebinding an already bound port (Boolean).
914 """
915 args = []
916 if not rebind:
917 args.append('--no-rebind')
918 args += [src, dst]
919 self._forward(reverse, args)
920
921
922 def remove_forwarding(self, src=None, reverse=False):
923 """Removes forwarding on port.
924
925 @param src: Port specification, or None to remove all forwarding.
926 @param reverse: Whether this is reverse forwarding (Boolean).
927 """
928 args = []
929 if src is None:
930 args.append('--remove-all')
931 else:
932 args += ['--remove', src]
933 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700934
935
xixuan6cf6d2f2016-01-29 15:29:00 -0800936 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700937 """
938 Forwards a port securely through a tunnel process from the server
939 to the DUT for RPC server connection.
940 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
941 to the DUT.
942
943 @param port: remote port on the DUT.
944 @param local_port: local forwarding port.
945
946 @return: the tunnel process.
947 """
948 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800949 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700950
951
xixuan6cf6d2f2016-01-29 15:29:00 -0800952 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700953 """
954 Disconnects a previously forwarded port from the server to the DUT for
955 RPC server connection.
956 Remove the previously added 'ADB forward' rule to forward the RPC
957 packets from the AdbHost to the DUT.
958
959 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -0800960 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -0700961 @param port: remote port on the DUT.
962
963 """
964 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800965 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700966
967
968 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700969 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700970
971 @raise: error.AutoservError if the device failed to reboot into
972 bootloader mode.
973 """
974 if self.is_up(command=FASTBOOT_CMD):
975 return
976 self.adb_run('reboot bootloader')
977 if not self.wait_up(command=FASTBOOT_CMD):
978 raise error.AutoservError(
979 'The device failed to reboot into bootloader mode.')
980
981
Dan Shie4e807b2015-12-10 09:04:03 -0800982 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700983 """Ensure the device is up and can be accessed by adb command.
984
Dan Shie4e807b2015-12-10 09:04:03 -0800985 @param timeout: Time limit in seconds before returning even if the host
986 is not up.
987
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700988 @raise: error.AutoservError if the device failed to reboot into
989 adb mode.
990 """
991 if self.is_up():
992 return
Dan Shi04980372016-03-22 10:57:47 -0700993 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
994 # check if the device is in adb mode.
995 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -0800996 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700997 raise error.AutoservError(
998 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800999 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001000
1001
1002 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001003 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001004 """Get the Android build information from the build url.
1005
1006 @param build_url: The url to use for downloading Android artifacts.
1007 pattern: http://$devserver:###/static/branch/target/build_id
1008
Dan Shi6450e142016-03-11 11:52:20 -08001009 @return: A dictionary of build information, including keys:
1010 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001011 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001012 """
Dan Shiab999722015-12-04 14:27:08 -08001013 if not build_url:
1014 raise AndroidInstallError('Need build_url to download image files.')
1015
1016 try:
1017 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001018 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001019 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001020 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001021 match.group('BUILD_TYPE'))),
1022 'build_id': match.group('BUILD_ID')}
1023 except (AttributeError, IndexError, ValueError) as e:
1024 raise AndroidInstallError(
1025 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001026
1027
Dan Shia2872172015-10-31 01:16:51 -07001028 @retry.retry(error.AutoservRunError, timeout_min=10)
Dan Shidb0366c2016-02-19 10:36:18 -08001029 def download_file(self, build_url, file, dest_dir):
Dan Shia2872172015-10-31 01:16:51 -07001030 """Download the given file from the build url.
1031
1032 @param build_url: The url to use for downloading Android artifacts.
1033 pattern: http://$devserver:###/static/branch/target/build_id
1034 @param file: Name of the file to be downloaded, e.g., boot.img.
1035 @param dest_dir: Destination folder for the file to be downloaded to.
1036 """
Dan Shidb0366c2016-02-19 10:36:18 -08001037 # Append the file name to the url if build_url is linked to the folder
1038 # containing the file.
1039 if not build_url.endswith('/%s' % file):
1040 src_url = os.path.join(build_url, file)
1041 else:
1042 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001043 dest_file = os.path.join(dest_dir, file)
1044 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001045 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Dan Shia2872172015-10-31 01:16:51 -07001046 except:
1047 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001048 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001049 raise
1050
1051
Dan Shiab999722015-12-04 14:27:08 -08001052 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001053 """Download required image files from the given build_url to a local
1054 directory in the machine runs fastboot command.
1055
1056 @param build_url: The url to use for downloading Android artifacts.
1057 pattern: http://$devserver:###/static/branch/target/build_id
1058
1059 @return: Path to the directory contains image files.
1060 """
Dan Shi08ff1282016-02-18 19:51:16 -08001061 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001062
1063 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001064 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001065 image_files = [zipped_image_file] + ANDROID_STANDALONE_IMAGES
1066
1067 try:
1068 for image_file in image_files:
Dan Shidb0366c2016-02-19 10:36:18 -08001069 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001070
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001071 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1072 (image_dir, zipped_image_file, image_dir))
Dan Shia2872172015-10-31 01:16:51 -07001073
1074 return image_dir
1075 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001076 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001077 raise
1078
1079
Dan Shiab999722015-12-04 14:27:08 -08001080 def stage_brillo_image_files(self, build_url):
1081 """Download required brillo image files from the given build_url to a
1082 local directory in the machine runs fastboot command.
1083
1084 @param build_url: The url to use for downloading Android artifacts.
1085 pattern: http://$devserver:###/static/branch/target/build_id
1086
1087 @return: Path to the directory contains image files.
1088 """
Dan Shi08ff1282016-02-18 19:51:16 -08001089 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001090
1091 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1092 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1093 image_dir = self.teststation.get_tmp_dir()
1094 image_files = [zipped_image_file, vendor_partitions_file]
1095
1096 try:
1097 for image_file in image_files:
Dan Shidb0366c2016-02-19 10:36:18 -08001098 self.download_file(build_url, image_file, image_dir)
Dan Shiab999722015-12-04 14:27:08 -08001099
1100 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1101 (image_dir, zipped_image_file, image_dir))
1102 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1103 (image_dir, vendor_partitions_file,
1104 os.path.join(image_dir, 'vendor')))
1105 return image_dir
1106 except:
1107 self.teststation.run('rm -rf %s' % image_dir)
1108 raise
1109
1110
Simran Basibeb2bb22016-02-03 15:25:48 -08001111 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001112 """Stage a build on a devserver and return the build_url and devserver.
1113
1114 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001115
Dan Shi225b9042015-11-18 10:25:21 -08001116 @returns a tuple with an update URL like:
1117 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1118 and the devserver instance.
1119 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001120 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001121 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001122 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1123 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001124 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001125 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001126 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001127 devserver.trigger_download(target, build_id, branch,
1128 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001129 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001130
1131
Dan Shie4e807b2015-12-10 09:04:03 -08001132 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001133 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001134 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001135
1136 Following are the steps used here to provision an android device:
1137 1. If build_local_path is not set, download the image zip file, e.g.,
1138 shamu-img-2284311.zip, unzip it.
1139 2. Run fastboot to install following artifacts:
1140 bootloader, radio, boot, system, vendor(only if exists)
1141
1142 Repair is not supported for Android devices yet.
1143
1144 @param build_url: The url to use for downloading Android artifacts.
1145 pattern: http://$devserver:###/static/$build
1146 @param build_local_path: The path to a local folder that contains the
1147 image files needed to provision the device. Note that the folder
1148 is in the machine running adb command, rather than the drone.
1149 @param wipe: If true, userdata will be wiped before flashing.
1150 @param flash_all: If True, all img files found in img_path will be
1151 flashed. Otherwise, only boot and system are flashed.
1152
1153 @raises AndroidInstallError if any error occurs.
1154 """
Dan Shia2872172015-10-31 01:16:51 -07001155 # If the build is not staged in local server yet, clean up the temp
1156 # folder used to store image files after the provision is completed.
1157 delete_build_folder = bool(not build_local_path)
1158
1159 try:
1160 # Download image files needed for provision to a local directory.
1161 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001162 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001163
1164 # Device needs to be in bootloader mode for flashing.
1165 self.ensure_bootloader_mode()
1166
1167 if wipe:
Dan Shie4e807b2015-12-10 09:04:03 -08001168 self.fastboot_run('-w')
Dan Shia2872172015-10-31 01:16:51 -07001169
1170 # Get all *.img file in the build_local_path.
1171 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001172 image_files = self.teststation.run(
1173 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001174 images = dict([(os.path.basename(f), f) for f in image_files])
1175 for image, image_file in images.items():
1176 if image not in ANDROID_IMAGES:
1177 continue
1178 logging.info('Flashing %s...', image_file)
Dan Shi70c30192016-03-22 23:14:12 -07001179 self.fastboot_run('-S 256M flash %s %s' %
Dan Shie9913d32016-03-09 14:17:26 -08001180 (image[:-4], image_file))
Dan Shia2872172015-10-31 01:16:51 -07001181 if image == ANDROID_BOOTLOADER:
1182 self.fastboot_run('reboot-bootloader')
1183 self.wait_up(command=FASTBOOT_CMD)
1184 except Exception as e:
1185 logging.error('Install Android build failed with error: %s', e)
1186 # Re-raise the exception with type of AndroidInstallError.
1187 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1188 finally:
1189 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001190 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001191 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1192 DEFAULT_WAIT_UP_TIME_SECONDS)
1193 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001194 logging.info('Successfully installed Android build staged at %s.',
1195 build_url)
1196
1197
Dan Shiab999722015-12-04 14:27:08 -08001198 def install_brillo(self, build_url, build_local_path=None):
1199 """Install the Brillo DUT.
1200
1201 Following are the steps used here to provision an android device:
1202 1. If build_local_path is not set, download the image zip file, e.g.,
1203 dragonboard-img-123456.zip, unzip it. And download the vendor
1204 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1205 unzip it to vendor folder.
1206 2. Run provision_device script to install OS images and vendor
1207 partitions.
1208
1209 @param build_url: The url to use for downloading Android artifacts.
1210 pattern: http://$devserver:###/static/$build
1211 @param build_local_path: The path to a local folder that contains the
1212 image files needed to provision the device. Note that the folder
1213 is in the machine running adb command, rather than the drone.
1214
1215 @raises AndroidInstallError if any error occurs.
1216 """
1217 # If the build is not staged in local server yet, clean up the temp
1218 # folder used to store image files after the provision is completed.
1219 delete_build_folder = bool(not build_local_path)
1220
Dan Shiab999722015-12-04 14:27:08 -08001221 try:
1222 # Download image files needed for provision to a local directory.
1223 if not build_local_path:
1224 build_local_path = self.stage_brillo_image_files(build_url)
1225
1226 # Device needs to be in bootloader mode for flashing.
1227 self.ensure_bootloader_mode()
1228
1229 # Run provision_device command to install image files and vendor
1230 # partitions.
1231 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1232 cmd = (BRILLO_PROVISION_CMD %
1233 {'os_image_dir': build_local_path,
1234 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001235 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001236 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001237 self.teststation.run(cmd)
1238 except Exception as e:
1239 logging.error('Install Brillo build failed with error: %s', e)
1240 # Re-raise the exception with type of AndroidInstallError.
1241 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1242 finally:
1243 if delete_build_folder:
1244 self.teststation.run('rm -rf %s' % build_local_path)
1245 self.ensure_adb_mode()
1246 logging.info('Successfully installed Android build staged at %s.',
1247 build_url)
1248
1249
Dan Shibe3636a2016-02-14 22:48:01 -08001250 @property
1251 def job_repo_url_attribute(self):
1252 """Get the host attribute name for job_repo_url, which should append the
1253 adb serial.
1254 """
1255 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1256
1257
Dan Shie4e807b2015-12-10 09:04:03 -08001258 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001259 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001260 """Install the DUT.
1261
1262 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001263 pattern: http://$devserver:###/static/$build. If build_url is
1264 set to None, the code may try _parser.options.image to do the
1265 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001266 @param build_local_path: The path to a local directory that contains the
1267 image files needed to provision the device.
1268 @param wipe: If true, userdata will be wiped before flashing.
1269 @param flash_all: If True, all img files found in img_path will be
1270 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001271
Dan Shibe3636a2016-02-14 22:48:01 -08001272 @returns A tuple of (image_name, host_attributes).
1273 image_name is the name of image installed, e.g.,
1274 git_mnc-release/shamu-userdebug/1234
1275 host_attributes is a dictionary of (attribute, value), which
1276 can be saved to afe_host_attributes table in database. This
1277 method returns a dictionary with a single entry of
1278 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1279 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001280 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001281 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001282 if not build_url and self._parser.options.image:
1283 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001284 self._parser.options.image, os_type=os_type)
1285 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001286 self.install_android(
1287 build_url=build_url, build_local_path=build_local_path,
1288 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001289 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001290 self.install_brillo(
1291 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001292 else:
1293 raise error.InstallError(
1294 'Installation of os type %s is not supported.' %
1295 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001296 return (build_url.split('static/')[-1],
1297 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001298
1299
1300 def list_files_glob(self, path_glob):
1301 """Get a list of files on the device given glob pattern path.
1302
1303 @param path_glob: The path glob that we want to return the list of
1304 files that match the glob. Relative paths will not work as
1305 expected. Supply an absolute path to get the list of files
1306 you're hoping for.
1307
1308 @returns List of files that match the path_glob.
1309 """
1310 # This is just in case path_glob has no path separator.
1311 base_path = os.path.dirname(path_glob) or '.'
1312 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001313 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001314 if result.exit_status != 0:
1315 return []
1316 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001317
1318
Dan Shidb0366c2016-02-19 10:36:18 -08001319 def install_apk(self, apk, force_reinstall=False):
Kevin Cheng31355942016-01-05 14:23:35 -08001320 """Install the specified apk.
1321
1322 This will install the apk and override it if it's already installed and
1323 will also allow for downgraded apks.
1324
1325 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001326 @param force_reinstall: True to reinstall the apk even if it's already
1327 installed. Default is set to False.
1328
1329 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001330 """
Dan Shidb0366c2016-02-19 10:36:18 -08001331 return self.adb_run('install %s -d %s' %
1332 ('-r' if force_reinstall else '', apk))
1333
1334
1335 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1336 def _confirm_apk_installed(self, package_name):
1337 """Confirm if apk is already installed with the given name.
1338
1339 `pm list packages` command is not reliable some time. The retry helps to
1340 reduce the chance of false negative.
1341
1342 @param package_name: Name of the package, e.g., com.android.phone.
1343
1344 @raise AutoservRunError: If the package is not found or pm list command
1345 failed for any reason.
1346 """
1347 name = 'package:%s' % package_name
1348 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1349
1350
1351 def is_apk_installed(self, package_name):
1352 """Check if apk is already installed with the given name.
1353
1354 @param package_name: Name of the package, e.g., com.android.phone.
1355
1356 @return: True if package is installed. False otherwise.
1357 """
1358 try:
1359 self._confirm_apk_installed(package_name)
1360 return True
1361 except:
1362 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001363
1364
1365 def get_attributes_to_clear_before_provision(self):
1366 """Get a list of attributes to be cleared before machine_install starts.
1367 """
1368 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001369
1370
1371 def get_labels(self):
1372 """Return a list of the labels gathered from the devices connected.
1373
1374 @return: A list of strings that denote the labels from all the devices
1375 connected.
1376 """
1377 return self.labels.get_labels(self)
1378
1379
1380 def update_labels(self):
1381 """Update the labels for this testbed."""
1382 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001383
1384
1385 def stage_server_side_package(self, image=None):
1386 """Stage autotest server-side package on devserver.
1387
1388 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1389
1390 @return: A url to the autotest server-side package. Return None if
1391 server-side package is not supported.
1392 @raise: error.AutoservError if fail to locate the build to test with.
1393 """
1394 if image:
1395 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1396 else:
1397 job_repo_url = afe_utils.get_host_attribute(
1398 self, self.job_repo_url_attribute)
1399 if job_repo_url:
1400 devserver_url, image = (
1401 tools.get_devserver_build_from_package_url(
1402 job_repo_url, True))
1403 ds = dev_server.AndroidBuildServer(devserver_url)
1404 else:
1405 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1406 if not labels:
1407 raise error.AutoservError(
1408 'Failed to stage server-side package. The host has '
1409 'no job_report_url attribute or version label.')
1410 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1411 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1412
1413 branch, target, build_id = utils.parse_launch_control_build(image)
1414 build_target, _ = utils.parse_launch_control_target(target)
1415
1416 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1417 # packaging is not supported.
1418 try:
1419 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1420 logging.warn('Build %s is older than %s. Server side packaging '
1421 'is disabled.', image,
1422 self.MIN_VERSION_SUPPORT_SSP)
1423 return None
1424 except ValueError:
1425 logging.warn('Failed to compare build id in %s with the minimum '
1426 'version that supports server side packaging. Server '
1427 'side packaging is disabled.', image)
1428 return None
1429
1430 ds.stage_artifacts(target, build_id, branch,
1431 artifacts=['autotest_server_package'])
1432 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1433 {'build_target': build_target,
1434 'build_id': build_id})
1435 return '%s/static/%s/%s' % (ds.url(), image,
1436 autotest_server_package_name)