blob: dd619905e0b41a0ff39c348d565b5284fbded53b [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
Ralph Nathanb45eb672015-11-18 20:04:39 -0800520 def remount(self):
521 """Remounts paritions on the device read-write.
522
523 Specifically, the /system, /vendor (if present) and /oem (if present)
524 partitions on the device are remounted read-write.
525 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800526 self.adb_run('remount')
527
528
Kevin Cheng549beb42015-11-18 11:42:25 -0800529 @staticmethod
530 def parse_device_serials(devices_output):
531 """Return a list of parsed serials from the output.
532
533 @param devices_output: Output from either an adb or fastboot command.
534
535 @returns List of device serials
536 """
537 devices = []
538 for line in devices_output.splitlines():
539 match = re.search(DEVICE_FINDER_REGEX, line)
540 if match:
541 serial = match.group('SERIAL')
542 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
543 serial = DEVICE_NO_SERIAL_TAG
544 logging.debug('Found Device: %s', serial)
545 devices.append(serial)
546 return devices
547
548
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700549 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700550 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700551
552 @params use_adb: True to get adb accessible devices. Set to False to
553 get fastboot accessible devices.
554
Kevin Chengd19e6c62015-10-28 16:39:39 -0700555 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700556 """
557 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300558 result = self.adb_run('devices').stdout
559 if self.adb_serial and self.adb_serial not in result:
560 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700561 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300562 result = self.fastboot_run('devices').stdout
563 if (self.fastboot_serial and
564 self.fastboot_serial not in result):
565 # fastboot devices won't list the devices using TCP
566 try:
567 if 'product' in self.fastboot_run('getvar product',
568 timeout=2).stderr:
569 result += '\n%s\tfastboot' % self.fastboot_serial
570 except error.AutotestHostRunError:
571 pass
572 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700573
574
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700575 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700576 """Get a list of devices currently attached to the test station and
577 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700578 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800579 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700580 raise error.AutoservError(
581 'Not given ADB serial but multiple devices detected')
582 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700583
584
585 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700586 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700587 accessible by fastboot command.
588 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700589 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800590 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700591 raise error.AutoservError(
592 'Not given fastboot serial but multiple devices detected')
593 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700594
595
596 def is_up(self, timeout=0, command=ADB_CMD):
597 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700598
599 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700600 @param command: `adb`, the device can be accessed by adb command,
601 or `fastboot`, the device can be accessed by fastboot command.
602 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700603
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700604 @returns True if the device is detectable by given command, False
605 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700606
607 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700608 if command == ADB_CMD:
609 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800610 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800611 # ADB has a device state, if the device is not online, no
612 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800613 # DUT with single device connected may not have adb_serial set.
614 # Therefore, skip checking if serial is in the list of adb devices
615 # if self.adb_serial is not set.
616 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800617 logging.debug('Waiting for device to enter the ready state.')
618 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700619 elif command == FASTBOOT_CMD:
620 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800621 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700622 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700623 raise NotImplementedError('Mode %s is not supported' % command)
624
625 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700626
627
628 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700629 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700630
631 Called as the test ends. Will return the device to USB mode and kill
632 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700633 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800634 # TODO(sbasi) Originally, we would kill the server after each test to
635 # reduce the opportunity for bad server state to hang around.
636 # Unfortunately, there is a period of time after each kill during which
637 # the Android device becomes unusable, and if we start the next test
638 # too quickly, we'll get an error complaining about no ADB device
639 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700640 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800641 # |close| the associated teststation as well.
642 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700643 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700644
645
646 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700647 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700648
649 @param message String message to log into syslog
650 @param tag String tag prefix for syslog
651
652 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700653 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700654
655
656 def get_autodir(self):
657 """Return the directory to install autotest for client side tests."""
658 return '/data/autotest'
659
Kevin Cheng018db352015-09-20 02:22:08 -0700660
Kris Rambishde8f9d12015-12-16 12:42:41 -0800661 def is_device_ready(self):
662 """Return the if the device is ready for ADB commands."""
663 dev_state = self.adb_run('get-state').stdout.strip()
664 logging.debug('Current device state: %s', dev_state)
665 return dev_state == 'device'
666
667
Kevin Chengd19e6c62015-10-28 16:39:39 -0700668 def verify_connectivity(self):
669 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800670 if not self.is_device_ready():
671 raise error.AutoservHostError('device state is not in the '
672 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700673
674
Simran Basid3ba3fb2015-09-11 14:35:07 -0700675 def verify_software(self):
676 """Verify working software on an adb_host.
677
Simran Basi38f7ddf2015-09-18 12:25:03 -0700678 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700679 """
Dan Shiab999722015-12-04 14:27:08 -0800680 # Check if adb and fastboot are present.
681 self.teststation.run('which adb')
682 self.teststation.run('which fastboot')
683 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700684
Kevin Cheng018db352015-09-20 02:22:08 -0700685
Simran Basid3ba3fb2015-09-11 14:35:07 -0700686 def verify_job_repo_url(self, tag=''):
687 """Make sure job_repo_url of this host is valid.
688
Simran Basi38f7ddf2015-09-18 12:25:03 -0700689 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700690
691 @param tag: The tag from the server job, in the format
692 <job_id>-<user>/<hostname>, or <hostless> for a server job.
693 """
694 return
Kevin Cheng018db352015-09-20 02:22:08 -0700695
696
Simran Basibeb2bb22016-02-03 15:25:48 -0800697 def repair(self):
698 """Attempt to get the DUT to pass `self.verify()`."""
699 try:
700 self.ensure_adb_mode(timeout=30)
701 return
702 except error.AutoservError as e:
703 logging.error(e)
704 logging.debug('Verifying the device is accessible via fastboot.')
705 self.ensure_bootloader_mode()
706 if not self.job.run_test(
707 'provision_AndroidUpdate', host=self, value=None,
708 force=True, repair=True):
709 raise error.AutoservRepairTotalFailure(
710 'Unable to repair the device.')
711
712
Simran Basi1b023762015-09-25 12:12:20 -0700713 def send_file(self, source, dest, delete_dest=False,
714 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700715 """Copy files from the drone to the device.
716
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400717 Just a note, there is the possibility the test station is localhost
718 which makes some of these steps redundant (e.g. creating tmp dir) but
719 that scenario will undoubtedly be a development scenario (test station
720 is also the moblab) and not the typical live test running scenario so
721 the redundancy I think is harmless.
722
Kevin Cheng018db352015-09-20 02:22:08 -0700723 @param source: The file/directory on the drone to send to the device.
724 @param dest: The destination path on the device to copy to.
725 @param delete_dest: A flag set to choose whether or not to delete
726 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700727 @param preserve_symlinks: Controls if symlinks on the source will be
728 copied as such on the destination or
729 transformed into the referenced
730 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700731 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700732 # If we need to preserve symlinks, let's check if the source is a
733 # symlink itself and if so, just create it on the device.
734 if preserve_symlinks:
735 symlink_target = None
736 try:
737 symlink_target = os.readlink(source)
738 except OSError:
739 # Guess it's not a symlink.
740 pass
741
742 if symlink_target is not None:
743 # Once we create the symlink, let's get out of here.
744 self.run('ln -s %s %s' % (symlink_target, dest))
745 return
746
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400747 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700748 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400749 src_path = os.path.join(tmp_dir, os.path.basename(dest))
750 # Now copy the file over to the test station so you can reference the
751 # file in the push command.
752 self.teststation.send_file(source, src_path,
753 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700754
755 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400756 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700757
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700758 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700759
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400760 # Cleanup the test station.
761 try:
762 self.teststation.run('rm -rf %s' % tmp_dir)
763 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
764 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700765
766
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700767 def _get_file_info(self, dest):
768 """Get permission and possible symlink info about file on the device.
769
770 These files are on the device so we only have shell commands (via adb)
771 to get the info we want. We'll use 'ls' to get it all.
772
773 @param dest: File to get info about.
774
775 @returns a dict of the file permissions and symlink.
776 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800777 # Grab file info.
778 file_info = self.run_output('ls -l %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700779 symlink = None
780 perms = 0
781 match = re.match(FILE_INFO_REGEX, file_info)
782 if match:
783 # Check if it's a symlink and grab the linked dest if it is.
784 if match.group('TYPE') == 'l':
785 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
786 if symlink_match:
787 symlink = symlink_match.group('SYMLINK')
788
789 # Set the perms.
790 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
791 if perm != '-':
792 perms |= perm_flag
793
794 return {'perms': perms,
795 'symlink': symlink}
796
797
Simran Basi1b023762015-09-25 12:12:20 -0700798 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
799 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700800 """Copy files from the device to the drone.
801
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400802 Just a note, there is the possibility the test station is localhost
803 which makes some of these steps redundant (e.g. creating tmp dir) but
804 that scenario will undoubtedly be a development scenario (test station
805 is also the moblab) and not the typical live test running scenario so
806 the redundancy I think is harmless.
807
Kevin Cheng018db352015-09-20 02:22:08 -0700808 @param source: The file/directory on the device to copy back to the
809 drone.
810 @param dest: The destination path on the drone to copy to.
811 @param delete_dest: A flag set to choose whether or not to delete
812 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700813 @param preserve_perm: Tells get_file() to try to preserve the sources
814 permissions on files and dirs.
815 @param preserve_symlinks: Try to preserve symlinks instead of
816 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700817 """
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400818 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700819 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400820 dest_path = os.path.join(tmp_dir, os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700821
822 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400823 self.teststation.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700824
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700825 source_info = {}
826 if preserve_symlinks or preserve_perm:
827 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700828
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700829 # If we want to preserve symlinks, just create it here, otherwise pull
830 # the file off the device.
831 if preserve_symlinks and source_info['symlink']:
832 os.symlink(source_info['symlink'], dest)
833 else:
Roshan Pius95567142015-11-03 09:56:08 -0800834 self.adb_run('pull %s %s' % (source, dest_path))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700835
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400836 # Copy over the file from the test station and clean up.
837 self.teststation.get_file(dest_path, dest)
838 try:
839 self.teststation.run('rm -rf %s' % tmp_dir)
840 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
841 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700842
843 if preserve_perm:
844 os.chmod(dest, source_info['perms'])
Kevin Cheng018db352015-09-20 02:22:08 -0700845
846
847 def get_release_version(self):
848 """Get the release version from the RELEASE_FILE on the device.
849
850 @returns The release string in the RELEASE_FILE.
851
852 """
853 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700854
855
856 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700857 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700858
Kevin Chengd19e6c62015-10-28 16:39:39 -0700859 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700860
861 @param parent: Parent directory of the returned tmp dir.
862
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700863 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700864 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700865 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
866 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700867 if not parent.startswith(TMP_DIR):
868 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700869 self.run('mkdir -p %s' % parent)
870 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
871 self.tmp_dirs.append(tmp_dir)
872 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700873
874
875 def get_platform(self):
876 """Determine the correct platform label for this host.
877
878 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700879 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700880
881 @returns a string representing this host's platform.
882 """
883 return 'adb'
884
885
Gilad Arnolda76bef02015-09-29 13:55:15 -0700886 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800887 """Get the OS type of the DUT, e.g., android or brillo.
888 """
889 if not self._os_type:
890 if self.run_output('getprop ro.product.brand') == 'Brillo':
891 self._os_type = OS_TYPE_BRILLO
892 else:
893 self._os_type = OS_TYPE_ANDROID
894
895 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700896
897
898 def _forward(self, reverse, args):
899 """Execute a forwarding command.
900
901 @param reverse: Whether this is reverse forwarding (Boolean).
902 @param args: List of command arguments.
903 """
904 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700905 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700906
907
908 def add_forwarding(self, src, dst, reverse=False, rebind=True):
909 """Forward a port between the ADB host and device.
910
911 Port specifications are any strings accepted as such by ADB, for
912 example 'tcp:8080'.
913
914 @param src: Port specification to forward from.
915 @param dst: Port specification to forward to.
916 @param reverse: Do reverse forwarding from device to host (Boolean).
917 @param rebind: Allow rebinding an already bound port (Boolean).
918 """
919 args = []
920 if not rebind:
921 args.append('--no-rebind')
922 args += [src, dst]
923 self._forward(reverse, args)
924
925
926 def remove_forwarding(self, src=None, reverse=False):
927 """Removes forwarding on port.
928
929 @param src: Port specification, or None to remove all forwarding.
930 @param reverse: Whether this is reverse forwarding (Boolean).
931 """
932 args = []
933 if src is None:
934 args.append('--remove-all')
935 else:
936 args += ['--remove', src]
937 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700938
939
xixuan6cf6d2f2016-01-29 15:29:00 -0800940 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700941 """
942 Forwards a port securely through a tunnel process from the server
943 to the DUT for RPC server connection.
944 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
945 to the DUT.
946
947 @param port: remote port on the DUT.
948 @param local_port: local forwarding port.
949
950 @return: the tunnel process.
951 """
952 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800953 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700954
955
xixuan6cf6d2f2016-01-29 15:29:00 -0800956 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700957 """
958 Disconnects a previously forwarded port from the server to the DUT for
959 RPC server connection.
960 Remove the previously added 'ADB forward' rule to forward the RPC
961 packets from the AdbHost to the DUT.
962
963 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -0800964 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -0700965 @param port: remote port on the DUT.
966
967 """
968 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800969 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700970
971
972 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700973 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700974
975 @raise: error.AutoservError if the device failed to reboot into
976 bootloader mode.
977 """
978 if self.is_up(command=FASTBOOT_CMD):
979 return
980 self.adb_run('reboot bootloader')
981 if not self.wait_up(command=FASTBOOT_CMD):
982 raise error.AutoservError(
983 'The device failed to reboot into bootloader mode.')
984
985
Dan Shie4e807b2015-12-10 09:04:03 -0800986 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700987 """Ensure the device is up and can be accessed by adb command.
988
Dan Shie4e807b2015-12-10 09:04:03 -0800989 @param timeout: Time limit in seconds before returning even if the host
990 is not up.
991
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700992 @raise: error.AutoservError if the device failed to reboot into
993 adb mode.
994 """
995 if self.is_up():
996 return
Dan Shi04980372016-03-22 10:57:47 -0700997 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
998 # check if the device is in adb mode.
999 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001000 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001001 raise error.AutoservError(
1002 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001003 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001004
1005
1006 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001007 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001008 """Get the Android build information from the build url.
1009
1010 @param build_url: The url to use for downloading Android artifacts.
1011 pattern: http://$devserver:###/static/branch/target/build_id
1012
Dan Shi6450e142016-03-11 11:52:20 -08001013 @return: A dictionary of build information, including keys:
1014 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001015 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001016 """
Dan Shiab999722015-12-04 14:27:08 -08001017 if not build_url:
1018 raise AndroidInstallError('Need build_url to download image files.')
1019
1020 try:
1021 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001022 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001023 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001024 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001025 match.group('BUILD_TYPE'))),
1026 'build_id': match.group('BUILD_ID')}
1027 except (AttributeError, IndexError, ValueError) as e:
1028 raise AndroidInstallError(
1029 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001030
1031
Dan Shia2872172015-10-31 01:16:51 -07001032 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001033 def download_file(self, build_url, file, dest_dir, unzip=False,
1034 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001035 """Download the given file from the build url.
1036
1037 @param build_url: The url to use for downloading Android artifacts.
1038 pattern: http://$devserver:###/static/branch/target/build_id
1039 @param file: Name of the file to be downloaded, e.g., boot.img.
1040 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001041 @param unzip: If True, unzip the downloaded file.
1042 @param unzip_dest: Location to unzip the downloaded file to. If not
1043 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001044 """
Dan Shidb0366c2016-02-19 10:36:18 -08001045 # Append the file name to the url if build_url is linked to the folder
1046 # containing the file.
1047 if not build_url.endswith('/%s' % file):
1048 src_url = os.path.join(build_url, file)
1049 else:
1050 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001051 dest_file = os.path.join(dest_dir, file)
1052 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001053 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001054 if unzip:
1055 unzip_dest = unzip_dest or dest_dir
1056 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1057 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001058 except:
1059 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001060 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001061 raise
1062
1063
Dan Shiab999722015-12-04 14:27:08 -08001064 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001065 """Download required image files from the given build_url to a local
1066 directory in the machine runs fastboot command.
1067
1068 @param build_url: The url to use for downloading Android artifacts.
1069 pattern: http://$devserver:###/static/branch/target/build_id
1070
1071 @return: Path to the directory contains image files.
1072 """
Dan Shi08ff1282016-02-18 19:51:16 -08001073 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001074
1075 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001076 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001077
1078 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001079 self.download_file(build_url, zipped_image_file, image_dir,
1080 unzip=True)
1081 for image_file in ANDROID_STANDALONE_IMAGES:
Dan Shidb0366c2016-02-19 10:36:18 -08001082 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001083
Dan Shia2872172015-10-31 01:16:51 -07001084 return image_dir
1085 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001086 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001087 raise
1088
1089
Dan Shiab999722015-12-04 14:27:08 -08001090 def stage_brillo_image_files(self, build_url):
1091 """Download required brillo image files from the given build_url to a
1092 local directory in the machine runs fastboot command.
1093
1094 @param build_url: The url to use for downloading Android artifacts.
1095 pattern: http://$devserver:###/static/branch/target/build_id
1096
1097 @return: Path to the directory contains image files.
1098 """
Dan Shi08ff1282016-02-18 19:51:16 -08001099 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001100
1101 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1102 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1103 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001104
1105 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001106 self.download_file(build_url, zipped_image_file, image_dir,
1107 unzip=True)
1108 self.download_file(build_url, vendor_partitions_file, image_dir,
1109 unzip=True,
1110 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001111 return image_dir
1112 except:
1113 self.teststation.run('rm -rf %s' % image_dir)
1114 raise
1115
1116
Simran Basibeb2bb22016-02-03 15:25:48 -08001117 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001118 """Stage a build on a devserver and return the build_url and devserver.
1119
1120 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001121
Dan Shi225b9042015-11-18 10:25:21 -08001122 @returns a tuple with an update URL like:
1123 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1124 and the devserver instance.
1125 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001126 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001127 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001128 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1129 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001130 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001131 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001132 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001133 devserver.trigger_download(target, build_id, branch,
1134 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001135 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001136
1137
Dan Shie4e807b2015-12-10 09:04:03 -08001138 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001139 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001140 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001141
1142 Following are the steps used here to provision an android device:
1143 1. If build_local_path is not set, download the image zip file, e.g.,
1144 shamu-img-2284311.zip, unzip it.
1145 2. Run fastboot to install following artifacts:
1146 bootloader, radio, boot, system, vendor(only if exists)
1147
1148 Repair is not supported for Android devices yet.
1149
1150 @param build_url: The url to use for downloading Android artifacts.
1151 pattern: http://$devserver:###/static/$build
1152 @param build_local_path: The path to a local folder that contains the
1153 image files needed to provision the device. Note that the folder
1154 is in the machine running adb command, rather than the drone.
1155 @param wipe: If true, userdata will be wiped before flashing.
1156 @param flash_all: If True, all img files found in img_path will be
1157 flashed. Otherwise, only boot and system are flashed.
1158
1159 @raises AndroidInstallError if any error occurs.
1160 """
Dan Shia2872172015-10-31 01:16:51 -07001161 # If the build is not staged in local server yet, clean up the temp
1162 # folder used to store image files after the provision is completed.
1163 delete_build_folder = bool(not build_local_path)
1164
1165 try:
1166 # Download image files needed for provision to a local directory.
1167 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001168 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001169
1170 # Device needs to be in bootloader mode for flashing.
1171 self.ensure_bootloader_mode()
1172
1173 if wipe:
Dan Shie4e807b2015-12-10 09:04:03 -08001174 self.fastboot_run('-w')
Dan Shia2872172015-10-31 01:16:51 -07001175
1176 # Get all *.img file in the build_local_path.
1177 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001178 image_files = self.teststation.run(
1179 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001180 images = dict([(os.path.basename(f), f) for f in image_files])
1181 for image, image_file in images.items():
1182 if image not in ANDROID_IMAGES:
1183 continue
1184 logging.info('Flashing %s...', image_file)
Dan Shi70c30192016-03-22 23:14:12 -07001185 self.fastboot_run('-S 256M flash %s %s' %
Dan Shie9913d32016-03-09 14:17:26 -08001186 (image[:-4], image_file))
Dan Shia2872172015-10-31 01:16:51 -07001187 if image == ANDROID_BOOTLOADER:
1188 self.fastboot_run('reboot-bootloader')
1189 self.wait_up(command=FASTBOOT_CMD)
1190 except Exception as e:
1191 logging.error('Install Android build failed with error: %s', e)
1192 # Re-raise the exception with type of AndroidInstallError.
1193 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1194 finally:
1195 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001196 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001197 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1198 DEFAULT_WAIT_UP_TIME_SECONDS)
1199 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001200 logging.info('Successfully installed Android build staged at %s.',
1201 build_url)
1202
1203
Dan Shiab999722015-12-04 14:27:08 -08001204 def install_brillo(self, build_url, build_local_path=None):
1205 """Install the Brillo DUT.
1206
1207 Following are the steps used here to provision an android device:
1208 1. If build_local_path is not set, download the image zip file, e.g.,
1209 dragonboard-img-123456.zip, unzip it. And download the vendor
1210 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1211 unzip it to vendor folder.
1212 2. Run provision_device script to install OS images and vendor
1213 partitions.
1214
1215 @param build_url: The url to use for downloading Android artifacts.
1216 pattern: http://$devserver:###/static/$build
1217 @param build_local_path: The path to a local folder that contains the
1218 image files needed to provision the device. Note that the folder
1219 is in the machine running adb command, rather than the drone.
1220
1221 @raises AndroidInstallError if any error occurs.
1222 """
1223 # If the build is not staged in local server yet, clean up the temp
1224 # folder used to store image files after the provision is completed.
1225 delete_build_folder = bool(not build_local_path)
1226
Dan Shiab999722015-12-04 14:27:08 -08001227 try:
1228 # Download image files needed for provision to a local directory.
1229 if not build_local_path:
1230 build_local_path = self.stage_brillo_image_files(build_url)
1231
1232 # Device needs to be in bootloader mode for flashing.
1233 self.ensure_bootloader_mode()
1234
1235 # Run provision_device command to install image files and vendor
1236 # partitions.
1237 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1238 cmd = (BRILLO_PROVISION_CMD %
1239 {'os_image_dir': build_local_path,
1240 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001241 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001242 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001243 self.teststation.run(cmd)
1244 except Exception as e:
1245 logging.error('Install Brillo build failed with error: %s', e)
1246 # Re-raise the exception with type of AndroidInstallError.
1247 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1248 finally:
1249 if delete_build_folder:
1250 self.teststation.run('rm -rf %s' % build_local_path)
1251 self.ensure_adb_mode()
1252 logging.info('Successfully installed Android build staged at %s.',
1253 build_url)
1254
1255
Dan Shibe3636a2016-02-14 22:48:01 -08001256 @property
1257 def job_repo_url_attribute(self):
1258 """Get the host attribute name for job_repo_url, which should append the
1259 adb serial.
1260 """
1261 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1262
1263
Dan Shie4e807b2015-12-10 09:04:03 -08001264 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001265 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001266 """Install the DUT.
1267
1268 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001269 pattern: http://$devserver:###/static/$build. If build_url is
1270 set to None, the code may try _parser.options.image to do the
1271 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001272 @param build_local_path: The path to a local directory that contains the
1273 image files needed to provision the device.
1274 @param wipe: If true, userdata will be wiped before flashing.
1275 @param flash_all: If True, all img files found in img_path will be
1276 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001277
Dan Shibe3636a2016-02-14 22:48:01 -08001278 @returns A tuple of (image_name, host_attributes).
1279 image_name is the name of image installed, e.g.,
1280 git_mnc-release/shamu-userdebug/1234
1281 host_attributes is a dictionary of (attribute, value), which
1282 can be saved to afe_host_attributes table in database. This
1283 method returns a dictionary with a single entry of
1284 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1285 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001286 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001287 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001288 if not build_url and self._parser.options.image:
1289 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001290 self._parser.options.image, os_type=os_type)
1291 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001292 self.install_android(
1293 build_url=build_url, build_local_path=build_local_path,
1294 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001295 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001296 self.install_brillo(
1297 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001298 else:
1299 raise error.InstallError(
1300 'Installation of os type %s is not supported.' %
1301 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001302 return (build_url.split('static/')[-1],
1303 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001304
1305
1306 def list_files_glob(self, path_glob):
1307 """Get a list of files on the device given glob pattern path.
1308
1309 @param path_glob: The path glob that we want to return the list of
1310 files that match the glob. Relative paths will not work as
1311 expected. Supply an absolute path to get the list of files
1312 you're hoping for.
1313
1314 @returns List of files that match the path_glob.
1315 """
1316 # This is just in case path_glob has no path separator.
1317 base_path = os.path.dirname(path_glob) or '.'
1318 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001319 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001320 if result.exit_status != 0:
1321 return []
1322 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001323
1324
Dan Shidb0366c2016-02-19 10:36:18 -08001325 def install_apk(self, apk, force_reinstall=False):
Kevin Cheng31355942016-01-05 14:23:35 -08001326 """Install the specified apk.
1327
1328 This will install the apk and override it if it's already installed and
1329 will also allow for downgraded apks.
1330
1331 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001332 @param force_reinstall: True to reinstall the apk even if it's already
1333 installed. Default is set to False.
1334
1335 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001336 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001337 client_utils.poll_for_condition(
1338 lambda: self.run('pm list packages',
1339 ignore_status=True).exit_status == 0,
1340 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001341 return self.adb_run('install %s -d %s' %
1342 ('-r' if force_reinstall else '', apk))
1343
1344
1345 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1346 def _confirm_apk_installed(self, package_name):
1347 """Confirm if apk is already installed with the given name.
1348
1349 `pm list packages` command is not reliable some time. The retry helps to
1350 reduce the chance of false negative.
1351
1352 @param package_name: Name of the package, e.g., com.android.phone.
1353
1354 @raise AutoservRunError: If the package is not found or pm list command
1355 failed for any reason.
1356 """
1357 name = 'package:%s' % package_name
1358 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1359
1360
1361 def is_apk_installed(self, package_name):
1362 """Check if apk is already installed with the given name.
1363
1364 @param package_name: Name of the package, e.g., com.android.phone.
1365
1366 @return: True if package is installed. False otherwise.
1367 """
1368 try:
1369 self._confirm_apk_installed(package_name)
1370 return True
1371 except:
1372 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001373
1374
1375 def get_attributes_to_clear_before_provision(self):
1376 """Get a list of attributes to be cleared before machine_install starts.
1377 """
1378 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001379
1380
1381 def get_labels(self):
1382 """Return a list of the labels gathered from the devices connected.
1383
1384 @return: A list of strings that denote the labels from all the devices
1385 connected.
1386 """
1387 return self.labels.get_labels(self)
1388
1389
1390 def update_labels(self):
1391 """Update the labels for this testbed."""
1392 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001393
1394
1395 def stage_server_side_package(self, image=None):
1396 """Stage autotest server-side package on devserver.
1397
1398 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1399
1400 @return: A url to the autotest server-side package. Return None if
1401 server-side package is not supported.
1402 @raise: error.AutoservError if fail to locate the build to test with.
1403 """
1404 if image:
1405 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1406 else:
1407 job_repo_url = afe_utils.get_host_attribute(
1408 self, self.job_repo_url_attribute)
1409 if job_repo_url:
1410 devserver_url, image = (
1411 tools.get_devserver_build_from_package_url(
1412 job_repo_url, True))
1413 ds = dev_server.AndroidBuildServer(devserver_url)
1414 else:
1415 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1416 if not labels:
1417 raise error.AutoservError(
1418 'Failed to stage server-side package. The host has '
1419 'no job_report_url attribute or version label.')
1420 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1421 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1422
1423 branch, target, build_id = utils.parse_launch_control_build(image)
1424 build_target, _ = utils.parse_launch_control_target(target)
1425
1426 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1427 # packaging is not supported.
1428 try:
1429 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1430 logging.warn('Build %s is older than %s. Server side packaging '
1431 'is disabled.', image,
1432 self.MIN_VERSION_SUPPORT_SSP)
1433 return None
1434 except ValueError:
1435 logging.warn('Failed to compare build id in %s with the minimum '
1436 'version that supports server side packaging. Server '
1437 'side packaging is disabled.', image)
1438 return None
1439
1440 ds.stage_artifacts(target, build_id, branch,
1441 artifacts=['autotest_server_package'])
1442 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1443 {'build_target': build_target,
1444 'build_id': build_id})
1445 return '%s/static/%s/%s' % (ds.url(), image,
1446 autotest_server_package_name)