blob: d99ec4c95060d62fbe60fb66041b5665fd995a99 [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
Dan Shi49d451f2016-04-19 09:25:01 -070015from autotest_lib.client.common_lib import android_utils
Simran Basi431010f2013-09-04 10:42:41 -070016from autotest_lib.client.common_lib import error
Dan Shi6450e142016-03-11 11:52:20 -080017from autotest_lib.client.common_lib import global_config
Dan Shi225b9042015-11-18 10:25:21 -080018from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070019from autotest_lib.client.common_lib.cros import retry
Dan Shi6450e142016-03-11 11:52:20 -080020from autotest_lib.server import afe_utils
Dan Shi225b9042015-11-18 10:25:21 -080021from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070022from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080023from autotest_lib.server import utils
Simran Basi5ace6f22016-01-06 17:30:44 -080024from autotest_lib.server.cros import provision
Dan Shi6450e142016-03-11 11:52:20 -080025from autotest_lib.server.cros.dynamic_suite import tools
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070026from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070027from autotest_lib.server.hosts import abstract_ssh
Kevin Chengc6a645a2015-12-18 11:15:10 -080028from autotest_lib.server.hosts import adb_label
29from autotest_lib.server.hosts import base_label
Kevin Cheng85e864a2015-11-30 11:49:34 -080030from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070031
32
Dan Shi6450e142016-03-11 11:52:20 -080033CONFIG = global_config.global_config
34
Dan Shi6ea3e1c2015-10-28 15:19:04 -070035ADB_CMD = 'adb'
36FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070037SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070038# Some devices have no serial, then `adb serial` has output such as:
39# (no serial number) device
40# ?????????? device
41DEVICE_NO_SERIAL_MSG = '(no serial number)'
42DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070043# Regex to find an adb device. Examples:
44# 0146B5580B01801B device
45# 018e0ecb20c97a62 device
46# 172.22.75.141:5555 device
Kevin Cheng224415e2016-04-22 11:32:10 -070047# localhost:22 device
Alexandru Branciogea380fb2016-04-01 16:01:34 +030048DEVICE_FINDER_REGEX = (r'^(?P<SERIAL>([\w-]+)|((tcp:)?' +
49 '\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}([:]5555)?)|' +
Kevin Cheng224415e2016-04-22 11:32:10 -070050 '((tcp:)?localhost([:]22)?)|' +
Filipe Brandenburger34363392015-08-13 14:57:45 -070051 re.escape(DEVICE_NO_SERIAL_MSG) +
Alexandru Branciogea380fb2016-04-01 16:01:34 +030052 r')[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070053CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
54CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
55 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070056RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070057BOARD_FILE = 'ro.product.device'
Simran Basi38f7ddf2015-09-18 12:25:03 -070058TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070059# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080060# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070061FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
62FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
63# List of the perm stats indexed by the order they are listed in the example
64# supplied above.
65FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
66 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
67 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070068
Dan Shi6ea3e1c2015-10-28 15:19:04 -070069# Default maximum number of seconds to wait for a device to be down.
70DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
71# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080072DEFAULT_WAIT_UP_TIME_SECONDS = 300
73# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080074WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070075
Dan Shi7075f552016-04-21 15:42:41 -070076# Default timeout for retrying adb/fastboot command.
77DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS = 10
78
Dan Shia2872172015-10-31 01:16:51 -070079OS_TYPE_ANDROID = 'android'
80OS_TYPE_BRILLO = 'brillo'
81
Dan Shie234dea2016-01-20 17:15:17 -080082# Regex to parse build name to get the detailed build information.
Dan Shi6450e142016-03-11 11:52:20 -080083BUILD_REGEX = ('(?P<BRANCH>([^/]+))/(?P<BUILD_TARGET>([^/]+))-'
Dan Shie234dea2016-01-20 17:15:17 -080084 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))')
Dan Shia2872172015-10-31 01:16:51 -070085# Regex to parse devserver url to get the detailed build information. Sample
86# url: http://$devserver:8080/static/branch/target/build_id
Dan Shie234dea2016-01-20 17:15:17 -080087DEVSERVER_URL_REGEX = '.*/%s/*' % BUILD_REGEX
Dan Shia2872172015-10-31 01:16:51 -070088
Dan Shi6450e142016-03-11 11:52:20 -080089ANDROID_IMAGE_FILE_FMT = '%(build_target)s-img-%(build_id)s.zip'
Dan Shi49d451f2016-04-19 09:25:01 -070090
Dan Shiab999722015-12-04 14:27:08 -080091BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
Dan Shi6450e142016-03-11 11:52:20 -080092 '%(build_target)s-vendor_partitions-%(build_id)s.zip')
93AUTOTEST_SERVER_PACKAGE_FILE_FMT = (
94 '%(build_target)s-autotest_server_package-%(build_id)s.tar.bz2')
Simran Basi9228a6f2016-03-29 12:03:37 -070095ADB_DEVICE_PREFIXES = ['product:', 'model:', 'device:']
Dan Shia2872172015-10-31 01:16:51 -070096
Simran Basi9c5d3982016-04-01 18:49:44 -070097# Map of product names to build target name.
98PRODUCT_TARGET_MAP = {'dragon' : 'ryu',
99 'flo' : 'razor',
100 'flo_lte' : 'razorg',
101 'gm4g_sprout' : 'seed_l8150',
102 'flounder' : 'volantis',
103 'flounder_lte' : 'volantisg'}
104
Dan Shiab999722015-12-04 14:27:08 -0800105# Command to provision a Brillo device.
106# os_image_dir: The full path of the directory that contains all the Android image
107# files (from the image zip file).
108# vendor_partition_dir: The full path of the directory that contains all the
109# Brillo vendor partitions, and provision-device script.
110BRILLO_PROVISION_CMD = (
Simran Basi7e52c622016-01-05 15:43:51 -0800111 'sudo ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
Dan Shiab999722015-12-04 14:27:08 -0800112 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
113 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -0700114
115class AndroidInstallError(error.InstallError):
116 """Generic error for Android installation related exceptions."""
117
118
Simran Basi724b8a52013-09-30 11:19:31 -0700119class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700120 """This class represents a host running an ADB server."""
121
Simran Basi5ace6f22016-01-06 17:30:44 -0800122 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700123 _LABEL_FUNCTIONS = []
124 _DETECTABLE_LABELS = []
125 label_decorator = functools.partial(utils.add_label_detector,
126 _LABEL_FUNCTIONS,
127 _DETECTABLE_LABELS)
128
Dan Shi225b9042015-11-18 10:25:21 -0800129 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700130
Dan Shi6450e142016-03-11 11:52:20 -0800131 # Minimum build id that supports server side packaging. Older builds may
132 # not have server side package built or with Autotest code change to support
133 # server-side packaging.
134 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
135 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
136
beeps46dadc92013-11-07 14:07:10 -0800137 @staticmethod
138 def check_host(host, timeout=10):
139 """
140 Check if the given host is an adb host.
141
Simran Basi14622bb2015-11-25 13:23:40 -0800142 If SSH connectivity can't be established, check_host will try to use
143 user 'adb' as well. If SSH connectivity still can't be established
144 then the original SSH user is restored.
145
beeps46dadc92013-11-07 14:07:10 -0800146 @param host: An ssh host representing a device.
147 @param timeout: The timeout for the run command.
148
149
150 @return: True if the host device has adb.
151
152 @raises AutoservRunError: If the command failed.
153 @raises AutoservSSHTimeout: Ssh connection has timed out.
154 """
Dan Shi64e130f2015-12-16 14:45:44 -0800155 # host object may not have user attribute if it's a LocalHost object.
156 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800157 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800158 if not (host.hostname == 'localhost' or
159 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700160 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700161 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700162 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700163 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800164 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800165 if current_user is not None:
166 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800167 return False
168 return result.exit_status == 0
169
170
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700171 # TODO(garnold) Remove the 'serials' argument once all clients are made to
172 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700173 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700174 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700175 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700176 """Initialize an ADB Host.
177
178 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700179 test station connected to an Android DUT. This will be the DUT
180 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700181 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700182
183 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700184 @param serials: DEPRECATED (to be removed)
185 @param adb_serial: An ADB device serial. If None, assume a single
186 device is attached (and fail otherwise).
187 @param fastboot_serial: A fastboot device serial. If None, defaults to
188 the ADB serial (or assumes a single device if
189 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800190 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700191 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800192 # Sets up the is_client_install_supported field.
193 super(ADBHost, self)._initialize(hostname=hostname,
194 is_client_install_supported=False,
195 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800196
Kevin Chengd19e6c62015-10-28 16:39:39 -0700197 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800198 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi1bf60eb2015-12-01 16:39:29 -0800199 # TODO (sbasi/kevcheng): Once the teststation host is committed,
200 # refactor the serial retrieval.
201 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800202 self.adb_serial = adb_serial
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300203 adb_prefix = any(adb_serial.startswith(p) for p in ADB_DEVICE_PREFIXES)
204 self.fastboot_serial = (fastboot_serial or
205 ('tcp:%s' % adb_serial.split(':')[0] if
206 ':' in adb_serial and not adb_prefix else adb_serial))
Kevin Cheng85e864a2015-11-30 11:49:34 -0800207 self.teststation = (teststation if teststation
208 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700209
210 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800211 if self.adb_serial:
212 msg += ', ADB serial: %s' % self.adb_serial
213 if self.fastboot_serial:
214 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700215 logging.debug(msg)
216
Simran Basi9228a6f2016-03-29 12:03:37 -0700217 self._use_tcpip = ':' in adb_serial and not adb_prefix
Simran Basibeb2bb22016-02-03 15:25:48 -0800218 # Try resetting the ADB daemon on the device, however if we are
219 # creating the host to do a repair job, the device maybe inaccesible
220 # via ADB.
221 try:
222 self._reset_adbd_connection()
223 except (error.AutotestHostRunError, error.AutoservRunError) as e:
224 logging.error('Unable to reset the device adb daemon connection: '
225 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800226 self._os_type = None
227
Simran Basi431010f2013-09-04 10:42:41 -0700228
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700229 def _connect_over_tcpip_as_needed(self):
230 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700231 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700232 return
233 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700234 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700235
236
Roshan Pius4d7540c2015-12-16 13:30:32 -0800237 def _restart_adbd_with_root_permissions(self):
238 """Restarts the adb daemon with root permissions."""
Dan Shi922de302016-04-22 15:19:18 -0700239 @retry.retry(error.AutoservRunError, timeout_min=20/60.0, delay_sec=1)
240 def run_adb_root():
241 """Run command `adb root`."""
242 self.adb_run('root')
243
244 # adb command may flake with error "device not found". Retry the root
245 # command to reduce the chance of flake.
246 run_adb_root()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800247 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
248 time.sleep(1)
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300249 self._connect_over_tcpip_as_needed()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800250 self.adb_run('wait-for-device')
251
252
Simran Basi9228a6f2016-03-29 12:03:37 -0700253 def _set_tcp_port(self):
254 """Ensure the device remains in tcp/ip mode after a reboot."""
255 if not self._use_tcpip:
256 return
257 port = self.adb_serial.split(':')[-1]
258 self.run('setprop persist.adb.tcp.port %s' % port)
259
260
Roshan Pius4d7540c2015-12-16 13:30:32 -0800261 def _reset_adbd_connection(self):
262 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800263 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700264 self._restart_adbd_with_root_permissions()
265 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800266
267
Kevin Cheng85e864a2015-11-30 11:49:34 -0800268 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800269 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700270 """Runs an adb command.
271
Kevin Chengd19e6c62015-10-28 16:39:39 -0700272 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700273
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700274 Refer to _device_run method for docstring for parameters.
275 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800276 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700277
278
Kevin Cheng85e864a2015-11-30 11:49:34 -0800279 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800280 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700281 """Runs an fastboot command.
282
Kevin Chengd19e6c62015-10-28 16:39:39 -0700283 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700284
285 Refer to _device_run method for docstring for parameters.
286 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800287 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700288
289
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700290 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700291 timeout=3600, ignore_status=False, ignore_timeout=False,
292 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
293 connect_timeout=30, options='', stdin=None, verbose=True,
294 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700295 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700296
Kevin Chengd19e6c62015-10-28 16:39:39 -0700297 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700298
Simran Basi431010f2013-09-04 10:42:41 -0700299 @param command: Command to run.
300 @param shell: If true the command runs in the adb shell otherwise if
301 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700302 reboot with shell=False will call 'adb reboot'. This
303 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700304 @param timeout: Time limit in seconds before attempting to
305 kill the running process. The run() function
306 will take a few seconds longer than 'timeout'
307 to complete if it has to kill the process.
308 @param ignore_status: Do not raise an exception, no matter
309 what the exit code of the command is.
310 @param ignore_timeout: Bool True if command timeouts should be
311 ignored. Will return None on command timeout.
312 @param stdout: Redirect stdout.
313 @param stderr: Redirect stderr.
314 @param connect_timeout: Connection timeout (in seconds)
315 @param options: String with additional ssh command options
316 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700317 @param require_sudo: True to require sudo to run the command. Default is
318 False.
Simran Basi431010f2013-09-04 10:42:41 -0700319 @param args: Sequence of strings to pass as arguments to command by
320 quoting them in " and escaping their contents if
321 necessary.
322
323 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700324 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700325 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800326 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700327 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800328 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700329 else:
330 raise NotImplementedError('Mode %s is not supported' % function)
331
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700332 if function != ADB_CMD and shell:
333 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700334
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700335 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700336
337 if serial:
338 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700339
Simran Basi431010f2013-09-04 10:42:41 -0700340 if shell:
341 cmd += '%s ' % SHELL_CMD
342 cmd += command
343
Roshan Pius58e5dd32015-10-16 15:16:42 -0700344 if verbose:
345 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700346
Kevin Cheng85e864a2015-11-30 11:49:34 -0800347 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400348 ignore_status=ignore_status,
349 ignore_timeout=ignore_timeout, stdout_tee=stdout,
350 stderr_tee=stderr, options=options, stdin=stdin,
351 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700352
353
Dan Shie234dea2016-01-20 17:15:17 -0800354 def get_board_name(self):
355 """Get the name of the board, e.g., shamu, dragonboard etc.
356 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700357 product = self.run_output('getprop %s' % BOARD_FILE)
358 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800359
360
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700361 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700362 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700363 """Determine the correct board label for the device.
364
365 @returns a string representing this device's board.
366 """
Dan Shie234dea2016-01-20 17:15:17 -0800367 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700368 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800369 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700370
371
Christopher Wiley08849d52013-11-22 08:57:58 -0800372 def job_start(self):
373 """
374 Disable log collection on adb_hosts.
375
376 TODO(sbasi): crbug.com/305427
Christopher Wiley08849d52013-11-22 08:57:58 -0800377 """
378
379
Simran Basi431010f2013-09-04 10:42:41 -0700380 def run(self, command, timeout=3600, ignore_status=False,
381 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
382 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700383 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700384 """Run a command on the adb device.
385
386 The command given will be ran directly on the adb device; for example
387 'ls' will be ran as: 'abd shell ls'
388
389 @param command: The command line string.
390 @param timeout: Time limit in seconds before attempting to
391 kill the running process. The run() function
392 will take a few seconds longer than 'timeout'
393 to complete if it has to kill the process.
394 @param ignore_status: Do not raise an exception, no matter
395 what the exit code of the command is.
396 @param ignore_timeout: Bool True if command timeouts should be
397 ignored. Will return None on command timeout.
398 @param stdout_tee: Redirect stdout.
399 @param stderr_tee: Redirect stderr.
400 @param connect_timeout: Connection timeout (in seconds).
401 @param options: String with additional ssh command options.
402 @param stdin: Stdin to pass (a string) to the executed command
403 @param args: Sequence of strings to pass as arguments to command by
404 quoting them in " and escaping their contents if
405 necessary.
406
407 @returns A CMDResult object or None if the call timed out and
408 ignore_timeout is True.
409
410 @raises AutoservRunError: If the command failed.
411 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700412 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700413 command = ('"%s; echo %s:\$?"' %
414 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700415 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700416 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700417 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
418 stdout=stdout_tee, stderr=stderr_tee,
419 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700420 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700421 if not result:
422 # In case of timeouts.
423 return None
424
425 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700426 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700427 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700428 'Failed to parse the exit code for command: %s' %
429 command, result)
430 elif parse_output:
431 result.stdout = parse_output.group('OUTPUT')
432 result.exit_status = int(parse_output.group('EXIT_CODE'))
433 if result.exit_status != 0 and not ignore_status:
434 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700435 return result
436
437
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700438 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
439 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700440
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700441 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700442
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700443 @param timeout: Time limit in seconds before returning even if the host
444 is not up.
445 @param command: The command used to test if a device is up, i.e.,
446 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700447
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700448 @returns True if the host was found to be up before the timeout expires,
449 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700450 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700451 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
452 delay_sec=1)
453 def _wait_up():
454 if not self.is_up(command=command):
455 raise error.TimeoutException('Device is still down.')
456 return True
457
458 try:
459 _wait_up()
460 logging.debug('Host %s is now up, and can be accessed by %s.',
461 self.hostname, command)
462 return True
463 except error.TimeoutException:
464 logging.debug('Host %s is still down after waiting %d seconds',
465 self.hostname, timeout)
466 return False
Simran Basi431010f2013-09-04 10:42:41 -0700467
468
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700469 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
470 warning_timer=None, old_boot_id=None, command=ADB_CMD):
471 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700472
473 Overrides wait_down from AbstractSSHHost.
474
475 @param timeout: Time in seconds to wait for the host to go down.
476 @param warning_timer: Time limit in seconds that will generate
477 a warning if the host is not down yet.
478 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700479 @param old_boot_id: Not applicable for adb_host.
480 @param command: `adb`, test if the device can be accessed by adb
481 command, or `fastboot`, test if the device can be accessed by
482 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700483
484 @returns True if the device goes down before the timeout, False
485 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700486 """
487 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
488 delay_sec=1)
489 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700490 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700491 raise error.TimeoutException('Device is still up.')
492 return True
493
494 try:
495 _wait_down()
496 logging.debug('Host %s is now down', self.hostname)
497 return True
498 except error.TimeoutException:
499 logging.debug('Host %s is still up after waiting %d seconds',
500 self.hostname, timeout)
501 return False
502
503
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700504 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700505 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700506
507 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700508 """
509 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700510 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700511 self.adb_run('reboot', timeout=10, ignore_timeout=True)
512 if not self.wait_down():
513 raise error.AutoservRebootError(
514 'ADB Device is still up after reboot')
515 if not self.wait_up():
516 raise error.AutoservRebootError(
517 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800518 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800519
520
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300521 def fastboot_reboot(self):
522 """Do a fastboot reboot to go back to adb.
523
524 @raises AutoservRebootError if reboot failed.
525 """
526 self.fastboot_run('reboot')
527 if not self.wait_down(command=FASTBOOT_CMD):
528 raise error.AutoservRebootError(
529 'Device is still in fastboot mode after reboot')
530 if not self.wait_up():
531 raise error.AutoservRebootError(
532 'Device failed to boot to adb after fastboot reboot.')
533 self._reset_adbd_connection()
534
535
Ralph Nathanb45eb672015-11-18 20:04:39 -0800536 def remount(self):
537 """Remounts paritions on the device read-write.
538
539 Specifically, the /system, /vendor (if present) and /oem (if present)
540 partitions on the device are remounted read-write.
541 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800542 self.adb_run('remount')
543
544
Kevin Cheng549beb42015-11-18 11:42:25 -0800545 @staticmethod
546 def parse_device_serials(devices_output):
547 """Return a list of parsed serials from the output.
548
549 @param devices_output: Output from either an adb or fastboot command.
550
551 @returns List of device serials
552 """
553 devices = []
554 for line in devices_output.splitlines():
555 match = re.search(DEVICE_FINDER_REGEX, line)
556 if match:
557 serial = match.group('SERIAL')
558 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
559 serial = DEVICE_NO_SERIAL_TAG
560 logging.debug('Found Device: %s', serial)
561 devices.append(serial)
562 return devices
563
564
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700565 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700566 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700567
568 @params use_adb: True to get adb accessible devices. Set to False to
569 get fastboot accessible devices.
570
Kevin Chengd19e6c62015-10-28 16:39:39 -0700571 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700572 """
573 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300574 result = self.adb_run('devices').stdout
575 if self.adb_serial and self.adb_serial not in result:
576 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700577 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300578 result = self.fastboot_run('devices').stdout
579 if (self.fastboot_serial and
580 self.fastboot_serial not in result):
581 # fastboot devices won't list the devices using TCP
582 try:
583 if 'product' in self.fastboot_run('getvar product',
584 timeout=2).stderr:
585 result += '\n%s\tfastboot' % self.fastboot_serial
Kevin Chengcfcb2cf2016-04-13 10:04:36 -0700586 # The main reason we do a general Exception catch here instead
587 # of setting ignore_timeout/status to True is because even when
588 # the fastboot process has been nuked, it still stays around and
589 # so bgjob wants to warn us of this and tries to read the
590 # /proc/<pid>/stack file which then promptly returns an
591 # 'Operation not permitted' error since we're running as moblab
592 # and we don't have permission to read those files.
593 except Exception:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300594 pass
595 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700596
597
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700598 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700599 """Get a list of devices currently attached to the test station and
600 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700601 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800602 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700603 raise error.AutoservError(
604 'Not given ADB serial but multiple devices detected')
605 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700606
607
608 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700609 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700610 accessible by fastboot command.
611 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700612 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800613 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700614 raise error.AutoservError(
615 'Not given fastboot serial but multiple devices detected')
616 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700617
618
619 def is_up(self, timeout=0, command=ADB_CMD):
620 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700621
622 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700623 @param command: `adb`, the device can be accessed by adb command,
624 or `fastboot`, the device can be accessed by fastboot command.
625 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700626
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700627 @returns True if the device is detectable by given command, False
628 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700629
630 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700631 if command == ADB_CMD:
632 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800633 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800634 # ADB has a device state, if the device is not online, no
635 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800636 # DUT with single device connected may not have adb_serial set.
637 # Therefore, skip checking if serial is in the list of adb devices
638 # if self.adb_serial is not set.
639 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800640 logging.debug('Waiting for device to enter the ready state.')
641 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700642 elif command == FASTBOOT_CMD:
643 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800644 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700645 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700646 raise NotImplementedError('Mode %s is not supported' % command)
647
648 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700649
650
651 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700652 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700653
654 Called as the test ends. Will return the device to USB mode and kill
655 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700656 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800657 # TODO(sbasi) Originally, we would kill the server after each test to
658 # reduce the opportunity for bad server state to hang around.
659 # Unfortunately, there is a period of time after each kill during which
660 # the Android device becomes unusable, and if we start the next test
661 # too quickly, we'll get an error complaining about no ADB device
662 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700663 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800664 # |close| the associated teststation as well.
665 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700666 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700667
668
669 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700670 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700671
672 @param message String message to log into syslog
673 @param tag String tag prefix for syslog
674
675 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700676 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700677
678
679 def get_autodir(self):
680 """Return the directory to install autotest for client side tests."""
681 return '/data/autotest'
682
Kevin Cheng018db352015-09-20 02:22:08 -0700683
Kris Rambishde8f9d12015-12-16 12:42:41 -0800684 def is_device_ready(self):
685 """Return the if the device is ready for ADB commands."""
Dan Shi7075f552016-04-21 15:42:41 -0700686 try:
687 # Retry to avoid possible flakes.
688 is_ready = client_utils.poll_for_condition(
689 lambda: self.adb_run('get-state').stdout.strip() == 'device',
690 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS, sleep_interval=1,
691 desc='Waiting for device state to be `device`')
692 except client_utils.TimeoutError:
693 is_ready = False
694
695 logging.debug('Device state is %sready', '' if is_ready else 'NOT ')
696 return is_ready
Kris Rambishde8f9d12015-12-16 12:42:41 -0800697
698
Kevin Chengd19e6c62015-10-28 16:39:39 -0700699 def verify_connectivity(self):
700 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800701 if not self.is_device_ready():
702 raise error.AutoservHostError('device state is not in the '
703 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700704
705
Simran Basid3ba3fb2015-09-11 14:35:07 -0700706 def verify_software(self):
707 """Verify working software on an adb_host.
708
Simran Basi38f7ddf2015-09-18 12:25:03 -0700709 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700710 """
Dan Shiab999722015-12-04 14:27:08 -0800711 # Check if adb and fastboot are present.
712 self.teststation.run('which adb')
713 self.teststation.run('which fastboot')
714 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700715
Kevin Cheng018db352015-09-20 02:22:08 -0700716
Simran Basid3ba3fb2015-09-11 14:35:07 -0700717 def verify_job_repo_url(self, tag=''):
718 """Make sure job_repo_url of this host is valid.
719
Simran Basi38f7ddf2015-09-18 12:25:03 -0700720 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700721
722 @param tag: The tag from the server job, in the format
723 <job_id>-<user>/<hostname>, or <hostless> for a server job.
724 """
725 return
Kevin Cheng018db352015-09-20 02:22:08 -0700726
727
Simran Basibeb2bb22016-02-03 15:25:48 -0800728 def repair(self):
729 """Attempt to get the DUT to pass `self.verify()`."""
730 try:
731 self.ensure_adb_mode(timeout=30)
732 return
733 except error.AutoservError as e:
734 logging.error(e)
735 logging.debug('Verifying the device is accessible via fastboot.')
736 self.ensure_bootloader_mode()
737 if not self.job.run_test(
738 'provision_AndroidUpdate', host=self, value=None,
739 force=True, repair=True):
740 raise error.AutoservRepairTotalFailure(
741 'Unable to repair the device.')
742
743
Simran Basi1b023762015-09-25 12:12:20 -0700744 def send_file(self, source, dest, delete_dest=False,
745 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700746 """Copy files from the drone to the device.
747
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400748 Just a note, there is the possibility the test station is localhost
749 which makes some of these steps redundant (e.g. creating tmp dir) but
750 that scenario will undoubtedly be a development scenario (test station
751 is also the moblab) and not the typical live test running scenario so
752 the redundancy I think is harmless.
753
Kevin Cheng018db352015-09-20 02:22:08 -0700754 @param source: The file/directory on the drone to send to the device.
755 @param dest: The destination path on the device to copy to.
756 @param delete_dest: A flag set to choose whether or not to delete
757 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700758 @param preserve_symlinks: Controls if symlinks on the source will be
759 copied as such on the destination or
760 transformed into the referenced
761 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700762 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700763 # If we need to preserve symlinks, let's check if the source is a
764 # symlink itself and if so, just create it on the device.
765 if preserve_symlinks:
766 symlink_target = None
767 try:
768 symlink_target = os.readlink(source)
769 except OSError:
770 # Guess it's not a symlink.
771 pass
772
773 if symlink_target is not None:
774 # Once we create the symlink, let's get out of here.
775 self.run('ln -s %s %s' % (symlink_target, dest))
776 return
777
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400778 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700779 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400780 src_path = os.path.join(tmp_dir, os.path.basename(dest))
781 # Now copy the file over to the test station so you can reference the
782 # file in the push command.
783 self.teststation.send_file(source, src_path,
784 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700785
786 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400787 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700788
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700789 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700790
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400791 # Cleanup the test station.
792 try:
793 self.teststation.run('rm -rf %s' % tmp_dir)
794 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
795 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700796
797
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700798 def _get_file_info(self, dest):
799 """Get permission and possible symlink info about file on the device.
800
801 These files are on the device so we only have shell commands (via adb)
802 to get the info we want. We'll use 'ls' to get it all.
803
804 @param dest: File to get info about.
805
806 @returns a dict of the file permissions and symlink.
807 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800808 # Grab file info.
809 file_info = self.run_output('ls -l %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700810 symlink = None
811 perms = 0
812 match = re.match(FILE_INFO_REGEX, file_info)
813 if match:
814 # Check if it's a symlink and grab the linked dest if it is.
815 if match.group('TYPE') == 'l':
816 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
817 if symlink_match:
818 symlink = symlink_match.group('SYMLINK')
819
820 # Set the perms.
821 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
822 if perm != '-':
823 perms |= perm_flag
824
825 return {'perms': perms,
826 'symlink': symlink}
827
828
Simran Basi1b023762015-09-25 12:12:20 -0700829 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
830 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700831 """Copy files from the device to the drone.
832
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400833 Just a note, there is the possibility the test station is localhost
834 which makes some of these steps redundant (e.g. creating tmp dir) but
835 that scenario will undoubtedly be a development scenario (test station
836 is also the moblab) and not the typical live test running scenario so
837 the redundancy I think is harmless.
838
Kevin Cheng018db352015-09-20 02:22:08 -0700839 @param source: The file/directory on the device to copy back to the
840 drone.
841 @param dest: The destination path on the drone to copy to.
842 @param delete_dest: A flag set to choose whether or not to delete
843 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700844 @param preserve_perm: Tells get_file() to try to preserve the sources
845 permissions on files and dirs.
846 @param preserve_symlinks: Try to preserve symlinks instead of
847 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700848 """
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400849 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700850 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400851 dest_path = os.path.join(tmp_dir, os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700852
853 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400854 self.teststation.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700855
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700856 source_info = {}
857 if preserve_symlinks or preserve_perm:
858 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700859
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700860 # If we want to preserve symlinks, just create it here, otherwise pull
861 # the file off the device.
862 if preserve_symlinks and source_info['symlink']:
863 os.symlink(source_info['symlink'], dest)
864 else:
Roshan Pius95567142015-11-03 09:56:08 -0800865 self.adb_run('pull %s %s' % (source, dest_path))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700866
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400867 # Copy over the file from the test station and clean up.
868 self.teststation.get_file(dest_path, dest)
869 try:
870 self.teststation.run('rm -rf %s' % tmp_dir)
871 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
872 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700873
874 if preserve_perm:
875 os.chmod(dest, source_info['perms'])
Kevin Cheng018db352015-09-20 02:22:08 -0700876
877
878 def get_release_version(self):
879 """Get the release version from the RELEASE_FILE on the device.
880
881 @returns The release string in the RELEASE_FILE.
882
883 """
884 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700885
886
887 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700888 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700889
Kevin Chengd19e6c62015-10-28 16:39:39 -0700890 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700891
892 @param parent: Parent directory of the returned tmp dir.
893
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700894 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700895 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700896 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
897 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700898 if not parent.startswith(TMP_DIR):
899 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700900 self.run('mkdir -p %s' % parent)
901 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
902 self.tmp_dirs.append(tmp_dir)
903 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700904
905
906 def get_platform(self):
907 """Determine the correct platform label for this host.
908
909 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700910 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700911
912 @returns a string representing this host's platform.
913 """
914 return 'adb'
915
916
Gilad Arnolda76bef02015-09-29 13:55:15 -0700917 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800918 """Get the OS type of the DUT, e.g., android or brillo.
919 """
920 if not self._os_type:
921 if self.run_output('getprop ro.product.brand') == 'Brillo':
922 self._os_type = OS_TYPE_BRILLO
923 else:
924 self._os_type = OS_TYPE_ANDROID
925
926 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700927
928
929 def _forward(self, reverse, args):
930 """Execute a forwarding command.
931
932 @param reverse: Whether this is reverse forwarding (Boolean).
933 @param args: List of command arguments.
934 """
935 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700936 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700937
938
939 def add_forwarding(self, src, dst, reverse=False, rebind=True):
940 """Forward a port between the ADB host and device.
941
942 Port specifications are any strings accepted as such by ADB, for
943 example 'tcp:8080'.
944
945 @param src: Port specification to forward from.
946 @param dst: Port specification to forward to.
947 @param reverse: Do reverse forwarding from device to host (Boolean).
948 @param rebind: Allow rebinding an already bound port (Boolean).
949 """
950 args = []
951 if not rebind:
952 args.append('--no-rebind')
953 args += [src, dst]
954 self._forward(reverse, args)
955
956
957 def remove_forwarding(self, src=None, reverse=False):
958 """Removes forwarding on port.
959
960 @param src: Port specification, or None to remove all forwarding.
961 @param reverse: Whether this is reverse forwarding (Boolean).
962 """
963 args = []
964 if src is None:
965 args.append('--remove-all')
966 else:
967 args += ['--remove', src]
968 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700969
970
xixuan6cf6d2f2016-01-29 15:29:00 -0800971 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700972 """
973 Forwards a port securely through a tunnel process from the server
974 to the DUT for RPC server connection.
975 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
976 to the DUT.
977
978 @param port: remote port on the DUT.
979 @param local_port: local forwarding port.
980
981 @return: the tunnel process.
982 """
983 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800984 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700985
986
xixuan6cf6d2f2016-01-29 15:29:00 -0800987 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700988 """
989 Disconnects a previously forwarded port from the server to the DUT for
990 RPC server connection.
991 Remove the previously added 'ADB forward' rule to forward the RPC
992 packets from the AdbHost to the DUT.
993
994 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -0800995 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -0700996 @param port: remote port on the DUT.
997
998 """
999 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001000 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001001
1002
1003 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001004 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001005
1006 @raise: error.AutoservError if the device failed to reboot into
1007 bootloader mode.
1008 """
1009 if self.is_up(command=FASTBOOT_CMD):
1010 return
1011 self.adb_run('reboot bootloader')
1012 if not self.wait_up(command=FASTBOOT_CMD):
1013 raise error.AutoservError(
1014 'The device failed to reboot into bootloader mode.')
1015
1016
Dan Shie4e807b2015-12-10 09:04:03 -08001017 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001018 """Ensure the device is up and can be accessed by adb command.
1019
Dan Shie4e807b2015-12-10 09:04:03 -08001020 @param timeout: Time limit in seconds before returning even if the host
1021 is not up.
1022
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001023 @raise: error.AutoservError if the device failed to reboot into
1024 adb mode.
1025 """
1026 if self.is_up():
1027 return
Dan Shi04980372016-03-22 10:57:47 -07001028 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1029 # check if the device is in adb mode.
1030 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001031 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001032 raise error.AutoservError(
1033 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001034 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001035
1036
1037 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001038 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001039 """Get the Android build information from the build url.
1040
1041 @param build_url: The url to use for downloading Android artifacts.
1042 pattern: http://$devserver:###/static/branch/target/build_id
1043
Dan Shi6450e142016-03-11 11:52:20 -08001044 @return: A dictionary of build information, including keys:
1045 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001046 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001047 """
Dan Shiab999722015-12-04 14:27:08 -08001048 if not build_url:
1049 raise AndroidInstallError('Need build_url to download image files.')
1050
1051 try:
1052 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001053 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001054 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001055 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001056 match.group('BUILD_TYPE'))),
1057 'build_id': match.group('BUILD_ID')}
1058 except (AttributeError, IndexError, ValueError) as e:
1059 raise AndroidInstallError(
1060 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001061
1062
Dan Shia2872172015-10-31 01:16:51 -07001063 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001064 def download_file(self, build_url, file, dest_dir, unzip=False,
1065 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001066 """Download the given file from the build url.
1067
1068 @param build_url: The url to use for downloading Android artifacts.
1069 pattern: http://$devserver:###/static/branch/target/build_id
1070 @param file: Name of the file to be downloaded, e.g., boot.img.
1071 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001072 @param unzip: If True, unzip the downloaded file.
1073 @param unzip_dest: Location to unzip the downloaded file to. If not
1074 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001075 """
Dan Shidb0366c2016-02-19 10:36:18 -08001076 # Append the file name to the url if build_url is linked to the folder
1077 # containing the file.
1078 if not build_url.endswith('/%s' % file):
1079 src_url = os.path.join(build_url, file)
1080 else:
1081 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001082 dest_file = os.path.join(dest_dir, file)
1083 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001084 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001085 if unzip:
1086 unzip_dest = unzip_dest or dest_dir
1087 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1088 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001089 except:
1090 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001091 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001092 raise
1093
1094
Dan Shiab999722015-12-04 14:27:08 -08001095 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001096 """Download required image files from the given build_url to a local
1097 directory in the machine runs fastboot command.
1098
1099 @param build_url: The url to use for downloading Android artifacts.
1100 pattern: http://$devserver:###/static/branch/target/build_id
1101
1102 @return: Path to the directory contains image files.
1103 """
Dan Shi08ff1282016-02-18 19:51:16 -08001104 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001105
1106 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001107 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001108
1109 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001110 self.download_file(build_url, zipped_image_file, image_dir,
1111 unzip=True)
Dan Shi49d451f2016-04-19 09:25:01 -07001112 images = android_utils.AndroidImageFiles.get_standalone_images(
1113 build_info['build_target'])
1114 for image_file in images:
Dan Shidb0366c2016-02-19 10:36:18 -08001115 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001116
Dan Shia2872172015-10-31 01:16:51 -07001117 return image_dir
1118 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001119 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001120 raise
1121
1122
Dan Shiab999722015-12-04 14:27:08 -08001123 def stage_brillo_image_files(self, build_url):
1124 """Download required brillo image files from the given build_url to a
1125 local directory in the machine runs fastboot command.
1126
1127 @param build_url: The url to use for downloading Android artifacts.
1128 pattern: http://$devserver:###/static/branch/target/build_id
1129
1130 @return: Path to the directory contains image files.
1131 """
Dan Shi08ff1282016-02-18 19:51:16 -08001132 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001133
1134 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1135 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1136 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001137
1138 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001139 self.download_file(build_url, zipped_image_file, image_dir,
1140 unzip=True)
1141 self.download_file(build_url, vendor_partitions_file, image_dir,
1142 unzip=True,
1143 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001144 return image_dir
1145 except:
1146 self.teststation.run('rm -rf %s' % image_dir)
1147 raise
1148
1149
Simran Basibeb2bb22016-02-03 15:25:48 -08001150 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001151 """Stage a build on a devserver and return the build_url and devserver.
1152
1153 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001154
Dan Shi225b9042015-11-18 10:25:21 -08001155 @returns a tuple with an update URL like:
1156 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1157 and the devserver instance.
1158 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001159 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001160 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001161 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1162 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001163 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001164 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001165 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001166 devserver.trigger_download(target, build_id, branch,
1167 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001168 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001169
1170
Dan Shie4e807b2015-12-10 09:04:03 -08001171 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001172 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001173 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001174
1175 Following are the steps used here to provision an android device:
1176 1. If build_local_path is not set, download the image zip file, e.g.,
1177 shamu-img-2284311.zip, unzip it.
1178 2. Run fastboot to install following artifacts:
1179 bootloader, radio, boot, system, vendor(only if exists)
1180
1181 Repair is not supported for Android devices yet.
1182
1183 @param build_url: The url to use for downloading Android artifacts.
1184 pattern: http://$devserver:###/static/$build
1185 @param build_local_path: The path to a local folder that contains the
1186 image files needed to provision the device. Note that the folder
1187 is in the machine running adb command, rather than the drone.
1188 @param wipe: If true, userdata will be wiped before flashing.
1189 @param flash_all: If True, all img files found in img_path will be
1190 flashed. Otherwise, only boot and system are flashed.
1191
1192 @raises AndroidInstallError if any error occurs.
1193 """
Dan Shia2872172015-10-31 01:16:51 -07001194 # If the build is not staged in local server yet, clean up the temp
1195 # folder used to store image files after the provision is completed.
1196 delete_build_folder = bool(not build_local_path)
1197
1198 try:
1199 # Download image files needed for provision to a local directory.
1200 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001201 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001202
1203 # Device needs to be in bootloader mode for flashing.
1204 self.ensure_bootloader_mode()
1205
1206 if wipe:
Dan Shie4e807b2015-12-10 09:04:03 -08001207 self.fastboot_run('-w')
Dan Shia2872172015-10-31 01:16:51 -07001208
1209 # Get all *.img file in the build_local_path.
1210 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001211 image_files = self.teststation.run(
1212 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001213 images = dict([(os.path.basename(f), f) for f in image_files])
Dan Shi49d451f2016-04-19 09:25:01 -07001214 build_info = self.get_build_info_from_build_url(build_url)
1215 board = build_info['build_target']
1216 all_images = (
1217 android_utils.AndroidImageFiles.get_standalone_images(board)
1218 + android_utils.AndroidImageFiles.get_zipped_images(board))
1219
1220 # Sort images to be flashed, bootloader needs to be the first one.
1221 bootloader = android_utils.AndroidImageFiles.BOOTLOADER
1222 sorted_images = sorted(
1223 images.items(),
1224 key=lambda pair: 0 if pair[0] == bootloader else 1)
1225 for image, image_file in sorted_images:
1226 if image not in all_images:
Dan Shia2872172015-10-31 01:16:51 -07001227 continue
1228 logging.info('Flashing %s...', image_file)
Dan Shi70c30192016-03-22 23:14:12 -07001229 self.fastboot_run('-S 256M flash %s %s' %
Dan Shie9913d32016-03-09 14:17:26 -08001230 (image[:-4], image_file))
Dan Shi49d451f2016-04-19 09:25:01 -07001231 if image == android_utils.AndroidImageFiles.BOOTLOADER:
Dan Shia2872172015-10-31 01:16:51 -07001232 self.fastboot_run('reboot-bootloader')
1233 self.wait_up(command=FASTBOOT_CMD)
1234 except Exception as e:
1235 logging.error('Install Android build failed with error: %s', e)
1236 # Re-raise the exception with type of AndroidInstallError.
1237 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1238 finally:
1239 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001240 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001241 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1242 DEFAULT_WAIT_UP_TIME_SECONDS)
1243 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001244 logging.info('Successfully installed Android build staged at %s.',
1245 build_url)
1246
1247
Dan Shiab999722015-12-04 14:27:08 -08001248 def install_brillo(self, build_url, build_local_path=None):
1249 """Install the Brillo DUT.
1250
1251 Following are the steps used here to provision an android device:
1252 1. If build_local_path is not set, download the image zip file, e.g.,
1253 dragonboard-img-123456.zip, unzip it. And download the vendor
1254 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1255 unzip it to vendor folder.
1256 2. Run provision_device script to install OS images and vendor
1257 partitions.
1258
1259 @param build_url: The url to use for downloading Android artifacts.
1260 pattern: http://$devserver:###/static/$build
1261 @param build_local_path: The path to a local folder that contains the
1262 image files needed to provision the device. Note that the folder
1263 is in the machine running adb command, rather than the drone.
1264
1265 @raises AndroidInstallError if any error occurs.
1266 """
1267 # If the build is not staged in local server yet, clean up the temp
1268 # folder used to store image files after the provision is completed.
1269 delete_build_folder = bool(not build_local_path)
1270
Dan Shiab999722015-12-04 14:27:08 -08001271 try:
1272 # Download image files needed for provision to a local directory.
1273 if not build_local_path:
1274 build_local_path = self.stage_brillo_image_files(build_url)
1275
1276 # Device needs to be in bootloader mode for flashing.
1277 self.ensure_bootloader_mode()
1278
1279 # Run provision_device command to install image files and vendor
1280 # partitions.
1281 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1282 cmd = (BRILLO_PROVISION_CMD %
1283 {'os_image_dir': build_local_path,
1284 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001285 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001286 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001287 self.teststation.run(cmd)
1288 except Exception as e:
1289 logging.error('Install Brillo build failed with error: %s', e)
1290 # Re-raise the exception with type of AndroidInstallError.
1291 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1292 finally:
1293 if delete_build_folder:
1294 self.teststation.run('rm -rf %s' % build_local_path)
1295 self.ensure_adb_mode()
1296 logging.info('Successfully installed Android build staged at %s.',
1297 build_url)
1298
1299
Dan Shibe3636a2016-02-14 22:48:01 -08001300 @property
1301 def job_repo_url_attribute(self):
1302 """Get the host attribute name for job_repo_url, which should append the
1303 adb serial.
1304 """
1305 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1306
1307
Dan Shie4e807b2015-12-10 09:04:03 -08001308 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001309 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001310 """Install the DUT.
1311
1312 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001313 pattern: http://$devserver:###/static/$build. If build_url is
1314 set to None, the code may try _parser.options.image to do the
1315 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001316 @param build_local_path: The path to a local directory that contains the
1317 image files needed to provision the device.
1318 @param wipe: If true, userdata will be wiped before flashing.
1319 @param flash_all: If True, all img files found in img_path will be
1320 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001321
Dan Shibe3636a2016-02-14 22:48:01 -08001322 @returns A tuple of (image_name, host_attributes).
1323 image_name is the name of image installed, e.g.,
1324 git_mnc-release/shamu-userdebug/1234
1325 host_attributes is a dictionary of (attribute, value), which
1326 can be saved to afe_host_attributes table in database. This
1327 method returns a dictionary with a single entry of
1328 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1329 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001330 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001331 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001332 if not build_url and self._parser.options.image:
1333 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001334 self._parser.options.image, os_type=os_type)
1335 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001336 self.install_android(
1337 build_url=build_url, build_local_path=build_local_path,
1338 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001339 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001340 self.install_brillo(
1341 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001342 else:
1343 raise error.InstallError(
1344 'Installation of os type %s is not supported.' %
1345 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001346 return (build_url.split('static/')[-1],
1347 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001348
1349
1350 def list_files_glob(self, path_glob):
1351 """Get a list of files on the device given glob pattern path.
1352
1353 @param path_glob: The path glob that we want to return the list of
1354 files that match the glob. Relative paths will not work as
1355 expected. Supply an absolute path to get the list of files
1356 you're hoping for.
1357
1358 @returns List of files that match the path_glob.
1359 """
1360 # This is just in case path_glob has no path separator.
1361 base_path = os.path.dirname(path_glob) or '.'
1362 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001363 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001364 if result.exit_status != 0:
1365 return []
1366 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001367
1368
Dan Shidb0366c2016-02-19 10:36:18 -08001369 def install_apk(self, apk, force_reinstall=False):
Kevin Cheng31355942016-01-05 14:23:35 -08001370 """Install the specified apk.
1371
1372 This will install the apk and override it if it's already installed and
1373 will also allow for downgraded apks.
1374
1375 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001376 @param force_reinstall: True to reinstall the apk even if it's already
1377 installed. Default is set to False.
1378
1379 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001380 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001381 client_utils.poll_for_condition(
1382 lambda: self.run('pm list packages',
1383 ignore_status=True).exit_status == 0,
1384 timeout=120)
Dan Shi043c45b2016-04-11 17:18:49 -07001385 client_utils.poll_for_condition(
1386 lambda: self.run('service list | grep mount',
1387 ignore_status=True).exit_status == 0,
1388 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001389 return self.adb_run('install %s -d %s' %
1390 ('-r' if force_reinstall else '', apk))
1391
1392
1393 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1394 def _confirm_apk_installed(self, package_name):
1395 """Confirm if apk is already installed with the given name.
1396
1397 `pm list packages` command is not reliable some time. The retry helps to
1398 reduce the chance of false negative.
1399
1400 @param package_name: Name of the package, e.g., com.android.phone.
1401
1402 @raise AutoservRunError: If the package is not found or pm list command
1403 failed for any reason.
1404 """
1405 name = 'package:%s' % package_name
1406 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1407
1408
1409 def is_apk_installed(self, package_name):
1410 """Check if apk is already installed with the given name.
1411
1412 @param package_name: Name of the package, e.g., com.android.phone.
1413
1414 @return: True if package is installed. False otherwise.
1415 """
1416 try:
1417 self._confirm_apk_installed(package_name)
1418 return True
1419 except:
1420 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001421
1422
1423 def get_attributes_to_clear_before_provision(self):
1424 """Get a list of attributes to be cleared before machine_install starts.
1425 """
1426 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001427
1428
1429 def get_labels(self):
1430 """Return a list of the labels gathered from the devices connected.
1431
1432 @return: A list of strings that denote the labels from all the devices
1433 connected.
1434 """
1435 return self.labels.get_labels(self)
1436
1437
1438 def update_labels(self):
1439 """Update the labels for this testbed."""
1440 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001441
1442
1443 def stage_server_side_package(self, image=None):
1444 """Stage autotest server-side package on devserver.
1445
1446 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1447
1448 @return: A url to the autotest server-side package. Return None if
1449 server-side package is not supported.
1450 @raise: error.AutoservError if fail to locate the build to test with.
1451 """
1452 if image:
1453 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1454 else:
1455 job_repo_url = afe_utils.get_host_attribute(
1456 self, self.job_repo_url_attribute)
1457 if job_repo_url:
1458 devserver_url, image = (
1459 tools.get_devserver_build_from_package_url(
1460 job_repo_url, True))
1461 ds = dev_server.AndroidBuildServer(devserver_url)
1462 else:
1463 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1464 if not labels:
1465 raise error.AutoservError(
1466 'Failed to stage server-side package. The host has '
1467 'no job_report_url attribute or version label.')
1468 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1469 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1470
1471 branch, target, build_id = utils.parse_launch_control_build(image)
1472 build_target, _ = utils.parse_launch_control_target(target)
1473
1474 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1475 # packaging is not supported.
1476 try:
1477 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1478 logging.warn('Build %s is older than %s. Server side packaging '
1479 'is disabled.', image,
1480 self.MIN_VERSION_SUPPORT_SSP)
1481 return None
1482 except ValueError:
1483 logging.warn('Failed to compare build id in %s with the minimum '
1484 'version that supports server side packaging. Server '
1485 'side packaging is disabled.', image)
1486 return None
1487
1488 ds.stage_artifacts(target, build_id, branch,
1489 artifacts=['autotest_server_package'])
1490 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1491 {'build_target': build_target,
1492 'build_id': build_id})
1493 return '%s/static/%s/%s' % (ds.url(), image,
1494 autotest_server_package_name)