blob: e5ddd82cab9a1285ad59001e00c1dc0ba2f686b1 [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
993 self.fastboot_run('reboot')
Dan Shie4e807b2015-12-10 09:04:03 -0800994 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700995 raise error.AutoservError(
996 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800997 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -0700998
999
1000 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001001 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001002 """Get the Android build information from the build url.
1003
1004 @param build_url: The url to use for downloading Android artifacts.
1005 pattern: http://$devserver:###/static/branch/target/build_id
1006
Dan Shi6450e142016-03-11 11:52:20 -08001007 @return: A dictionary of build information, including keys:
1008 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001009 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001010 """
Dan Shiab999722015-12-04 14:27:08 -08001011 if not build_url:
1012 raise AndroidInstallError('Need build_url to download image files.')
1013
1014 try:
1015 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001016 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001017 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001018 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001019 match.group('BUILD_TYPE'))),
1020 'build_id': match.group('BUILD_ID')}
1021 except (AttributeError, IndexError, ValueError) as e:
1022 raise AndroidInstallError(
1023 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001024
1025
Dan Shia2872172015-10-31 01:16:51 -07001026 @retry.retry(error.AutoservRunError, timeout_min=10)
Dan Shidb0366c2016-02-19 10:36:18 -08001027 def download_file(self, build_url, file, dest_dir):
Dan Shia2872172015-10-31 01:16:51 -07001028 """Download the given file from the build url.
1029
1030 @param build_url: The url to use for downloading Android artifacts.
1031 pattern: http://$devserver:###/static/branch/target/build_id
1032 @param file: Name of the file to be downloaded, e.g., boot.img.
1033 @param dest_dir: Destination folder for the file to be downloaded to.
1034 """
Dan Shidb0366c2016-02-19 10:36:18 -08001035 # Append the file name to the url if build_url is linked to the folder
1036 # containing the file.
1037 if not build_url.endswith('/%s' % file):
1038 src_url = os.path.join(build_url, file)
1039 else:
1040 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001041 dest_file = os.path.join(dest_dir, file)
1042 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001043 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Dan Shia2872172015-10-31 01:16:51 -07001044 except:
1045 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001046 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001047 raise
1048
1049
Dan Shiab999722015-12-04 14:27:08 -08001050 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001051 """Download required image files from the given build_url to a local
1052 directory in the machine runs fastboot command.
1053
1054 @param build_url: The url to use for downloading Android artifacts.
1055 pattern: http://$devserver:###/static/branch/target/build_id
1056
1057 @return: Path to the directory contains image files.
1058 """
Dan Shi08ff1282016-02-18 19:51:16 -08001059 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001060
1061 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001062 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001063 image_files = [zipped_image_file] + ANDROID_STANDALONE_IMAGES
1064
1065 try:
1066 for image_file in image_files:
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
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001069 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1070 (image_dir, zipped_image_file, image_dir))
Dan Shia2872172015-10-31 01:16:51 -07001071
1072 return image_dir
1073 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001074 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001075 raise
1076
1077
Dan Shiab999722015-12-04 14:27:08 -08001078 def stage_brillo_image_files(self, build_url):
1079 """Download required brillo image files from the given build_url to a
1080 local directory in the machine runs fastboot command.
1081
1082 @param build_url: The url to use for downloading Android artifacts.
1083 pattern: http://$devserver:###/static/branch/target/build_id
1084
1085 @return: Path to the directory contains image files.
1086 """
Dan Shi08ff1282016-02-18 19:51:16 -08001087 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001088
1089 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1090 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1091 image_dir = self.teststation.get_tmp_dir()
1092 image_files = [zipped_image_file, vendor_partitions_file]
1093
1094 try:
1095 for image_file in image_files:
Dan Shidb0366c2016-02-19 10:36:18 -08001096 self.download_file(build_url, image_file, image_dir)
Dan Shiab999722015-12-04 14:27:08 -08001097
1098 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1099 (image_dir, zipped_image_file, image_dir))
1100 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1101 (image_dir, vendor_partitions_file,
1102 os.path.join(image_dir, 'vendor')))
1103 return image_dir
1104 except:
1105 self.teststation.run('rm -rf %s' % image_dir)
1106 raise
1107
1108
Simran Basibeb2bb22016-02-03 15:25:48 -08001109 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001110 """Stage a build on a devserver and return the build_url and devserver.
1111
1112 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001113
Dan Shi225b9042015-11-18 10:25:21 -08001114 @returns a tuple with an update URL like:
1115 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1116 and the devserver instance.
1117 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001118 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001119 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001120 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1121 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001122 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001123 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001124 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001125 devserver.trigger_download(target, build_id, branch,
1126 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001127 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001128
1129
Dan Shie4e807b2015-12-10 09:04:03 -08001130 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001131 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001132 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001133
1134 Following are the steps used here to provision an android device:
1135 1. If build_local_path is not set, download the image zip file, e.g.,
1136 shamu-img-2284311.zip, unzip it.
1137 2. Run fastboot to install following artifacts:
1138 bootloader, radio, boot, system, vendor(only if exists)
1139
1140 Repair is not supported for Android devices yet.
1141
1142 @param build_url: The url to use for downloading Android artifacts.
1143 pattern: http://$devserver:###/static/$build
1144 @param build_local_path: The path to a local folder that contains the
1145 image files needed to provision the device. Note that the folder
1146 is in the machine running adb command, rather than the drone.
1147 @param wipe: If true, userdata will be wiped before flashing.
1148 @param flash_all: If True, all img files found in img_path will be
1149 flashed. Otherwise, only boot and system are flashed.
1150
1151 @raises AndroidInstallError if any error occurs.
1152 """
Dan Shia2872172015-10-31 01:16:51 -07001153 # If the build is not staged in local server yet, clean up the temp
1154 # folder used to store image files after the provision is completed.
1155 delete_build_folder = bool(not build_local_path)
1156
1157 try:
1158 # Download image files needed for provision to a local directory.
1159 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001160 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001161
1162 # Device needs to be in bootloader mode for flashing.
1163 self.ensure_bootloader_mode()
1164
1165 if wipe:
Dan Shie4e807b2015-12-10 09:04:03 -08001166 self.fastboot_run('-w')
Dan Shia2872172015-10-31 01:16:51 -07001167
1168 # Get all *.img file in the build_local_path.
1169 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001170 image_files = self.teststation.run(
1171 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001172 images = dict([(os.path.basename(f), f) for f in image_files])
1173 for image, image_file in images.items():
1174 if image not in ANDROID_IMAGES:
1175 continue
1176 logging.info('Flashing %s...', image_file)
Dan Shie9913d32016-03-09 14:17:26 -08001177 self.fastboot_run('-S 512M flash %s %s' %
1178 (image[:-4], image_file))
Dan Shia2872172015-10-31 01:16:51 -07001179 if image == ANDROID_BOOTLOADER:
1180 self.fastboot_run('reboot-bootloader')
1181 self.wait_up(command=FASTBOOT_CMD)
1182 except Exception as e:
1183 logging.error('Install Android build failed with error: %s', e)
1184 # Re-raise the exception with type of AndroidInstallError.
1185 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1186 finally:
1187 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001188 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001189 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1190 DEFAULT_WAIT_UP_TIME_SECONDS)
1191 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001192 logging.info('Successfully installed Android build staged at %s.',
1193 build_url)
1194
1195
Dan Shiab999722015-12-04 14:27:08 -08001196 def install_brillo(self, build_url, build_local_path=None):
1197 """Install the Brillo DUT.
1198
1199 Following are the steps used here to provision an android device:
1200 1. If build_local_path is not set, download the image zip file, e.g.,
1201 dragonboard-img-123456.zip, unzip it. And download the vendor
1202 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1203 unzip it to vendor folder.
1204 2. Run provision_device script to install OS images and vendor
1205 partitions.
1206
1207 @param build_url: The url to use for downloading Android artifacts.
1208 pattern: http://$devserver:###/static/$build
1209 @param build_local_path: The path to a local folder that contains the
1210 image files needed to provision the device. Note that the folder
1211 is in the machine running adb command, rather than the drone.
1212
1213 @raises AndroidInstallError if any error occurs.
1214 """
1215 # If the build is not staged in local server yet, clean up the temp
1216 # folder used to store image files after the provision is completed.
1217 delete_build_folder = bool(not build_local_path)
1218
Dan Shiab999722015-12-04 14:27:08 -08001219 try:
1220 # Download image files needed for provision to a local directory.
1221 if not build_local_path:
1222 build_local_path = self.stage_brillo_image_files(build_url)
1223
1224 # Device needs to be in bootloader mode for flashing.
1225 self.ensure_bootloader_mode()
1226
1227 # Run provision_device command to install image files and vendor
1228 # partitions.
1229 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1230 cmd = (BRILLO_PROVISION_CMD %
1231 {'os_image_dir': build_local_path,
1232 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001233 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001234 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001235 self.teststation.run(cmd)
1236 except Exception as e:
1237 logging.error('Install Brillo build failed with error: %s', e)
1238 # Re-raise the exception with type of AndroidInstallError.
1239 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1240 finally:
1241 if delete_build_folder:
1242 self.teststation.run('rm -rf %s' % build_local_path)
1243 self.ensure_adb_mode()
1244 logging.info('Successfully installed Android build staged at %s.',
1245 build_url)
1246
1247
Dan Shibe3636a2016-02-14 22:48:01 -08001248 @property
1249 def job_repo_url_attribute(self):
1250 """Get the host attribute name for job_repo_url, which should append the
1251 adb serial.
1252 """
1253 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1254
1255
Dan Shie4e807b2015-12-10 09:04:03 -08001256 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001257 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001258 """Install the DUT.
1259
1260 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001261 pattern: http://$devserver:###/static/$build. If build_url is
1262 set to None, the code may try _parser.options.image to do the
1263 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001264 @param build_local_path: The path to a local directory that contains the
1265 image files needed to provision the device.
1266 @param wipe: If true, userdata will be wiped before flashing.
1267 @param flash_all: If True, all img files found in img_path will be
1268 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001269
Dan Shibe3636a2016-02-14 22:48:01 -08001270 @returns A tuple of (image_name, host_attributes).
1271 image_name is the name of image installed, e.g.,
1272 git_mnc-release/shamu-userdebug/1234
1273 host_attributes is a dictionary of (attribute, value), which
1274 can be saved to afe_host_attributes table in database. This
1275 method returns a dictionary with a single entry of
1276 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1277 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001278 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001279 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001280 if not build_url and self._parser.options.image:
1281 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001282 self._parser.options.image, os_type=os_type)
1283 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001284 self.install_android(
1285 build_url=build_url, build_local_path=build_local_path,
1286 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001287 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001288 self.install_brillo(
1289 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001290 else:
1291 raise error.InstallError(
1292 'Installation of os type %s is not supported.' %
1293 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001294 return (build_url.split('static/')[-1],
1295 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001296
1297
1298 def list_files_glob(self, path_glob):
1299 """Get a list of files on the device given glob pattern path.
1300
1301 @param path_glob: The path glob that we want to return the list of
1302 files that match the glob. Relative paths will not work as
1303 expected. Supply an absolute path to get the list of files
1304 you're hoping for.
1305
1306 @returns List of files that match the path_glob.
1307 """
1308 # This is just in case path_glob has no path separator.
1309 base_path = os.path.dirname(path_glob) or '.'
1310 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001311 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001312 if result.exit_status != 0:
1313 return []
1314 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001315
1316
Dan Shidb0366c2016-02-19 10:36:18 -08001317 def install_apk(self, apk, force_reinstall=False):
Kevin Cheng31355942016-01-05 14:23:35 -08001318 """Install the specified apk.
1319
1320 This will install the apk and override it if it's already installed and
1321 will also allow for downgraded apks.
1322
1323 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001324 @param force_reinstall: True to reinstall the apk even if it's already
1325 installed. Default is set to False.
1326
1327 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001328 """
Dan Shidb0366c2016-02-19 10:36:18 -08001329 return self.adb_run('install %s -d %s' %
1330 ('-r' if force_reinstall else '', apk))
1331
1332
1333 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1334 def _confirm_apk_installed(self, package_name):
1335 """Confirm if apk is already installed with the given name.
1336
1337 `pm list packages` command is not reliable some time. The retry helps to
1338 reduce the chance of false negative.
1339
1340 @param package_name: Name of the package, e.g., com.android.phone.
1341
1342 @raise AutoservRunError: If the package is not found or pm list command
1343 failed for any reason.
1344 """
1345 name = 'package:%s' % package_name
1346 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1347
1348
1349 def is_apk_installed(self, package_name):
1350 """Check if apk is already installed with the given name.
1351
1352 @param package_name: Name of the package, e.g., com.android.phone.
1353
1354 @return: True if package is installed. False otherwise.
1355 """
1356 try:
1357 self._confirm_apk_installed(package_name)
1358 return True
1359 except:
1360 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001361
1362
1363 def get_attributes_to_clear_before_provision(self):
1364 """Get a list of attributes to be cleared before machine_install starts.
1365 """
1366 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001367
1368
1369 def get_labels(self):
1370 """Return a list of the labels gathered from the devices connected.
1371
1372 @return: A list of strings that denote the labels from all the devices
1373 connected.
1374 """
1375 return self.labels.get_labels(self)
1376
1377
1378 def update_labels(self):
1379 """Update the labels for this testbed."""
1380 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001381
1382
1383 def stage_server_side_package(self, image=None):
1384 """Stage autotest server-side package on devserver.
1385
1386 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1387
1388 @return: A url to the autotest server-side package. Return None if
1389 server-side package is not supported.
1390 @raise: error.AutoservError if fail to locate the build to test with.
1391 """
1392 if image:
1393 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1394 else:
1395 job_repo_url = afe_utils.get_host_attribute(
1396 self, self.job_repo_url_attribute)
1397 if job_repo_url:
1398 devserver_url, image = (
1399 tools.get_devserver_build_from_package_url(
1400 job_repo_url, True))
1401 ds = dev_server.AndroidBuildServer(devserver_url)
1402 else:
1403 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1404 if not labels:
1405 raise error.AutoservError(
1406 'Failed to stage server-side package. The host has '
1407 'no job_report_url attribute or version label.')
1408 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1409 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1410
1411 branch, target, build_id = utils.parse_launch_control_build(image)
1412 build_target, _ = utils.parse_launch_control_target(target)
1413
1414 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1415 # packaging is not supported.
1416 try:
1417 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1418 logging.warn('Build %s is older than %s. Server side packaging '
1419 'is disabled.', image,
1420 self.MIN_VERSION_SUPPORT_SSP)
1421 return None
1422 except ValueError:
1423 logging.warn('Failed to compare build id in %s with the minimum '
1424 'version that supports server side packaging. Server '
1425 'side packaging is disabled.', image)
1426 return None
1427
1428 ds.stage_artifacts(target, build_id, branch,
1429 artifacts=['autotest_server_package'])
1430 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1431 {'build_target': build_target,
1432 'build_id': build_id})
1433 return '%s/static/%s/%s' % (ds.url(), image,
1434 autotest_server_package_name)