blob: ee2ac6b64e280c50049875835d81a3bf0bc32953 [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
Dan Shi12a4f662016-05-10 14:49:42 -0700115# Default timeout in minutes for fastboot commands.
116DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN = 10
117
David Purselle01548b2016-05-11 10:00:42 -0700118# Default permissions for files/dirs copied from the device.
119_DEFAULT_FILE_PERMS = 0o600
120_DEFAULT_DIR_PERMS = 0o700
121
Dan Shia2872172015-10-31 01:16:51 -0700122class AndroidInstallError(error.InstallError):
123 """Generic error for Android installation related exceptions."""
124
125
Simran Basi724b8a52013-09-30 11:19:31 -0700126class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700127 """This class represents a host running an ADB server."""
128
Simran Basi5ace6f22016-01-06 17:30:44 -0800129 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700130 _LABEL_FUNCTIONS = []
131 _DETECTABLE_LABELS = []
132 label_decorator = functools.partial(utils.add_label_detector,
133 _LABEL_FUNCTIONS,
134 _DETECTABLE_LABELS)
135
Dan Shi225b9042015-11-18 10:25:21 -0800136 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700137
Dan Shi6450e142016-03-11 11:52:20 -0800138 # Minimum build id that supports server side packaging. Older builds may
139 # not have server side package built or with Autotest code change to support
140 # server-side packaging.
141 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
142 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
143
beeps46dadc92013-11-07 14:07:10 -0800144 @staticmethod
145 def check_host(host, timeout=10):
146 """
147 Check if the given host is an adb host.
148
Simran Basi14622bb2015-11-25 13:23:40 -0800149 If SSH connectivity can't be established, check_host will try to use
150 user 'adb' as well. If SSH connectivity still can't be established
151 then the original SSH user is restored.
152
beeps46dadc92013-11-07 14:07:10 -0800153 @param host: An ssh host representing a device.
154 @param timeout: The timeout for the run command.
155
156
157 @return: True if the host device has adb.
158
159 @raises AutoservRunError: If the command failed.
160 @raises AutoservSSHTimeout: Ssh connection has timed out.
161 """
Dan Shi64e130f2015-12-16 14:45:44 -0800162 # host object may not have user attribute if it's a LocalHost object.
163 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800164 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800165 if not (host.hostname == 'localhost' or
166 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700167 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700168 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700169 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700170 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800171 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800172 if current_user is not None:
173 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800174 return False
175 return result.exit_status == 0
176
177
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700178 # TODO(garnold) Remove the 'serials' argument once all clients are made to
179 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700180 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700181 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700182 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700183 """Initialize an ADB Host.
184
185 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700186 test station connected to an Android DUT. This will be the DUT
187 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700188 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700189
190 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700191 @param serials: DEPRECATED (to be removed)
192 @param adb_serial: An ADB device serial. If None, assume a single
193 device is attached (and fail otherwise).
194 @param fastboot_serial: A fastboot device serial. If None, defaults to
195 the ADB serial (or assumes a single device if
196 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800197 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700198 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800199 # Sets up the is_client_install_supported field.
200 super(ADBHost, self)._initialize(hostname=hostname,
201 is_client_install_supported=False,
202 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800203
Kevin Chengd19e6c62015-10-28 16:39:39 -0700204 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800205 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi1bf60eb2015-12-01 16:39:29 -0800206 # TODO (sbasi/kevcheng): Once the teststation host is committed,
207 # refactor the serial retrieval.
208 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800209 self.adb_serial = adb_serial
Dan Shi3a011ed2016-04-26 12:26:53 -0700210 if adb_serial:
211 adb_prefix = any(adb_serial.startswith(p)
212 for p in ADB_DEVICE_PREFIXES)
213 self.fastboot_serial = (fastboot_serial or
214 ('tcp:%s' % adb_serial.split(':')[0] if
215 ':' in adb_serial and not adb_prefix else adb_serial))
216 self._use_tcpip = ':' in adb_serial and not adb_prefix
217 else:
218 self.fastboot_serial = fastboot_serial or adb_serial
219 self._use_tcpip = False
Kevin Cheng85e864a2015-11-30 11:49:34 -0800220 self.teststation = (teststation if teststation
221 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700222
223 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800224 if self.adb_serial:
225 msg += ', ADB serial: %s' % self.adb_serial
226 if self.fastboot_serial:
227 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700228 logging.debug(msg)
229
Simran Basibeb2bb22016-02-03 15:25:48 -0800230 # Try resetting the ADB daemon on the device, however if we are
231 # creating the host to do a repair job, the device maybe inaccesible
232 # via ADB.
233 try:
234 self._reset_adbd_connection()
235 except (error.AutotestHostRunError, error.AutoservRunError) as e:
236 logging.error('Unable to reset the device adb daemon connection: '
237 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800238 self._os_type = None
239
Simran Basi431010f2013-09-04 10:42:41 -0700240
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700241 def _connect_over_tcpip_as_needed(self):
242 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700243 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700244 return
245 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700246 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700247
248
Roshan Pius4d7540c2015-12-16 13:30:32 -0800249 def _restart_adbd_with_root_permissions(self):
250 """Restarts the adb daemon with root permissions."""
Dan Shi922de302016-04-22 15:19:18 -0700251 @retry.retry(error.AutoservRunError, timeout_min=20/60.0, delay_sec=1)
252 def run_adb_root():
253 """Run command `adb root`."""
254 self.adb_run('root')
255
256 # adb command may flake with error "device not found". Retry the root
257 # command to reduce the chance of flake.
258 run_adb_root()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800259 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
260 time.sleep(1)
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300261 self._connect_over_tcpip_as_needed()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800262 self.adb_run('wait-for-device')
263
264
Simran Basi9228a6f2016-03-29 12:03:37 -0700265 def _set_tcp_port(self):
266 """Ensure the device remains in tcp/ip mode after a reboot."""
267 if not self._use_tcpip:
268 return
269 port = self.adb_serial.split(':')[-1]
270 self.run('setprop persist.adb.tcp.port %s' % port)
271
272
Roshan Pius4d7540c2015-12-16 13:30:32 -0800273 def _reset_adbd_connection(self):
274 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800275 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700276 self._restart_adbd_with_root_permissions()
277 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800278
279
Kevin Cheng85e864a2015-11-30 11:49:34 -0800280 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800281 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700282 """Runs an adb command.
283
Kevin Chengd19e6c62015-10-28 16:39:39 -0700284 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700285
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700286 Refer to _device_run method for docstring for parameters.
287 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800288 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700289
290
Kevin Cheng85e864a2015-11-30 11:49:34 -0800291 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800292 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700293 """Runs an fastboot command.
294
Kevin Chengd19e6c62015-10-28 16:39:39 -0700295 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700296
297 Refer to _device_run method for docstring for parameters.
298 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800299 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700300
301
Dan Shi12a4f662016-05-10 14:49:42 -0700302 # pylint: disable=missing-docstring
303 @retry.retry(error.AutoservRunError,
304 timeout_min=DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN)
305 def _fastboot_run_with_retry(self, command, **kwargs):
306 """Runs an fastboot command with retry.
307
308 This command will launch on the test station.
309
310 Refer to _device_run method for docstring for parameters.
311 """
312 return self.fastboot_run(command, **kwargs)
313
314
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700315 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700316 timeout=3600, ignore_status=False, ignore_timeout=False,
317 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
318 connect_timeout=30, options='', stdin=None, verbose=True,
319 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700320 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700321
Kevin Chengd19e6c62015-10-28 16:39:39 -0700322 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700323
Simran Basi431010f2013-09-04 10:42:41 -0700324 @param command: Command to run.
325 @param shell: If true the command runs in the adb shell otherwise if
326 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700327 reboot with shell=False will call 'adb reboot'. This
328 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700329 @param timeout: Time limit in seconds before attempting to
330 kill the running process. The run() function
331 will take a few seconds longer than 'timeout'
332 to complete if it has to kill the process.
333 @param ignore_status: Do not raise an exception, no matter
334 what the exit code of the command is.
335 @param ignore_timeout: Bool True if command timeouts should be
336 ignored. Will return None on command timeout.
337 @param stdout: Redirect stdout.
338 @param stderr: Redirect stderr.
339 @param connect_timeout: Connection timeout (in seconds)
340 @param options: String with additional ssh command options
341 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700342 @param require_sudo: True to require sudo to run the command. Default is
343 False.
Simran Basi431010f2013-09-04 10:42:41 -0700344 @param args: Sequence of strings to pass as arguments to command by
345 quoting them in " and escaping their contents if
346 necessary.
347
348 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700349 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700350 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800351 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700352 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800353 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700354 else:
355 raise NotImplementedError('Mode %s is not supported' % function)
356
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700357 if function != ADB_CMD and shell:
358 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700359
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700360 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700361
362 if serial:
363 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700364
Simran Basi431010f2013-09-04 10:42:41 -0700365 if shell:
366 cmd += '%s ' % SHELL_CMD
367 cmd += command
368
Roshan Pius58e5dd32015-10-16 15:16:42 -0700369 if verbose:
370 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700371
Kevin Cheng85e864a2015-11-30 11:49:34 -0800372 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400373 ignore_status=ignore_status,
374 ignore_timeout=ignore_timeout, stdout_tee=stdout,
375 stderr_tee=stderr, options=options, stdin=stdin,
376 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700377
378
Dan Shie234dea2016-01-20 17:15:17 -0800379 def get_board_name(self):
380 """Get the name of the board, e.g., shamu, dragonboard etc.
381 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700382 product = self.run_output('getprop %s' % BOARD_FILE)
383 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800384
385
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700386 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700387 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700388 """Determine the correct board label for the device.
389
390 @returns a string representing this device's board.
391 """
Dan Shie234dea2016-01-20 17:15:17 -0800392 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700393 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800394 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700395
396
Christopher Wiley08849d52013-11-22 08:57:58 -0800397 def job_start(self):
398 """
399 Disable log collection on adb_hosts.
400
401 TODO(sbasi): crbug.com/305427
Christopher Wiley08849d52013-11-22 08:57:58 -0800402 """
403
404
Simran Basi431010f2013-09-04 10:42:41 -0700405 def run(self, command, timeout=3600, ignore_status=False,
406 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
407 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700408 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700409 """Run a command on the adb device.
410
411 The command given will be ran directly on the adb device; for example
412 'ls' will be ran as: 'abd shell ls'
413
414 @param command: The command line string.
415 @param timeout: Time limit in seconds before attempting to
416 kill the running process. The run() function
417 will take a few seconds longer than 'timeout'
418 to complete if it has to kill the process.
419 @param ignore_status: Do not raise an exception, no matter
420 what the exit code of the command is.
421 @param ignore_timeout: Bool True if command timeouts should be
422 ignored. Will return None on command timeout.
423 @param stdout_tee: Redirect stdout.
424 @param stderr_tee: Redirect stderr.
425 @param connect_timeout: Connection timeout (in seconds).
426 @param options: String with additional ssh command options.
427 @param stdin: Stdin to pass (a string) to the executed command
428 @param args: Sequence of strings to pass as arguments to command by
429 quoting them in " and escaping their contents if
430 necessary.
431
432 @returns A CMDResult object or None if the call timed out and
433 ignore_timeout is True.
434
435 @raises AutoservRunError: If the command failed.
436 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700437 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700438 command = ('"%s; echo %s:\$?"' %
439 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700440 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700441 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700442 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
443 stdout=stdout_tee, stderr=stderr_tee,
444 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700445 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700446 if not result:
447 # In case of timeouts.
448 return None
449
450 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700451 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700452 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700453 'Failed to parse the exit code for command: %s' %
454 command, result)
455 elif parse_output:
456 result.stdout = parse_output.group('OUTPUT')
457 result.exit_status = int(parse_output.group('EXIT_CODE'))
458 if result.exit_status != 0 and not ignore_status:
459 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700460 return result
461
462
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700463 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
464 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700465
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700466 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700467
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700468 @param timeout: Time limit in seconds before returning even if the host
469 is not up.
470 @param command: The command used to test if a device is up, i.e.,
471 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700472
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700473 @returns True if the host was found to be up before the timeout expires,
474 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700475 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700476 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
477 delay_sec=1)
478 def _wait_up():
479 if not self.is_up(command=command):
480 raise error.TimeoutException('Device is still down.')
481 return True
482
483 try:
484 _wait_up()
485 logging.debug('Host %s is now up, and can be accessed by %s.',
486 self.hostname, command)
487 return True
488 except error.TimeoutException:
489 logging.debug('Host %s is still down after waiting %d seconds',
490 self.hostname, timeout)
491 return False
Simran Basi431010f2013-09-04 10:42:41 -0700492
493
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700494 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
495 warning_timer=None, old_boot_id=None, command=ADB_CMD):
496 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700497
498 Overrides wait_down from AbstractSSHHost.
499
500 @param timeout: Time in seconds to wait for the host to go down.
501 @param warning_timer: Time limit in seconds that will generate
502 a warning if the host is not down yet.
503 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700504 @param old_boot_id: Not applicable for adb_host.
505 @param command: `adb`, test if the device can be accessed by adb
506 command, or `fastboot`, test if the device can be accessed by
507 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700508
509 @returns True if the device goes down before the timeout, False
510 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700511 """
512 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
513 delay_sec=1)
514 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700515 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700516 raise error.TimeoutException('Device is still up.')
517 return True
518
519 try:
520 _wait_down()
521 logging.debug('Host %s is now down', self.hostname)
522 return True
523 except error.TimeoutException:
524 logging.debug('Host %s is still up after waiting %d seconds',
525 self.hostname, timeout)
526 return False
527
528
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700529 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700530 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700531
532 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700533 """
534 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700535 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700536 self.adb_run('reboot', timeout=10, ignore_timeout=True)
537 if not self.wait_down():
538 raise error.AutoservRebootError(
539 'ADB Device is still up after reboot')
540 if not self.wait_up():
541 raise error.AutoservRebootError(
542 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800543 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800544
545
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300546 def fastboot_reboot(self):
547 """Do a fastboot reboot to go back to adb.
548
549 @raises AutoservRebootError if reboot failed.
550 """
551 self.fastboot_run('reboot')
552 if not self.wait_down(command=FASTBOOT_CMD):
553 raise error.AutoservRebootError(
554 'Device is still in fastboot mode after reboot')
555 if not self.wait_up():
556 raise error.AutoservRebootError(
557 'Device failed to boot to adb after fastboot reboot.')
558 self._reset_adbd_connection()
559
560
Ralph Nathanb45eb672015-11-18 20:04:39 -0800561 def remount(self):
562 """Remounts paritions on the device read-write.
563
564 Specifically, the /system, /vendor (if present) and /oem (if present)
565 partitions on the device are remounted read-write.
566 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800567 self.adb_run('remount')
568
569
Kevin Cheng549beb42015-11-18 11:42:25 -0800570 @staticmethod
571 def parse_device_serials(devices_output):
572 """Return a list of parsed serials from the output.
573
574 @param devices_output: Output from either an adb or fastboot command.
575
576 @returns List of device serials
577 """
578 devices = []
579 for line in devices_output.splitlines():
580 match = re.search(DEVICE_FINDER_REGEX, line)
581 if match:
582 serial = match.group('SERIAL')
583 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
584 serial = DEVICE_NO_SERIAL_TAG
585 logging.debug('Found Device: %s', serial)
586 devices.append(serial)
587 return devices
588
589
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700590 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700591 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700592
593 @params use_adb: True to get adb accessible devices. Set to False to
594 get fastboot accessible devices.
595
Kevin Chengd19e6c62015-10-28 16:39:39 -0700596 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700597 """
598 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300599 result = self.adb_run('devices').stdout
600 if self.adb_serial and self.adb_serial not in result:
601 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700602 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300603 result = self.fastboot_run('devices').stdout
604 if (self.fastboot_serial and
605 self.fastboot_serial not in result):
606 # fastboot devices won't list the devices using TCP
607 try:
608 if 'product' in self.fastboot_run('getvar product',
609 timeout=2).stderr:
610 result += '\n%s\tfastboot' % self.fastboot_serial
Kevin Chengcfcb2cf2016-04-13 10:04:36 -0700611 # The main reason we do a general Exception catch here instead
612 # of setting ignore_timeout/status to True is because even when
613 # the fastboot process has been nuked, it still stays around and
614 # so bgjob wants to warn us of this and tries to read the
615 # /proc/<pid>/stack file which then promptly returns an
616 # 'Operation not permitted' error since we're running as moblab
617 # and we don't have permission to read those files.
618 except Exception:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300619 pass
620 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700621
622
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700623 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700624 """Get a list of devices currently attached to the test station and
625 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700626 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800627 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700628 raise error.AutoservError(
629 'Not given ADB serial but multiple devices detected')
630 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700631
632
633 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700634 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700635 accessible by fastboot command.
636 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700637 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800638 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700639 raise error.AutoservError(
640 'Not given fastboot serial but multiple devices detected')
641 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700642
643
644 def is_up(self, timeout=0, command=ADB_CMD):
645 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700646
647 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700648 @param command: `adb`, the device can be accessed by adb command,
649 or `fastboot`, the device can be accessed by fastboot command.
650 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700651
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700652 @returns True if the device is detectable by given command, False
653 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700654
655 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700656 if command == ADB_CMD:
657 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800658 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800659 # ADB has a device state, if the device is not online, no
660 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800661 # DUT with single device connected may not have adb_serial set.
662 # Therefore, skip checking if serial is in the list of adb devices
663 # if self.adb_serial is not set.
664 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800665 logging.debug('Waiting for device to enter the ready state.')
666 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700667 elif command == FASTBOOT_CMD:
668 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800669 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700670 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700671 raise NotImplementedError('Mode %s is not supported' % command)
672
673 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700674
675
676 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700677 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700678
679 Called as the test ends. Will return the device to USB mode and kill
680 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700681 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800682 # TODO(sbasi) Originally, we would kill the server after each test to
683 # reduce the opportunity for bad server state to hang around.
684 # Unfortunately, there is a period of time after each kill during which
685 # the Android device becomes unusable, and if we start the next test
686 # too quickly, we'll get an error complaining about no ADB device
687 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700688 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800689 # |close| the associated teststation as well.
690 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700691 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700692
693
694 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700695 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700696
697 @param message String message to log into syslog
698 @param tag String tag prefix for syslog
699
700 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700701 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700702
703
704 def get_autodir(self):
705 """Return the directory to install autotest for client side tests."""
706 return '/data/autotest'
707
Kevin Cheng018db352015-09-20 02:22:08 -0700708
Kris Rambishde8f9d12015-12-16 12:42:41 -0800709 def is_device_ready(self):
710 """Return the if the device is ready for ADB commands."""
Dan Shi7075f552016-04-21 15:42:41 -0700711 try:
712 # Retry to avoid possible flakes.
713 is_ready = client_utils.poll_for_condition(
714 lambda: self.adb_run('get-state').stdout.strip() == 'device',
715 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS, sleep_interval=1,
716 desc='Waiting for device state to be `device`')
717 except client_utils.TimeoutError:
718 is_ready = False
719
720 logging.debug('Device state is %sready', '' if is_ready else 'NOT ')
721 return is_ready
Kris Rambishde8f9d12015-12-16 12:42:41 -0800722
723
Kevin Chengd19e6c62015-10-28 16:39:39 -0700724 def verify_connectivity(self):
725 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800726 if not self.is_device_ready():
727 raise error.AutoservHostError('device state is not in the '
728 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700729
730
Simran Basid3ba3fb2015-09-11 14:35:07 -0700731 def verify_software(self):
732 """Verify working software on an adb_host.
733
Simran Basi38f7ddf2015-09-18 12:25:03 -0700734 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700735 """
Dan Shiab999722015-12-04 14:27:08 -0800736 # Check if adb and fastboot are present.
737 self.teststation.run('which adb')
738 self.teststation.run('which fastboot')
739 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700740
Dan Shi1e2a98a2016-05-18 12:08:08 -0700741 # Make sure ro.boot.hardware and ro.build.product match. This check is
742 # not applicable to Brillo.
743 if self.get_os_type() == OS_TYPE_ANDROID:
744 hardware = self.run_output('getprop ro.boot.hardware')
745 product = self.run_output('getprop ro.build.product')
746 if hardware != product:
747 raise error.AutoservHostError('ro.boot.hardware: %s does not '
748 'match to ro.build.product: %s' %
749 (hardware, product))
750
Kevin Cheng018db352015-09-20 02:22:08 -0700751
Simran Basid3ba3fb2015-09-11 14:35:07 -0700752 def verify_job_repo_url(self, tag=''):
753 """Make sure job_repo_url of this host is valid.
754
Simran Basi38f7ddf2015-09-18 12:25:03 -0700755 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700756
757 @param tag: The tag from the server job, in the format
758 <job_id>-<user>/<hostname>, or <hostless> for a server job.
759 """
760 return
Kevin Cheng018db352015-09-20 02:22:08 -0700761
762
Simran Basibeb2bb22016-02-03 15:25:48 -0800763 def repair(self):
764 """Attempt to get the DUT to pass `self.verify()`."""
765 try:
766 self.ensure_adb_mode(timeout=30)
767 return
768 except error.AutoservError as e:
769 logging.error(e)
770 logging.debug('Verifying the device is accessible via fastboot.')
771 self.ensure_bootloader_mode()
772 if not self.job.run_test(
773 'provision_AndroidUpdate', host=self, value=None,
774 force=True, repair=True):
775 raise error.AutoservRepairTotalFailure(
776 'Unable to repair the device.')
777
778
Simran Basi1b023762015-09-25 12:12:20 -0700779 def send_file(self, source, dest, delete_dest=False,
780 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700781 """Copy files from the drone to the device.
782
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400783 Just a note, there is the possibility the test station is localhost
784 which makes some of these steps redundant (e.g. creating tmp dir) but
785 that scenario will undoubtedly be a development scenario (test station
786 is also the moblab) and not the typical live test running scenario so
787 the redundancy I think is harmless.
788
Kevin Cheng018db352015-09-20 02:22:08 -0700789 @param source: The file/directory on the drone to send to the device.
790 @param dest: The destination path on the device to copy to.
791 @param delete_dest: A flag set to choose whether or not to delete
792 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700793 @param preserve_symlinks: Controls if symlinks on the source will be
794 copied as such on the destination or
795 transformed into the referenced
796 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700797 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700798 # If we need to preserve symlinks, let's check if the source is a
799 # symlink itself and if so, just create it on the device.
800 if preserve_symlinks:
801 symlink_target = None
802 try:
803 symlink_target = os.readlink(source)
804 except OSError:
805 # Guess it's not a symlink.
806 pass
807
808 if symlink_target is not None:
809 # Once we create the symlink, let's get out of here.
810 self.run('ln -s %s %s' % (symlink_target, dest))
811 return
812
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400813 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700814 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400815 src_path = os.path.join(tmp_dir, os.path.basename(dest))
816 # Now copy the file over to the test station so you can reference the
817 # file in the push command.
818 self.teststation.send_file(source, src_path,
819 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700820
821 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400822 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700823
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700824 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700825
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400826 # Cleanup the test station.
827 try:
828 self.teststation.run('rm -rf %s' % tmp_dir)
829 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
830 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700831
832
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700833 def _get_file_info(self, dest):
834 """Get permission and possible symlink info about file on the device.
835
836 These files are on the device so we only have shell commands (via adb)
837 to get the info we want. We'll use 'ls' to get it all.
838
839 @param dest: File to get info about.
840
841 @returns a dict of the file permissions and symlink.
842 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800843 # Grab file info.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700844 file_info = self.run_output('ls -ld %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700845 symlink = None
846 perms = 0
847 match = re.match(FILE_INFO_REGEX, file_info)
848 if match:
849 # Check if it's a symlink and grab the linked dest if it is.
850 if match.group('TYPE') == 'l':
851 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
852 if symlink_match:
853 symlink = symlink_match.group('SYMLINK')
854
855 # Set the perms.
856 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
857 if perm != '-':
858 perms |= perm_flag
859
860 return {'perms': perms,
861 'symlink': symlink}
862
863
Simran Basi1b023762015-09-25 12:12:20 -0700864 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
865 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700866 """Copy files from the device to the drone.
867
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400868 Just a note, there is the possibility the test station is localhost
869 which makes some of these steps redundant (e.g. creating tmp dir) but
870 that scenario will undoubtedly be a development scenario (test station
871 is also the moblab) and not the typical live test running scenario so
872 the redundancy I think is harmless.
873
Kevin Cheng018db352015-09-20 02:22:08 -0700874 @param source: The file/directory on the device to copy back to the
875 drone.
876 @param dest: The destination path on the drone to copy to.
877 @param delete_dest: A flag set to choose whether or not to delete
878 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700879 @param preserve_perm: Tells get_file() to try to preserve the sources
880 permissions on files and dirs.
881 @param preserve_symlinks: Try to preserve symlinks instead of
882 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700883 """
David Purselle01548b2016-05-11 10:00:42 -0700884 # Stage the files on the test station under teststation_temp_dir.
885 teststation_temp_dir = self.teststation.get_tmp_dir()
886 teststation_dest = os.path.join(teststation_temp_dir,
887 os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700888
David Purselle01548b2016-05-11 10:00:42 -0700889 # If dest is a directory, source will be put under it.
890 if os.path.isdir(dest):
891 receive_path = os.path.join(dest, os.path.basename(source))
892 else:
893 receive_path = dest
Kevin Cheng018db352015-09-20 02:22:08 -0700894
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700895 source_info = {}
896 if preserve_symlinks or preserve_perm:
897 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700898
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700899 # If we want to preserve symlinks, just create it here, otherwise pull
900 # the file off the device.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700901 #
902 # TODO(sadmac): Directories containing symlinks won't behave as
903 # expected.
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700904 if preserve_symlinks and source_info['symlink']:
905 os.symlink(source_info['symlink'], dest)
906 else:
David Purselle01548b2016-05-11 10:00:42 -0700907 self.adb_run('pull %s %s' % (source, teststation_temp_dir))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700908
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400909 # Copy over the file from the test station and clean up.
David Purselle01548b2016-05-11 10:00:42 -0700910 self.teststation.get_file(teststation_dest, dest,
911 delete_dest=delete_dest)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400912 try:
David Purselle01548b2016-05-11 10:00:42 -0700913 self.teststation.run('rm -rf %s' % teststation_temp_dir)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400914 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
David Purselle01548b2016-05-11 10:00:42 -0700915 logging.warn('failed to remove dir %s: %s',
916 teststation_temp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700917
David Purselle01548b2016-05-11 10:00:42 -0700918 # Set the permissions of the received file/dirs.
919 if os.path.isdir(receive_path):
920 for root, _dirs, files in os.walk(receive_path):
921 def process(rel_path, default_perm):
922 info = self._get_file_info(os.path.join(source, rel_path))
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700923
David Purselle01548b2016-05-11 10:00:42 -0700924 if info['perms'] != 0:
925 target = os.path.join(receive_path, rel_path)
926 if preserve_perm:
927 os.chmod(target, info['perms'])
928 else:
929 os.chmod(target, default_perm)
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700930
David Purselle01548b2016-05-11 10:00:42 -0700931 rel_root = os.path.relpath(root, receive_path)
932 process(rel_root, _DEFAULT_DIR_PERMS)
933 for f in files:
934 process(os.path.join(rel_root, f), _DEFAULT_FILE_PERMS)
935 elif preserve_perm:
936 os.chmod(receive_path, source_info['perms'])
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700937 else:
David Purselle01548b2016-05-11 10:00:42 -0700938 os.chmod(receive_path, _DEFAULT_FILE_PERMS)
Kevin Cheng018db352015-09-20 02:22:08 -0700939
940
941 def get_release_version(self):
942 """Get the release version from the RELEASE_FILE on the device.
943
944 @returns The release string in the RELEASE_FILE.
945
946 """
947 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700948
949
950 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700951 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700952
Kevin Chengd19e6c62015-10-28 16:39:39 -0700953 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700954
955 @param parent: Parent directory of the returned tmp dir.
956
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700957 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700958 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700959 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
960 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700961 if not parent.startswith(TMP_DIR):
962 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700963 self.run('mkdir -p %s' % parent)
964 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
965 self.tmp_dirs.append(tmp_dir)
966 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700967
968
969 def get_platform(self):
970 """Determine the correct platform label for this host.
971
972 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700973 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700974
975 @returns a string representing this host's platform.
976 """
977 return 'adb'
978
979
Gilad Arnolda76bef02015-09-29 13:55:15 -0700980 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800981 """Get the OS type of the DUT, e.g., android or brillo.
982 """
983 if not self._os_type:
984 if self.run_output('getprop ro.product.brand') == 'Brillo':
985 self._os_type = OS_TYPE_BRILLO
986 else:
987 self._os_type = OS_TYPE_ANDROID
988
989 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700990
991
992 def _forward(self, reverse, args):
993 """Execute a forwarding command.
994
995 @param reverse: Whether this is reverse forwarding (Boolean).
996 @param args: List of command arguments.
997 """
998 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700999 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001000
1001
1002 def add_forwarding(self, src, dst, reverse=False, rebind=True):
1003 """Forward a port between the ADB host and device.
1004
1005 Port specifications are any strings accepted as such by ADB, for
1006 example 'tcp:8080'.
1007
1008 @param src: Port specification to forward from.
1009 @param dst: Port specification to forward to.
1010 @param reverse: Do reverse forwarding from device to host (Boolean).
1011 @param rebind: Allow rebinding an already bound port (Boolean).
1012 """
1013 args = []
1014 if not rebind:
1015 args.append('--no-rebind')
1016 args += [src, dst]
1017 self._forward(reverse, args)
1018
1019
1020 def remove_forwarding(self, src=None, reverse=False):
1021 """Removes forwarding on port.
1022
1023 @param src: Port specification, or None to remove all forwarding.
1024 @param reverse: Whether this is reverse forwarding (Boolean).
1025 """
1026 args = []
1027 if src is None:
1028 args.append('--remove-all')
1029 else:
1030 args += ['--remove', src]
1031 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001032
1033
xixuan6cf6d2f2016-01-29 15:29:00 -08001034 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001035 """
1036 Forwards a port securely through a tunnel process from the server
1037 to the DUT for RPC server connection.
1038 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
1039 to the DUT.
1040
1041 @param port: remote port on the DUT.
1042 @param local_port: local forwarding port.
1043
1044 @return: the tunnel process.
1045 """
1046 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001047 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001048
1049
xixuan6cf6d2f2016-01-29 15:29:00 -08001050 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001051 """
1052 Disconnects a previously forwarded port from the server to the DUT for
1053 RPC server connection.
1054 Remove the previously added 'ADB forward' rule to forward the RPC
1055 packets from the AdbHost to the DUT.
1056
1057 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -08001058 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -07001059 @param port: remote port on the DUT.
1060
1061 """
1062 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001063 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001064
1065
1066 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001067 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001068
1069 @raise: error.AutoservError if the device failed to reboot into
1070 bootloader mode.
1071 """
1072 if self.is_up(command=FASTBOOT_CMD):
1073 return
1074 self.adb_run('reboot bootloader')
1075 if not self.wait_up(command=FASTBOOT_CMD):
1076 raise error.AutoservError(
1077 'The device failed to reboot into bootloader mode.')
1078
1079
Dan Shie4e807b2015-12-10 09:04:03 -08001080 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001081 """Ensure the device is up and can be accessed by adb command.
1082
Dan Shie4e807b2015-12-10 09:04:03 -08001083 @param timeout: Time limit in seconds before returning even if the host
1084 is not up.
1085
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001086 @raise: error.AutoservError if the device failed to reboot into
1087 adb mode.
1088 """
1089 if self.is_up():
1090 return
Dan Shi04980372016-03-22 10:57:47 -07001091 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1092 # check if the device is in adb mode.
1093 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001094 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001095 raise error.AutoservError(
1096 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001097 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001098
1099
1100 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001101 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001102 """Get the Android build information from the build url.
1103
1104 @param build_url: The url to use for downloading Android artifacts.
1105 pattern: http://$devserver:###/static/branch/target/build_id
1106
Dan Shi6450e142016-03-11 11:52:20 -08001107 @return: A dictionary of build information, including keys:
1108 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001109 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001110 """
Dan Shiab999722015-12-04 14:27:08 -08001111 if not build_url:
1112 raise AndroidInstallError('Need build_url to download image files.')
1113
1114 try:
1115 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001116 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001117 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001118 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001119 match.group('BUILD_TYPE'))),
1120 'build_id': match.group('BUILD_ID')}
1121 except (AttributeError, IndexError, ValueError) as e:
1122 raise AndroidInstallError(
1123 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001124
1125
Dan Shia2872172015-10-31 01:16:51 -07001126 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001127 def download_file(self, build_url, file, dest_dir, unzip=False,
1128 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001129 """Download the given file from the build url.
1130
1131 @param build_url: The url to use for downloading Android artifacts.
1132 pattern: http://$devserver:###/static/branch/target/build_id
1133 @param file: Name of the file to be downloaded, e.g., boot.img.
1134 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001135 @param unzip: If True, unzip the downloaded file.
1136 @param unzip_dest: Location to unzip the downloaded file to. If not
1137 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001138 """
Dan Shidb0366c2016-02-19 10:36:18 -08001139 # Append the file name to the url if build_url is linked to the folder
1140 # containing the file.
1141 if not build_url.endswith('/%s' % file):
1142 src_url = os.path.join(build_url, file)
1143 else:
1144 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001145 dest_file = os.path.join(dest_dir, file)
1146 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001147 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001148 if unzip:
1149 unzip_dest = unzip_dest or dest_dir
1150 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1151 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001152 except:
1153 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001154 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001155 raise
1156
1157
Dan Shiab999722015-12-04 14:27:08 -08001158 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001159 """Download required image files from the given build_url to a local
1160 directory in the machine runs fastboot command.
1161
1162 @param build_url: The url to use for downloading Android artifacts.
1163 pattern: http://$devserver:###/static/branch/target/build_id
1164
1165 @return: Path to the directory contains image files.
1166 """
Dan Shi08ff1282016-02-18 19:51:16 -08001167 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001168
1169 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001170 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001171
1172 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001173 self.download_file(build_url, zipped_image_file, image_dir,
1174 unzip=True)
Dan Shi49d451f2016-04-19 09:25:01 -07001175 images = android_utils.AndroidImageFiles.get_standalone_images(
1176 build_info['build_target'])
1177 for image_file in images:
Dan Shidb0366c2016-02-19 10:36:18 -08001178 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001179
Dan Shia2872172015-10-31 01:16:51 -07001180 return image_dir
1181 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001182 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001183 raise
1184
1185
Dan Shiab999722015-12-04 14:27:08 -08001186 def stage_brillo_image_files(self, build_url):
1187 """Download required brillo image files from the given build_url to a
1188 local directory in the machine runs fastboot command.
1189
1190 @param build_url: The url to use for downloading Android artifacts.
1191 pattern: http://$devserver:###/static/branch/target/build_id
1192
1193 @return: Path to the directory contains image files.
1194 """
Dan Shi08ff1282016-02-18 19:51:16 -08001195 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001196
1197 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1198 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1199 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001200
1201 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001202 self.download_file(build_url, zipped_image_file, image_dir,
1203 unzip=True)
1204 self.download_file(build_url, vendor_partitions_file, image_dir,
1205 unzip=True,
1206 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001207 return image_dir
1208 except:
1209 self.teststation.run('rm -rf %s' % image_dir)
1210 raise
1211
1212
Simran Basibeb2bb22016-02-03 15:25:48 -08001213 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001214 """Stage a build on a devserver and return the build_url and devserver.
1215
1216 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001217
Dan Shi225b9042015-11-18 10:25:21 -08001218 @returns a tuple with an update URL like:
1219 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1220 and the devserver instance.
1221 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001222 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001223 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001224 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1225 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001226 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001227 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001228 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001229 devserver.trigger_download(target, build_id, branch,
1230 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001231 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001232
1233
Dan Shie4e807b2015-12-10 09:04:03 -08001234 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001235 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001236 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001237
1238 Following are the steps used here to provision an android device:
1239 1. If build_local_path is not set, download the image zip file, e.g.,
1240 shamu-img-2284311.zip, unzip it.
1241 2. Run fastboot to install following artifacts:
1242 bootloader, radio, boot, system, vendor(only if exists)
1243
1244 Repair is not supported for Android devices yet.
1245
1246 @param build_url: The url to use for downloading Android artifacts.
1247 pattern: http://$devserver:###/static/$build
1248 @param build_local_path: The path to a local folder that contains the
1249 image files needed to provision the device. Note that the folder
1250 is in the machine running adb command, rather than the drone.
1251 @param wipe: If true, userdata will be wiped before flashing.
1252 @param flash_all: If True, all img files found in img_path will be
1253 flashed. Otherwise, only boot and system are flashed.
1254
1255 @raises AndroidInstallError if any error occurs.
1256 """
Dan Shia2872172015-10-31 01:16:51 -07001257 # If the build is not staged in local server yet, clean up the temp
1258 # folder used to store image files after the provision is completed.
1259 delete_build_folder = bool(not build_local_path)
1260
1261 try:
1262 # Download image files needed for provision to a local directory.
1263 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001264 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001265
1266 # Device needs to be in bootloader mode for flashing.
1267 self.ensure_bootloader_mode()
1268
1269 if wipe:
Dan Shi12a4f662016-05-10 14:49:42 -07001270 self._fastboot_run_with_retry('-w')
Dan Shia2872172015-10-31 01:16:51 -07001271
1272 # Get all *.img file in the build_local_path.
1273 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001274 image_files = self.teststation.run(
1275 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001276 images = dict([(os.path.basename(f), f) for f in image_files])
Dan Shi49d451f2016-04-19 09:25:01 -07001277 build_info = self.get_build_info_from_build_url(build_url)
1278 board = build_info['build_target']
1279 all_images = (
1280 android_utils.AndroidImageFiles.get_standalone_images(board)
1281 + android_utils.AndroidImageFiles.get_zipped_images(board))
1282
1283 # Sort images to be flashed, bootloader needs to be the first one.
1284 bootloader = android_utils.AndroidImageFiles.BOOTLOADER
1285 sorted_images = sorted(
1286 images.items(),
1287 key=lambda pair: 0 if pair[0] == bootloader else 1)
1288 for image, image_file in sorted_images:
1289 if image not in all_images:
Dan Shia2872172015-10-31 01:16:51 -07001290 continue
1291 logging.info('Flashing %s...', image_file)
Dan Shi12a4f662016-05-10 14:49:42 -07001292 self._fastboot_run_with_retry('-S 256M flash %s %s' %
1293 (image[:-4], image_file))
Dan Shi49d451f2016-04-19 09:25:01 -07001294 if image == android_utils.AndroidImageFiles.BOOTLOADER:
Dan Shia2872172015-10-31 01:16:51 -07001295 self.fastboot_run('reboot-bootloader')
1296 self.wait_up(command=FASTBOOT_CMD)
1297 except Exception as e:
1298 logging.error('Install Android build failed with error: %s', e)
1299 # Re-raise the exception with type of AndroidInstallError.
1300 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1301 finally:
1302 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001303 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001304 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1305 DEFAULT_WAIT_UP_TIME_SECONDS)
1306 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001307 logging.info('Successfully installed Android build staged at %s.',
1308 build_url)
1309
1310
Dan Shiab999722015-12-04 14:27:08 -08001311 def install_brillo(self, build_url, build_local_path=None):
1312 """Install the Brillo DUT.
1313
1314 Following are the steps used here to provision an android device:
1315 1. If build_local_path is not set, download the image zip file, e.g.,
1316 dragonboard-img-123456.zip, unzip it. And download the vendor
1317 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1318 unzip it to vendor folder.
1319 2. Run provision_device script to install OS images and vendor
1320 partitions.
1321
1322 @param build_url: The url to use for downloading Android artifacts.
1323 pattern: http://$devserver:###/static/$build
1324 @param build_local_path: The path to a local folder that contains the
1325 image files needed to provision the device. Note that the folder
1326 is in the machine running adb command, rather than the drone.
1327
1328 @raises AndroidInstallError if any error occurs.
1329 """
1330 # If the build is not staged in local server yet, clean up the temp
1331 # folder used to store image files after the provision is completed.
1332 delete_build_folder = bool(not build_local_path)
1333
Dan Shiab999722015-12-04 14:27:08 -08001334 try:
1335 # Download image files needed for provision to a local directory.
1336 if not build_local_path:
1337 build_local_path = self.stage_brillo_image_files(build_url)
1338
1339 # Device needs to be in bootloader mode for flashing.
1340 self.ensure_bootloader_mode()
1341
1342 # Run provision_device command to install image files and vendor
1343 # partitions.
1344 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1345 cmd = (BRILLO_PROVISION_CMD %
1346 {'os_image_dir': build_local_path,
1347 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001348 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001349 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001350 self.teststation.run(cmd)
1351 except Exception as e:
1352 logging.error('Install Brillo build failed with error: %s', e)
1353 # Re-raise the exception with type of AndroidInstallError.
1354 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1355 finally:
1356 if delete_build_folder:
1357 self.teststation.run('rm -rf %s' % build_local_path)
1358 self.ensure_adb_mode()
1359 logging.info('Successfully installed Android build staged at %s.',
1360 build_url)
1361
1362
Dan Shibe3636a2016-02-14 22:48:01 -08001363 @property
1364 def job_repo_url_attribute(self):
1365 """Get the host attribute name for job_repo_url, which should append the
1366 adb serial.
1367 """
1368 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1369
1370
Dan Shie4e807b2015-12-10 09:04:03 -08001371 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001372 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001373 """Install the DUT.
1374
1375 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001376 pattern: http://$devserver:###/static/$build. If build_url is
1377 set to None, the code may try _parser.options.image to do the
1378 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001379 @param build_local_path: The path to a local directory that contains the
1380 image files needed to provision the device.
1381 @param wipe: If true, userdata will be wiped before flashing.
1382 @param flash_all: If True, all img files found in img_path will be
1383 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001384
Dan Shibe3636a2016-02-14 22:48:01 -08001385 @returns A tuple of (image_name, host_attributes).
1386 image_name is the name of image installed, e.g.,
1387 git_mnc-release/shamu-userdebug/1234
1388 host_attributes is a dictionary of (attribute, value), which
1389 can be saved to afe_host_attributes table in database. This
1390 method returns a dictionary with a single entry of
1391 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1392 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001393 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001394 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001395 if not build_url and self._parser.options.image:
1396 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001397 self._parser.options.image, os_type=os_type)
1398 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001399 self.install_android(
1400 build_url=build_url, build_local_path=build_local_path,
1401 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001402 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001403 self.install_brillo(
1404 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001405 else:
1406 raise error.InstallError(
1407 'Installation of os type %s is not supported.' %
1408 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001409 return (build_url.split('static/')[-1],
1410 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001411
1412
1413 def list_files_glob(self, path_glob):
1414 """Get a list of files on the device given glob pattern path.
1415
1416 @param path_glob: The path glob that we want to return the list of
1417 files that match the glob. Relative paths will not work as
1418 expected. Supply an absolute path to get the list of files
1419 you're hoping for.
1420
1421 @returns List of files that match the path_glob.
1422 """
1423 # This is just in case path_glob has no path separator.
1424 base_path = os.path.dirname(path_glob) or '.'
1425 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001426 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001427 if result.exit_status != 0:
1428 return []
1429 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001430
1431
Dan Shida995002016-04-25 23:12:58 -07001432 def install_apk(self, apk, force_reinstall=True):
Kevin Cheng31355942016-01-05 14:23:35 -08001433 """Install the specified apk.
1434
1435 This will install the apk and override it if it's already installed and
1436 will also allow for downgraded apks.
1437
1438 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001439 @param force_reinstall: True to reinstall the apk even if it's already
Dan Shida995002016-04-25 23:12:58 -07001440 installed. Default is set to True.
Dan Shidb0366c2016-02-19 10:36:18 -08001441
1442 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001443 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001444 client_utils.poll_for_condition(
1445 lambda: self.run('pm list packages',
1446 ignore_status=True).exit_status == 0,
1447 timeout=120)
Dan Shi043c45b2016-04-11 17:18:49 -07001448 client_utils.poll_for_condition(
1449 lambda: self.run('service list | grep mount',
1450 ignore_status=True).exit_status == 0,
1451 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001452 return self.adb_run('install %s -d %s' %
1453 ('-r' if force_reinstall else '', apk))
1454
1455
1456 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1457 def _confirm_apk_installed(self, package_name):
1458 """Confirm if apk is already installed with the given name.
1459
1460 `pm list packages` command is not reliable some time. The retry helps to
1461 reduce the chance of false negative.
1462
1463 @param package_name: Name of the package, e.g., com.android.phone.
1464
1465 @raise AutoservRunError: If the package is not found or pm list command
1466 failed for any reason.
1467 """
1468 name = 'package:%s' % package_name
1469 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1470
1471
1472 def is_apk_installed(self, package_name):
1473 """Check if apk is already installed with the given name.
1474
1475 @param package_name: Name of the package, e.g., com.android.phone.
1476
1477 @return: True if package is installed. False otherwise.
1478 """
1479 try:
1480 self._confirm_apk_installed(package_name)
1481 return True
1482 except:
1483 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001484
1485
1486 def get_attributes_to_clear_before_provision(self):
1487 """Get a list of attributes to be cleared before machine_install starts.
1488 """
1489 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001490
1491
1492 def get_labels(self):
1493 """Return a list of the labels gathered from the devices connected.
1494
1495 @return: A list of strings that denote the labels from all the devices
1496 connected.
1497 """
1498 return self.labels.get_labels(self)
1499
1500
1501 def update_labels(self):
1502 """Update the labels for this testbed."""
1503 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001504
1505
1506 def stage_server_side_package(self, image=None):
1507 """Stage autotest server-side package on devserver.
1508
1509 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1510
1511 @return: A url to the autotest server-side package. Return None if
1512 server-side package is not supported.
1513 @raise: error.AutoservError if fail to locate the build to test with.
1514 """
1515 if image:
1516 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1517 else:
1518 job_repo_url = afe_utils.get_host_attribute(
1519 self, self.job_repo_url_attribute)
1520 if job_repo_url:
1521 devserver_url, image = (
1522 tools.get_devserver_build_from_package_url(
1523 job_repo_url, True))
1524 ds = dev_server.AndroidBuildServer(devserver_url)
1525 else:
1526 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1527 if not labels:
1528 raise error.AutoservError(
1529 'Failed to stage server-side package. The host has '
1530 'no job_report_url attribute or version label.')
1531 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1532 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1533
1534 branch, target, build_id = utils.parse_launch_control_build(image)
1535 build_target, _ = utils.parse_launch_control_target(target)
1536
1537 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1538 # packaging is not supported.
1539 try:
1540 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1541 logging.warn('Build %s is older than %s. Server side packaging '
1542 'is disabled.', image,
1543 self.MIN_VERSION_SUPPORT_SSP)
1544 return None
1545 except ValueError:
1546 logging.warn('Failed to compare build id in %s with the minimum '
1547 'version that supports server side packaging. Server '
1548 'side packaging is disabled.', image)
1549 return None
1550
1551 ds.stage_artifacts(target, build_id, branch,
1552 artifacts=['autotest_server_package'])
1553 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1554 {'build_target': build_target,
1555 'build_id': build_id})
1556 return '%s/static/%s/%s' % (ds.url(), image,
1557 autotest_server_package_name)