blob: 7baf80f11b7923d6f8571c326b3a005206202d2d [file] [log] [blame]
Simran Basi431010f2013-09-04 10:42:41 -07001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -07004import functools
Simran Basi431010f2013-09-04 10:42:41 -07005import logging
Kevin Cheng018db352015-09-20 02:22:08 -07006import os
Simran Basi431010f2013-09-04 10:42:41 -07007import re
Kevin Cheng92fe6ae2015-10-21 11:45:34 -07008import stat
Dan Shia2872172015-10-31 01:16:51 -07009import sys
Simran Basi431010f2013-09-04 10:42:41 -070010import time
11
12import common
13
Simran Basi9c5d3982016-04-01 18:49:44 -070014from autotest_lib.client.bin import utils as client_utils
Simran Basi431010f2013-09-04 10:42:41 -070015from autotest_lib.client.common_lib import error
Dan Shi6450e142016-03-11 11:52:20 -080016from autotest_lib.client.common_lib import global_config
Dan Shi225b9042015-11-18 10:25:21 -080017from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070018from autotest_lib.client.common_lib.cros import retry
Dan Shi6450e142016-03-11 11:52:20 -080019from autotest_lib.server import afe_utils
Dan Shi225b9042015-11-18 10:25:21 -080020from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070021from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080022from autotest_lib.server import utils
Simran Basi5ace6f22016-01-06 17:30:44 -080023from autotest_lib.server.cros import provision
Dan Shi6450e142016-03-11 11:52:20 -080024from autotest_lib.server.cros.dynamic_suite import tools
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070025from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070026from autotest_lib.server.hosts import abstract_ssh
Kevin Chengc6a645a2015-12-18 11:15:10 -080027from autotest_lib.server.hosts import adb_label
28from autotest_lib.server.hosts import base_label
Kevin Cheng85e864a2015-11-30 11:49:34 -080029from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070030
31
Dan Shi6450e142016-03-11 11:52:20 -080032CONFIG = global_config.global_config
33
Dan Shi6ea3e1c2015-10-28 15:19:04 -070034ADB_CMD = 'adb'
35FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070036SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070037# Some devices have no serial, then `adb serial` has output such as:
38# (no serial number) device
39# ?????????? device
40DEVICE_NO_SERIAL_MSG = '(no serial number)'
41DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070042# Regex to find an adb device. Examples:
43# 0146B5580B01801B device
44# 018e0ecb20c97a62 device
45# 172.22.75.141:5555 device
Alexandru Branciogea380fb2016-04-01 16:01:34 +030046DEVICE_FINDER_REGEX = (r'^(?P<SERIAL>([\w-]+)|((tcp:)?' +
47 '\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}([:]5555)?)|' +
Filipe Brandenburger34363392015-08-13 14:57:45 -070048 re.escape(DEVICE_NO_SERIAL_MSG) +
Alexandru Branciogea380fb2016-04-01 16:01:34 +030049 r')[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070050CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
51CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
52 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070053RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070054BOARD_FILE = 'ro.product.device'
Simran Basi38f7ddf2015-09-18 12:25:03 -070055TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070056# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080057# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070058FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
59FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
60# List of the perm stats indexed by the order they are listed in the example
61# supplied above.
62FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
63 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
64 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070065
Dan Shi6ea3e1c2015-10-28 15:19:04 -070066# Default maximum number of seconds to wait for a device to be down.
67DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
68# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080069DEFAULT_WAIT_UP_TIME_SECONDS = 300
70# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080071WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070072
Dan Shia2872172015-10-31 01:16:51 -070073OS_TYPE_ANDROID = 'android'
74OS_TYPE_BRILLO = 'brillo'
75
Dan Shie234dea2016-01-20 17:15:17 -080076# Regex to parse build name to get the detailed build information.
Dan Shi6450e142016-03-11 11:52:20 -080077BUILD_REGEX = ('(?P<BRANCH>([^/]+))/(?P<BUILD_TARGET>([^/]+))-'
Dan Shie234dea2016-01-20 17:15:17 -080078 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))')
Dan Shia2872172015-10-31 01:16:51 -070079# Regex to parse devserver url to get the detailed build information. Sample
80# url: http://$devserver:8080/static/branch/target/build_id
Dan Shie234dea2016-01-20 17:15:17 -080081DEVSERVER_URL_REGEX = '.*/%s/*' % BUILD_REGEX
Dan Shia2872172015-10-31 01:16:51 -070082
Dan Shi6450e142016-03-11 11:52:20 -080083ANDROID_IMAGE_FILE_FMT = '%(build_target)s-img-%(build_id)s.zip'
Dan Shia2872172015-10-31 01:16:51 -070084ANDROID_BOOTLOADER = 'bootloader.img'
85ANDROID_RADIO = 'radio.img'
86ANDROID_BOOT = 'boot.img'
87ANDROID_SYSTEM = 'system.img'
88ANDROID_VENDOR = 'vendor.img'
Dan Shiab999722015-12-04 14:27:08 -080089BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
Dan Shi6450e142016-03-11 11:52:20 -080090 '%(build_target)s-vendor_partitions-%(build_id)s.zip')
91AUTOTEST_SERVER_PACKAGE_FILE_FMT = (
92 '%(build_target)s-autotest_server_package-%(build_id)s.tar.bz2')
Simran Basi9228a6f2016-03-29 12:03:37 -070093ADB_DEVICE_PREFIXES = ['product:', 'model:', 'device:']
Dan Shia2872172015-10-31 01:16:51 -070094
95# Image files not inside the image zip file. These files should be downloaded
96# directly from devserver.
97ANDROID_STANDALONE_IMAGES = [ANDROID_BOOTLOADER, ANDROID_RADIO]
98# Image files that are packaged in a zip file, e.g., shamu-img-123456.zip
99ANDROID_ZIPPED_IMAGES = [ANDROID_BOOT, ANDROID_SYSTEM, ANDROID_VENDOR]
100# All image files to be flashed to an Android device.
101ANDROID_IMAGES = ANDROID_STANDALONE_IMAGES + ANDROID_ZIPPED_IMAGES
102
Simran Basi9c5d3982016-04-01 18:49:44 -0700103# Map of product names to build target name.
104PRODUCT_TARGET_MAP = {'dragon' : 'ryu',
105 'flo' : 'razor',
106 'flo_lte' : 'razorg',
107 'gm4g_sprout' : 'seed_l8150',
108 'flounder' : 'volantis',
109 'flounder_lte' : 'volantisg'}
110
Dan Shiab999722015-12-04 14:27:08 -0800111# Command to provision a Brillo device.
112# os_image_dir: The full path of the directory that contains all the Android image
113# files (from the image zip file).
114# vendor_partition_dir: The full path of the directory that contains all the
115# Brillo vendor partitions, and provision-device script.
116BRILLO_PROVISION_CMD = (
Simran Basi7e52c622016-01-05 15:43:51 -0800117 'sudo ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
Dan Shiab999722015-12-04 14:27:08 -0800118 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
119 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -0700120
121class AndroidInstallError(error.InstallError):
122 """Generic error for Android installation related exceptions."""
123
124
Simran Basi724b8a52013-09-30 11:19:31 -0700125class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700126 """This class represents a host running an ADB server."""
127
Simran Basi5ace6f22016-01-06 17:30:44 -0800128 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700129 _LABEL_FUNCTIONS = []
130 _DETECTABLE_LABELS = []
131 label_decorator = functools.partial(utils.add_label_detector,
132 _LABEL_FUNCTIONS,
133 _DETECTABLE_LABELS)
134
Dan Shi225b9042015-11-18 10:25:21 -0800135 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700136
Dan Shi6450e142016-03-11 11:52:20 -0800137 # Minimum build id that supports server side packaging. Older builds may
138 # not have server side package built or with Autotest code change to support
139 # server-side packaging.
140 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
141 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
142
beeps46dadc92013-11-07 14:07:10 -0800143 @staticmethod
144 def check_host(host, timeout=10):
145 """
146 Check if the given host is an adb host.
147
Simran Basi14622bb2015-11-25 13:23:40 -0800148 If SSH connectivity can't be established, check_host will try to use
149 user 'adb' as well. If SSH connectivity still can't be established
150 then the original SSH user is restored.
151
beeps46dadc92013-11-07 14:07:10 -0800152 @param host: An ssh host representing a device.
153 @param timeout: The timeout for the run command.
154
155
156 @return: True if the host device has adb.
157
158 @raises AutoservRunError: If the command failed.
159 @raises AutoservSSHTimeout: Ssh connection has timed out.
160 """
Dan Shi64e130f2015-12-16 14:45:44 -0800161 # host object may not have user attribute if it's a LocalHost object.
162 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800163 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800164 if not (host.hostname == 'localhost' or
165 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700166 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700167 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700168 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700169 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800170 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800171 if current_user is not None:
172 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800173 return False
174 return result.exit_status == 0
175
176
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700177 # TODO(garnold) Remove the 'serials' argument once all clients are made to
178 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700179 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700180 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700181 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700182 """Initialize an ADB Host.
183
184 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700185 test station connected to an Android DUT. This will be the DUT
186 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700187 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700188
189 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700190 @param serials: DEPRECATED (to be removed)
191 @param adb_serial: An ADB device serial. If None, assume a single
192 device is attached (and fail otherwise).
193 @param fastboot_serial: A fastboot device serial. If None, defaults to
194 the ADB serial (or assumes a single device if
195 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800196 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700197 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800198 # Sets up the is_client_install_supported field.
199 super(ADBHost, self)._initialize(hostname=hostname,
200 is_client_install_supported=False,
201 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800202
Kevin Chengd19e6c62015-10-28 16:39:39 -0700203 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800204 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi1bf60eb2015-12-01 16:39:29 -0800205 # TODO (sbasi/kevcheng): Once the teststation host is committed,
206 # refactor the serial retrieval.
207 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800208 self.adb_serial = adb_serial
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300209 adb_prefix = any(adb_serial.startswith(p) for p in ADB_DEVICE_PREFIXES)
210 self.fastboot_serial = (fastboot_serial or
211 ('tcp:%s' % adb_serial.split(':')[0] if
212 ':' in adb_serial and not adb_prefix else adb_serial))
Kevin Cheng85e864a2015-11-30 11:49:34 -0800213 self.teststation = (teststation if teststation
214 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700215
216 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800217 if self.adb_serial:
218 msg += ', ADB serial: %s' % self.adb_serial
219 if self.fastboot_serial:
220 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700221 logging.debug(msg)
222
Simran Basi9228a6f2016-03-29 12:03:37 -0700223 self._use_tcpip = ':' in adb_serial and not adb_prefix
Simran Basibeb2bb22016-02-03 15:25:48 -0800224 # Try resetting the ADB daemon on the device, however if we are
225 # creating the host to do a repair job, the device maybe inaccesible
226 # via ADB.
227 try:
228 self._reset_adbd_connection()
229 except (error.AutotestHostRunError, error.AutoservRunError) as e:
230 logging.error('Unable to reset the device adb daemon connection: '
231 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800232 self._os_type = None
233
Simran Basi431010f2013-09-04 10:42:41 -0700234
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700235 def _connect_over_tcpip_as_needed(self):
236 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700237 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700238 return
239 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700240 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700241
242
Roshan Pius4d7540c2015-12-16 13:30:32 -0800243 def _restart_adbd_with_root_permissions(self):
244 """Restarts the adb daemon with root permissions."""
245 self.adb_run('root')
246 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
247 time.sleep(1)
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300248 self._connect_over_tcpip_as_needed()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800249 self.adb_run('wait-for-device')
250
251
Simran Basi9228a6f2016-03-29 12:03:37 -0700252 def _set_tcp_port(self):
253 """Ensure the device remains in tcp/ip mode after a reboot."""
254 if not self._use_tcpip:
255 return
256 port = self.adb_serial.split(':')[-1]
257 self.run('setprop persist.adb.tcp.port %s' % port)
258
259
Roshan Pius4d7540c2015-12-16 13:30:32 -0800260 def _reset_adbd_connection(self):
261 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800262 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700263 self._restart_adbd_with_root_permissions()
264 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800265
266
Kevin Cheng85e864a2015-11-30 11:49:34 -0800267 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800268 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700269 """Runs an adb command.
270
Kevin Chengd19e6c62015-10-28 16:39:39 -0700271 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700272
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700273 Refer to _device_run method for docstring for parameters.
274 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800275 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700276
277
Kevin Cheng85e864a2015-11-30 11:49:34 -0800278 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800279 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700280 """Runs an fastboot command.
281
Kevin Chengd19e6c62015-10-28 16:39:39 -0700282 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700283
284 Refer to _device_run method for docstring for parameters.
285 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800286 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700287
288
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700289 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700290 timeout=3600, ignore_status=False, ignore_timeout=False,
291 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
292 connect_timeout=30, options='', stdin=None, verbose=True,
293 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700294 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700295
Kevin Chengd19e6c62015-10-28 16:39:39 -0700296 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700297
Simran Basi431010f2013-09-04 10:42:41 -0700298 @param command: Command to run.
299 @param shell: If true the command runs in the adb shell otherwise if
300 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700301 reboot with shell=False will call 'adb reboot'. This
302 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700303 @param timeout: Time limit in seconds before attempting to
304 kill the running process. The run() function
305 will take a few seconds longer than 'timeout'
306 to complete if it has to kill the process.
307 @param ignore_status: Do not raise an exception, no matter
308 what the exit code of the command is.
309 @param ignore_timeout: Bool True if command timeouts should be
310 ignored. Will return None on command timeout.
311 @param stdout: Redirect stdout.
312 @param stderr: Redirect stderr.
313 @param connect_timeout: Connection timeout (in seconds)
314 @param options: String with additional ssh command options
315 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700316 @param require_sudo: True to require sudo to run the command. Default is
317 False.
Simran Basi431010f2013-09-04 10:42:41 -0700318 @param args: Sequence of strings to pass as arguments to command by
319 quoting them in " and escaping their contents if
320 necessary.
321
322 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700323 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700324 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800325 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700326 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800327 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700328 else:
329 raise NotImplementedError('Mode %s is not supported' % function)
330
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700331 if function != ADB_CMD and shell:
332 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700333
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700334 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700335
336 if serial:
337 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700338
Simran Basi431010f2013-09-04 10:42:41 -0700339 if shell:
340 cmd += '%s ' % SHELL_CMD
341 cmd += command
342
Roshan Pius58e5dd32015-10-16 15:16:42 -0700343 if verbose:
344 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700345
Kevin Cheng85e864a2015-11-30 11:49:34 -0800346 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400347 ignore_status=ignore_status,
348 ignore_timeout=ignore_timeout, stdout_tee=stdout,
349 stderr_tee=stderr, options=options, stdin=stdin,
350 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700351
352
Dan Shie234dea2016-01-20 17:15:17 -0800353 def get_board_name(self):
354 """Get the name of the board, e.g., shamu, dragonboard etc.
355 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700356 product = self.run_output('getprop %s' % BOARD_FILE)
357 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800358
359
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700360 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700361 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700362 """Determine the correct board label for the device.
363
364 @returns a string representing this device's board.
365 """
Dan Shie234dea2016-01-20 17:15:17 -0800366 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700367 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800368 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700369
370
Christopher Wiley08849d52013-11-22 08:57:58 -0800371 def job_start(self):
372 """
373 Disable log collection on adb_hosts.
374
375 TODO(sbasi): crbug.com/305427
Christopher Wiley08849d52013-11-22 08:57:58 -0800376 """
377
378
Simran Basi431010f2013-09-04 10:42:41 -0700379 def run(self, command, timeout=3600, ignore_status=False,
380 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
381 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700382 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700383 """Run a command on the adb device.
384
385 The command given will be ran directly on the adb device; for example
386 'ls' will be ran as: 'abd shell ls'
387
388 @param command: The command line string.
389 @param timeout: Time limit in seconds before attempting to
390 kill the running process. The run() function
391 will take a few seconds longer than 'timeout'
392 to complete if it has to kill the process.
393 @param ignore_status: Do not raise an exception, no matter
394 what the exit code of the command is.
395 @param ignore_timeout: Bool True if command timeouts should be
396 ignored. Will return None on command timeout.
397 @param stdout_tee: Redirect stdout.
398 @param stderr_tee: Redirect stderr.
399 @param connect_timeout: Connection timeout (in seconds).
400 @param options: String with additional ssh command options.
401 @param stdin: Stdin to pass (a string) to the executed command
402 @param args: Sequence of strings to pass as arguments to command by
403 quoting them in " and escaping their contents if
404 necessary.
405
406 @returns A CMDResult object or None if the call timed out and
407 ignore_timeout is True.
408
409 @raises AutoservRunError: If the command failed.
410 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700411 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700412 command = ('"%s; echo %s:\$?"' %
413 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700414 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700415 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700416 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
417 stdout=stdout_tee, stderr=stderr_tee,
418 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700419 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700420 if not result:
421 # In case of timeouts.
422 return None
423
424 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700425 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700426 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700427 'Failed to parse the exit code for command: %s' %
428 command, result)
429 elif parse_output:
430 result.stdout = parse_output.group('OUTPUT')
431 result.exit_status = int(parse_output.group('EXIT_CODE'))
432 if result.exit_status != 0 and not ignore_status:
433 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700434 return result
435
436
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700437 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
438 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700439
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700440 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700441
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700442 @param timeout: Time limit in seconds before returning even if the host
443 is not up.
444 @param command: The command used to test if a device is up, i.e.,
445 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700446
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700447 @returns True if the host was found to be up before the timeout expires,
448 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700449 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700450 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
451 delay_sec=1)
452 def _wait_up():
453 if not self.is_up(command=command):
454 raise error.TimeoutException('Device is still down.')
455 return True
456
457 try:
458 _wait_up()
459 logging.debug('Host %s is now up, and can be accessed by %s.',
460 self.hostname, command)
461 return True
462 except error.TimeoutException:
463 logging.debug('Host %s is still down after waiting %d seconds',
464 self.hostname, timeout)
465 return False
Simran Basi431010f2013-09-04 10:42:41 -0700466
467
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700468 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
469 warning_timer=None, old_boot_id=None, command=ADB_CMD):
470 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700471
472 Overrides wait_down from AbstractSSHHost.
473
474 @param timeout: Time in seconds to wait for the host to go down.
475 @param warning_timer: Time limit in seconds that will generate
476 a warning if the host is not down yet.
477 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700478 @param old_boot_id: Not applicable for adb_host.
479 @param command: `adb`, test if the device can be accessed by adb
480 command, or `fastboot`, test if the device can be accessed by
481 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700482
483 @returns True if the device goes down before the timeout, False
484 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700485 """
486 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
487 delay_sec=1)
488 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700489 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700490 raise error.TimeoutException('Device is still up.')
491 return True
492
493 try:
494 _wait_down()
495 logging.debug('Host %s is now down', self.hostname)
496 return True
497 except error.TimeoutException:
498 logging.debug('Host %s is still up after waiting %d seconds',
499 self.hostname, timeout)
500 return False
501
502
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700503 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700504 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700505
506 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700507 """
508 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700509 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700510 self.adb_run('reboot', timeout=10, ignore_timeout=True)
511 if not self.wait_down():
512 raise error.AutoservRebootError(
513 'ADB Device is still up after reboot')
514 if not self.wait_up():
515 raise error.AutoservRebootError(
516 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800517 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800518
519
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300520 def fastboot_reboot(self):
521 """Do a fastboot reboot to go back to adb.
522
523 @raises AutoservRebootError if reboot failed.
524 """
525 self.fastboot_run('reboot')
526 if not self.wait_down(command=FASTBOOT_CMD):
527 raise error.AutoservRebootError(
528 'Device is still in fastboot mode after reboot')
529 if not self.wait_up():
530 raise error.AutoservRebootError(
531 'Device failed to boot to adb after fastboot reboot.')
532 self._reset_adbd_connection()
533
534
Ralph Nathanb45eb672015-11-18 20:04:39 -0800535 def remount(self):
536 """Remounts paritions on the device read-write.
537
538 Specifically, the /system, /vendor (if present) and /oem (if present)
539 partitions on the device are remounted read-write.
540 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800541 self.adb_run('remount')
542
543
Kevin Cheng549beb42015-11-18 11:42:25 -0800544 @staticmethod
545 def parse_device_serials(devices_output):
546 """Return a list of parsed serials from the output.
547
548 @param devices_output: Output from either an adb or fastboot command.
549
550 @returns List of device serials
551 """
552 devices = []
553 for line in devices_output.splitlines():
554 match = re.search(DEVICE_FINDER_REGEX, line)
555 if match:
556 serial = match.group('SERIAL')
557 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
558 serial = DEVICE_NO_SERIAL_TAG
559 logging.debug('Found Device: %s', serial)
560 devices.append(serial)
561 return devices
562
563
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700564 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700565 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700566
567 @params use_adb: True to get adb accessible devices. Set to False to
568 get fastboot accessible devices.
569
Kevin Chengd19e6c62015-10-28 16:39:39 -0700570 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700571 """
572 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300573 result = self.adb_run('devices').stdout
574 if self.adb_serial and self.adb_serial not in result:
575 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700576 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300577 result = self.fastboot_run('devices').stdout
578 if (self.fastboot_serial and
579 self.fastboot_serial not in result):
580 # fastboot devices won't list the devices using TCP
581 try:
582 if 'product' in self.fastboot_run('getvar product',
583 timeout=2).stderr:
584 result += '\n%s\tfastboot' % self.fastboot_serial
585 except error.AutotestHostRunError:
586 pass
587 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700588
589
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700590 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700591 """Get a list of devices currently attached to the test station and
592 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700593 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800594 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700595 raise error.AutoservError(
596 'Not given ADB serial but multiple devices detected')
597 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700598
599
600 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700601 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700602 accessible by fastboot command.
603 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700604 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800605 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700606 raise error.AutoservError(
607 'Not given fastboot serial but multiple devices detected')
608 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700609
610
611 def is_up(self, timeout=0, command=ADB_CMD):
612 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700613
614 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700615 @param command: `adb`, the device can be accessed by adb command,
616 or `fastboot`, the device can be accessed by fastboot command.
617 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700618
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700619 @returns True if the device is detectable by given command, False
620 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700621
622 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700623 if command == ADB_CMD:
624 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800625 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800626 # ADB has a device state, if the device is not online, no
627 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800628 # DUT with single device connected may not have adb_serial set.
629 # Therefore, skip checking if serial is in the list of adb devices
630 # if self.adb_serial is not set.
631 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800632 logging.debug('Waiting for device to enter the ready state.')
633 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700634 elif command == FASTBOOT_CMD:
635 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800636 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700637 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700638 raise NotImplementedError('Mode %s is not supported' % command)
639
640 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700641
642
643 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700644 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700645
646 Called as the test ends. Will return the device to USB mode and kill
647 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700648 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800649 # TODO(sbasi) Originally, we would kill the server after each test to
650 # reduce the opportunity for bad server state to hang around.
651 # Unfortunately, there is a period of time after each kill during which
652 # the Android device becomes unusable, and if we start the next test
653 # too quickly, we'll get an error complaining about no ADB device
654 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700655 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800656 # |close| the associated teststation as well.
657 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700658 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700659
660
661 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700662 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700663
664 @param message String message to log into syslog
665 @param tag String tag prefix for syslog
666
667 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700668 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700669
670
671 def get_autodir(self):
672 """Return the directory to install autotest for client side tests."""
673 return '/data/autotest'
674
Kevin Cheng018db352015-09-20 02:22:08 -0700675
Kris Rambishde8f9d12015-12-16 12:42:41 -0800676 def is_device_ready(self):
677 """Return the if the device is ready for ADB commands."""
678 dev_state = self.adb_run('get-state').stdout.strip()
679 logging.debug('Current device state: %s', dev_state)
680 return dev_state == 'device'
681
682
Kevin Chengd19e6c62015-10-28 16:39:39 -0700683 def verify_connectivity(self):
684 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800685 if not self.is_device_ready():
686 raise error.AutoservHostError('device state is not in the '
687 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700688
689
Simran Basid3ba3fb2015-09-11 14:35:07 -0700690 def verify_software(self):
691 """Verify working software on an adb_host.
692
Simran Basi38f7ddf2015-09-18 12:25:03 -0700693 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700694 """
Dan Shiab999722015-12-04 14:27:08 -0800695 # Check if adb and fastboot are present.
696 self.teststation.run('which adb')
697 self.teststation.run('which fastboot')
698 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700699
Kevin Cheng018db352015-09-20 02:22:08 -0700700
Simran Basid3ba3fb2015-09-11 14:35:07 -0700701 def verify_job_repo_url(self, tag=''):
702 """Make sure job_repo_url of this host is valid.
703
Simran Basi38f7ddf2015-09-18 12:25:03 -0700704 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700705
706 @param tag: The tag from the server job, in the format
707 <job_id>-<user>/<hostname>, or <hostless> for a server job.
708 """
709 return
Kevin Cheng018db352015-09-20 02:22:08 -0700710
711
Simran Basibeb2bb22016-02-03 15:25:48 -0800712 def repair(self):
713 """Attempt to get the DUT to pass `self.verify()`."""
714 try:
715 self.ensure_adb_mode(timeout=30)
716 return
717 except error.AutoservError as e:
718 logging.error(e)
719 logging.debug('Verifying the device is accessible via fastboot.')
720 self.ensure_bootloader_mode()
721 if not self.job.run_test(
722 'provision_AndroidUpdate', host=self, value=None,
723 force=True, repair=True):
724 raise error.AutoservRepairTotalFailure(
725 'Unable to repair the device.')
726
727
Simran Basi1b023762015-09-25 12:12:20 -0700728 def send_file(self, source, dest, delete_dest=False,
729 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700730 """Copy files from the drone to the device.
731
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400732 Just a note, there is the possibility the test station is localhost
733 which makes some of these steps redundant (e.g. creating tmp dir) but
734 that scenario will undoubtedly be a development scenario (test station
735 is also the moblab) and not the typical live test running scenario so
736 the redundancy I think is harmless.
737
Kevin Cheng018db352015-09-20 02:22:08 -0700738 @param source: The file/directory on the drone to send to the device.
739 @param dest: The destination path on the device to copy to.
740 @param delete_dest: A flag set to choose whether or not to delete
741 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700742 @param preserve_symlinks: Controls if symlinks on the source will be
743 copied as such on the destination or
744 transformed into the referenced
745 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700746 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700747 # If we need to preserve symlinks, let's check if the source is a
748 # symlink itself and if so, just create it on the device.
749 if preserve_symlinks:
750 symlink_target = None
751 try:
752 symlink_target = os.readlink(source)
753 except OSError:
754 # Guess it's not a symlink.
755 pass
756
757 if symlink_target is not None:
758 # Once we create the symlink, let's get out of here.
759 self.run('ln -s %s %s' % (symlink_target, dest))
760 return
761
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400762 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700763 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400764 src_path = os.path.join(tmp_dir, os.path.basename(dest))
765 # Now copy the file over to the test station so you can reference the
766 # file in the push command.
767 self.teststation.send_file(source, src_path,
768 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700769
770 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400771 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700772
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700773 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700774
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400775 # Cleanup the test station.
776 try:
777 self.teststation.run('rm -rf %s' % tmp_dir)
778 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
779 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700780
781
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700782 def _get_file_info(self, dest):
783 """Get permission and possible symlink info about file on the device.
784
785 These files are on the device so we only have shell commands (via adb)
786 to get the info we want. We'll use 'ls' to get it all.
787
788 @param dest: File to get info about.
789
790 @returns a dict of the file permissions and symlink.
791 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800792 # Grab file info.
793 file_info = self.run_output('ls -l %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700794 symlink = None
795 perms = 0
796 match = re.match(FILE_INFO_REGEX, file_info)
797 if match:
798 # Check if it's a symlink and grab the linked dest if it is.
799 if match.group('TYPE') == 'l':
800 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
801 if symlink_match:
802 symlink = symlink_match.group('SYMLINK')
803
804 # Set the perms.
805 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
806 if perm != '-':
807 perms |= perm_flag
808
809 return {'perms': perms,
810 'symlink': symlink}
811
812
Simran Basi1b023762015-09-25 12:12:20 -0700813 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
814 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700815 """Copy files from the device to the drone.
816
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400817 Just a note, there is the possibility the test station is localhost
818 which makes some of these steps redundant (e.g. creating tmp dir) but
819 that scenario will undoubtedly be a development scenario (test station
820 is also the moblab) and not the typical live test running scenario so
821 the redundancy I think is harmless.
822
Kevin Cheng018db352015-09-20 02:22:08 -0700823 @param source: The file/directory on the device to copy back to the
824 drone.
825 @param dest: The destination path on the drone to copy to.
826 @param delete_dest: A flag set to choose whether or not to delete
827 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700828 @param preserve_perm: Tells get_file() to try to preserve the sources
829 permissions on files and dirs.
830 @param preserve_symlinks: Try to preserve symlinks instead of
831 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700832 """
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400833 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700834 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400835 dest_path = os.path.join(tmp_dir, os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700836
837 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400838 self.teststation.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700839
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700840 source_info = {}
841 if preserve_symlinks or preserve_perm:
842 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700843
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700844 # If we want to preserve symlinks, just create it here, otherwise pull
845 # the file off the device.
846 if preserve_symlinks and source_info['symlink']:
847 os.symlink(source_info['symlink'], dest)
848 else:
Roshan Pius95567142015-11-03 09:56:08 -0800849 self.adb_run('pull %s %s' % (source, dest_path))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700850
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400851 # Copy over the file from the test station and clean up.
852 self.teststation.get_file(dest_path, dest)
853 try:
854 self.teststation.run('rm -rf %s' % tmp_dir)
855 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
856 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700857
858 if preserve_perm:
859 os.chmod(dest, source_info['perms'])
Kevin Cheng018db352015-09-20 02:22:08 -0700860
861
862 def get_release_version(self):
863 """Get the release version from the RELEASE_FILE on the device.
864
865 @returns The release string in the RELEASE_FILE.
866
867 """
868 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700869
870
871 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700872 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700873
Kevin Chengd19e6c62015-10-28 16:39:39 -0700874 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700875
876 @param parent: Parent directory of the returned tmp dir.
877
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700878 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700879 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700880 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
881 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700882 if not parent.startswith(TMP_DIR):
883 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700884 self.run('mkdir -p %s' % parent)
885 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
886 self.tmp_dirs.append(tmp_dir)
887 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700888
889
890 def get_platform(self):
891 """Determine the correct platform label for this host.
892
893 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700894 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700895
896 @returns a string representing this host's platform.
897 """
898 return 'adb'
899
900
Gilad Arnolda76bef02015-09-29 13:55:15 -0700901 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800902 """Get the OS type of the DUT, e.g., android or brillo.
903 """
904 if not self._os_type:
905 if self.run_output('getprop ro.product.brand') == 'Brillo':
906 self._os_type = OS_TYPE_BRILLO
907 else:
908 self._os_type = OS_TYPE_ANDROID
909
910 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700911
912
913 def _forward(self, reverse, args):
914 """Execute a forwarding command.
915
916 @param reverse: Whether this is reverse forwarding (Boolean).
917 @param args: List of command arguments.
918 """
919 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700920 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700921
922
923 def add_forwarding(self, src, dst, reverse=False, rebind=True):
924 """Forward a port between the ADB host and device.
925
926 Port specifications are any strings accepted as such by ADB, for
927 example 'tcp:8080'.
928
929 @param src: Port specification to forward from.
930 @param dst: Port specification to forward to.
931 @param reverse: Do reverse forwarding from device to host (Boolean).
932 @param rebind: Allow rebinding an already bound port (Boolean).
933 """
934 args = []
935 if not rebind:
936 args.append('--no-rebind')
937 args += [src, dst]
938 self._forward(reverse, args)
939
940
941 def remove_forwarding(self, src=None, reverse=False):
942 """Removes forwarding on port.
943
944 @param src: Port specification, or None to remove all forwarding.
945 @param reverse: Whether this is reverse forwarding (Boolean).
946 """
947 args = []
948 if src is None:
949 args.append('--remove-all')
950 else:
951 args += ['--remove', src]
952 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700953
954
xixuan6cf6d2f2016-01-29 15:29:00 -0800955 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700956 """
957 Forwards a port securely through a tunnel process from the server
958 to the DUT for RPC server connection.
959 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
960 to the DUT.
961
962 @param port: remote port on the DUT.
963 @param local_port: local forwarding port.
964
965 @return: the tunnel process.
966 """
967 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800968 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700969
970
xixuan6cf6d2f2016-01-29 15:29:00 -0800971 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700972 """
973 Disconnects a previously forwarded port from the server to the DUT for
974 RPC server connection.
975 Remove the previously added 'ADB forward' rule to forward the RPC
976 packets from the AdbHost to the DUT.
977
978 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -0800979 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -0700980 @param port: remote port on the DUT.
981
982 """
983 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800984 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700985
986
987 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700988 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700989
990 @raise: error.AutoservError if the device failed to reboot into
991 bootloader mode.
992 """
993 if self.is_up(command=FASTBOOT_CMD):
994 return
995 self.adb_run('reboot bootloader')
996 if not self.wait_up(command=FASTBOOT_CMD):
997 raise error.AutoservError(
998 'The device failed to reboot into bootloader mode.')
999
1000
Dan Shie4e807b2015-12-10 09:04:03 -08001001 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001002 """Ensure the device is up and can be accessed by adb command.
1003
Dan Shie4e807b2015-12-10 09:04:03 -08001004 @param timeout: Time limit in seconds before returning even if the host
1005 is not up.
1006
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001007 @raise: error.AutoservError if the device failed to reboot into
1008 adb mode.
1009 """
1010 if self.is_up():
1011 return
Dan Shi04980372016-03-22 10:57:47 -07001012 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1013 # check if the device is in adb mode.
1014 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001015 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001016 raise error.AutoservError(
1017 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001018 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001019
1020
1021 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001022 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001023 """Get the Android build information from the build url.
1024
1025 @param build_url: The url to use for downloading Android artifacts.
1026 pattern: http://$devserver:###/static/branch/target/build_id
1027
Dan Shi6450e142016-03-11 11:52:20 -08001028 @return: A dictionary of build information, including keys:
1029 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001030 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001031 """
Dan Shiab999722015-12-04 14:27:08 -08001032 if not build_url:
1033 raise AndroidInstallError('Need build_url to download image files.')
1034
1035 try:
1036 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001037 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001038 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001039 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001040 match.group('BUILD_TYPE'))),
1041 'build_id': match.group('BUILD_ID')}
1042 except (AttributeError, IndexError, ValueError) as e:
1043 raise AndroidInstallError(
1044 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001045
1046
Dan Shia2872172015-10-31 01:16:51 -07001047 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001048 def download_file(self, build_url, file, dest_dir, unzip=False,
1049 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001050 """Download the given file from the build url.
1051
1052 @param build_url: The url to use for downloading Android artifacts.
1053 pattern: http://$devserver:###/static/branch/target/build_id
1054 @param file: Name of the file to be downloaded, e.g., boot.img.
1055 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001056 @param unzip: If True, unzip the downloaded file.
1057 @param unzip_dest: Location to unzip the downloaded file to. If not
1058 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001059 """
Dan Shidb0366c2016-02-19 10:36:18 -08001060 # Append the file name to the url if build_url is linked to the folder
1061 # containing the file.
1062 if not build_url.endswith('/%s' % file):
1063 src_url = os.path.join(build_url, file)
1064 else:
1065 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001066 dest_file = os.path.join(dest_dir, file)
1067 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001068 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001069 if unzip:
1070 unzip_dest = unzip_dest or dest_dir
1071 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1072 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001073 except:
1074 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001075 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001076 raise
1077
1078
Dan Shiab999722015-12-04 14:27:08 -08001079 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001080 """Download required image files from the given build_url to a local
1081 directory in the machine runs fastboot command.
1082
1083 @param build_url: The url to use for downloading Android artifacts.
1084 pattern: http://$devserver:###/static/branch/target/build_id
1085
1086 @return: Path to the directory contains image files.
1087 """
Dan Shi08ff1282016-02-18 19:51:16 -08001088 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001089
1090 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001091 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001092
1093 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001094 self.download_file(build_url, zipped_image_file, image_dir,
1095 unzip=True)
1096 for image_file in ANDROID_STANDALONE_IMAGES:
Dan Shidb0366c2016-02-19 10:36:18 -08001097 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001098
Dan Shia2872172015-10-31 01:16:51 -07001099 return image_dir
1100 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001101 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001102 raise
1103
1104
Dan Shiab999722015-12-04 14:27:08 -08001105 def stage_brillo_image_files(self, build_url):
1106 """Download required brillo image files from the given build_url to a
1107 local directory in the machine runs fastboot command.
1108
1109 @param build_url: The url to use for downloading Android artifacts.
1110 pattern: http://$devserver:###/static/branch/target/build_id
1111
1112 @return: Path to the directory contains image files.
1113 """
Dan Shi08ff1282016-02-18 19:51:16 -08001114 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001115
1116 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1117 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1118 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001119
1120 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001121 self.download_file(build_url, zipped_image_file, image_dir,
1122 unzip=True)
1123 self.download_file(build_url, vendor_partitions_file, image_dir,
1124 unzip=True,
1125 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001126 return image_dir
1127 except:
1128 self.teststation.run('rm -rf %s' % image_dir)
1129 raise
1130
1131
Simran Basibeb2bb22016-02-03 15:25:48 -08001132 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001133 """Stage a build on a devserver and return the build_url and devserver.
1134
1135 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001136
Dan Shi225b9042015-11-18 10:25:21 -08001137 @returns a tuple with an update URL like:
1138 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1139 and the devserver instance.
1140 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001141 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001142 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001143 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1144 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001145 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001146 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001147 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001148 devserver.trigger_download(target, build_id, branch,
1149 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001150 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001151
1152
Dan Shie4e807b2015-12-10 09:04:03 -08001153 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001154 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001155 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001156
1157 Following are the steps used here to provision an android device:
1158 1. If build_local_path is not set, download the image zip file, e.g.,
1159 shamu-img-2284311.zip, unzip it.
1160 2. Run fastboot to install following artifacts:
1161 bootloader, radio, boot, system, vendor(only if exists)
1162
1163 Repair is not supported for Android devices yet.
1164
1165 @param build_url: The url to use for downloading Android artifacts.
1166 pattern: http://$devserver:###/static/$build
1167 @param build_local_path: The path to a local folder that contains the
1168 image files needed to provision the device. Note that the folder
1169 is in the machine running adb command, rather than the drone.
1170 @param wipe: If true, userdata will be wiped before flashing.
1171 @param flash_all: If True, all img files found in img_path will be
1172 flashed. Otherwise, only boot and system are flashed.
1173
1174 @raises AndroidInstallError if any error occurs.
1175 """
Dan Shia2872172015-10-31 01:16:51 -07001176 # If the build is not staged in local server yet, clean up the temp
1177 # folder used to store image files after the provision is completed.
1178 delete_build_folder = bool(not build_local_path)
1179
1180 try:
1181 # Download image files needed for provision to a local directory.
1182 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001183 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001184
1185 # Device needs to be in bootloader mode for flashing.
1186 self.ensure_bootloader_mode()
1187
1188 if wipe:
Dan Shie4e807b2015-12-10 09:04:03 -08001189 self.fastboot_run('-w')
Dan Shia2872172015-10-31 01:16:51 -07001190
1191 # Get all *.img file in the build_local_path.
1192 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001193 image_files = self.teststation.run(
1194 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001195 images = dict([(os.path.basename(f), f) for f in image_files])
1196 for image, image_file in images.items():
1197 if image not in ANDROID_IMAGES:
1198 continue
1199 logging.info('Flashing %s...', image_file)
Dan Shi70c30192016-03-22 23:14:12 -07001200 self.fastboot_run('-S 256M flash %s %s' %
Dan Shie9913d32016-03-09 14:17:26 -08001201 (image[:-4], image_file))
Dan Shia2872172015-10-31 01:16:51 -07001202 if image == ANDROID_BOOTLOADER:
1203 self.fastboot_run('reboot-bootloader')
1204 self.wait_up(command=FASTBOOT_CMD)
1205 except Exception as e:
1206 logging.error('Install Android build failed with error: %s', e)
1207 # Re-raise the exception with type of AndroidInstallError.
1208 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1209 finally:
1210 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001211 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001212 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1213 DEFAULT_WAIT_UP_TIME_SECONDS)
1214 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001215 logging.info('Successfully installed Android build staged at %s.',
1216 build_url)
1217
1218
Dan Shiab999722015-12-04 14:27:08 -08001219 def install_brillo(self, build_url, build_local_path=None):
1220 """Install the Brillo DUT.
1221
1222 Following are the steps used here to provision an android device:
1223 1. If build_local_path is not set, download the image zip file, e.g.,
1224 dragonboard-img-123456.zip, unzip it. And download the vendor
1225 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1226 unzip it to vendor folder.
1227 2. Run provision_device script to install OS images and vendor
1228 partitions.
1229
1230 @param build_url: The url to use for downloading Android artifacts.
1231 pattern: http://$devserver:###/static/$build
1232 @param build_local_path: The path to a local folder that contains the
1233 image files needed to provision the device. Note that the folder
1234 is in the machine running adb command, rather than the drone.
1235
1236 @raises AndroidInstallError if any error occurs.
1237 """
1238 # If the build is not staged in local server yet, clean up the temp
1239 # folder used to store image files after the provision is completed.
1240 delete_build_folder = bool(not build_local_path)
1241
Dan Shiab999722015-12-04 14:27:08 -08001242 try:
1243 # Download image files needed for provision to a local directory.
1244 if not build_local_path:
1245 build_local_path = self.stage_brillo_image_files(build_url)
1246
1247 # Device needs to be in bootloader mode for flashing.
1248 self.ensure_bootloader_mode()
1249
1250 # Run provision_device command to install image files and vendor
1251 # partitions.
1252 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1253 cmd = (BRILLO_PROVISION_CMD %
1254 {'os_image_dir': build_local_path,
1255 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001256 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001257 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001258 self.teststation.run(cmd)
1259 except Exception as e:
1260 logging.error('Install Brillo build failed with error: %s', e)
1261 # Re-raise the exception with type of AndroidInstallError.
1262 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1263 finally:
1264 if delete_build_folder:
1265 self.teststation.run('rm -rf %s' % build_local_path)
1266 self.ensure_adb_mode()
1267 logging.info('Successfully installed Android build staged at %s.',
1268 build_url)
1269
1270
Dan Shibe3636a2016-02-14 22:48:01 -08001271 @property
1272 def job_repo_url_attribute(self):
1273 """Get the host attribute name for job_repo_url, which should append the
1274 adb serial.
1275 """
1276 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1277
1278
Dan Shie4e807b2015-12-10 09:04:03 -08001279 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001280 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001281 """Install the DUT.
1282
1283 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001284 pattern: http://$devserver:###/static/$build. If build_url is
1285 set to None, the code may try _parser.options.image to do the
1286 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001287 @param build_local_path: The path to a local directory that contains the
1288 image files needed to provision the device.
1289 @param wipe: If true, userdata will be wiped before flashing.
1290 @param flash_all: If True, all img files found in img_path will be
1291 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001292
Dan Shibe3636a2016-02-14 22:48:01 -08001293 @returns A tuple of (image_name, host_attributes).
1294 image_name is the name of image installed, e.g.,
1295 git_mnc-release/shamu-userdebug/1234
1296 host_attributes is a dictionary of (attribute, value), which
1297 can be saved to afe_host_attributes table in database. This
1298 method returns a dictionary with a single entry of
1299 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1300 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001301 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001302 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001303 if not build_url and self._parser.options.image:
1304 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001305 self._parser.options.image, os_type=os_type)
1306 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001307 self.install_android(
1308 build_url=build_url, build_local_path=build_local_path,
1309 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001310 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001311 self.install_brillo(
1312 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001313 else:
1314 raise error.InstallError(
1315 'Installation of os type %s is not supported.' %
1316 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001317 return (build_url.split('static/')[-1],
1318 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001319
1320
1321 def list_files_glob(self, path_glob):
1322 """Get a list of files on the device given glob pattern path.
1323
1324 @param path_glob: The path glob that we want to return the list of
1325 files that match the glob. Relative paths will not work as
1326 expected. Supply an absolute path to get the list of files
1327 you're hoping for.
1328
1329 @returns List of files that match the path_glob.
1330 """
1331 # This is just in case path_glob has no path separator.
1332 base_path = os.path.dirname(path_glob) or '.'
1333 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001334 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001335 if result.exit_status != 0:
1336 return []
1337 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001338
1339
Dan Shidb0366c2016-02-19 10:36:18 -08001340 def install_apk(self, apk, force_reinstall=False):
Kevin Cheng31355942016-01-05 14:23:35 -08001341 """Install the specified apk.
1342
1343 This will install the apk and override it if it's already installed and
1344 will also allow for downgraded apks.
1345
1346 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001347 @param force_reinstall: True to reinstall the apk even if it's already
1348 installed. Default is set to False.
1349
1350 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001351 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001352 client_utils.poll_for_condition(
1353 lambda: self.run('pm list packages',
1354 ignore_status=True).exit_status == 0,
1355 timeout=120)
Dan Shi043c45b2016-04-11 17:18:49 -07001356 client_utils.poll_for_condition(
1357 lambda: self.run('service list | grep mount',
1358 ignore_status=True).exit_status == 0,
1359 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001360 return self.adb_run('install %s -d %s' %
1361 ('-r' if force_reinstall else '', apk))
1362
1363
1364 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1365 def _confirm_apk_installed(self, package_name):
1366 """Confirm if apk is already installed with the given name.
1367
1368 `pm list packages` command is not reliable some time. The retry helps to
1369 reduce the chance of false negative.
1370
1371 @param package_name: Name of the package, e.g., com.android.phone.
1372
1373 @raise AutoservRunError: If the package is not found or pm list command
1374 failed for any reason.
1375 """
1376 name = 'package:%s' % package_name
1377 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1378
1379
1380 def is_apk_installed(self, package_name):
1381 """Check if apk is already installed with the given name.
1382
1383 @param package_name: Name of the package, e.g., com.android.phone.
1384
1385 @return: True if package is installed. False otherwise.
1386 """
1387 try:
1388 self._confirm_apk_installed(package_name)
1389 return True
1390 except:
1391 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001392
1393
1394 def get_attributes_to_clear_before_provision(self):
1395 """Get a list of attributes to be cleared before machine_install starts.
1396 """
1397 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001398
1399
1400 def get_labels(self):
1401 """Return a list of the labels gathered from the devices connected.
1402
1403 @return: A list of strings that denote the labels from all the devices
1404 connected.
1405 """
1406 return self.labels.get_labels(self)
1407
1408
1409 def update_labels(self):
1410 """Update the labels for this testbed."""
1411 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001412
1413
1414 def stage_server_side_package(self, image=None):
1415 """Stage autotest server-side package on devserver.
1416
1417 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1418
1419 @return: A url to the autotest server-side package. Return None if
1420 server-side package is not supported.
1421 @raise: error.AutoservError if fail to locate the build to test with.
1422 """
1423 if image:
1424 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1425 else:
1426 job_repo_url = afe_utils.get_host_attribute(
1427 self, self.job_repo_url_attribute)
1428 if job_repo_url:
1429 devserver_url, image = (
1430 tools.get_devserver_build_from_package_url(
1431 job_repo_url, True))
1432 ds = dev_server.AndroidBuildServer(devserver_url)
1433 else:
1434 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1435 if not labels:
1436 raise error.AutoservError(
1437 'Failed to stage server-side package. The host has '
1438 'no job_report_url attribute or version label.')
1439 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1440 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1441
1442 branch, target, build_id = utils.parse_launch_control_build(image)
1443 build_target, _ = utils.parse_launch_control_target(target)
1444
1445 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1446 # packaging is not supported.
1447 try:
1448 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1449 logging.warn('Build %s is older than %s. Server side packaging '
1450 'is disabled.', image,
1451 self.MIN_VERSION_SUPPORT_SSP)
1452 return None
1453 except ValueError:
1454 logging.warn('Failed to compare build id in %s with the minimum '
1455 'version that supports server side packaging. Server '
1456 'side packaging is disabled.', image)
1457 return None
1458
1459 ds.stage_artifacts(target, build_id, branch,
1460 artifacts=['autotest_server_package'])
1461 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1462 {'build_target': build_target,
1463 'build_id': build_id})
1464 return '%s/static/%s/%s' % (ds.url(), image,
1465 autotest_server_package_name)