blob: 5ebc8ac656c525de0e8fa99589d610d20727ef20 [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
Dan Shia2872172015-10-31 01:16:51 -0700118class AndroidInstallError(error.InstallError):
119 """Generic error for Android installation related exceptions."""
120
121
Simran Basi724b8a52013-09-30 11:19:31 -0700122class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700123 """This class represents a host running an ADB server."""
124
Simran Basi5ace6f22016-01-06 17:30:44 -0800125 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700126 _LABEL_FUNCTIONS = []
127 _DETECTABLE_LABELS = []
128 label_decorator = functools.partial(utils.add_label_detector,
129 _LABEL_FUNCTIONS,
130 _DETECTABLE_LABELS)
131
Dan Shi225b9042015-11-18 10:25:21 -0800132 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700133
Dan Shi6450e142016-03-11 11:52:20 -0800134 # Minimum build id that supports server side packaging. Older builds may
135 # not have server side package built or with Autotest code change to support
136 # server-side packaging.
137 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
138 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
139
beeps46dadc92013-11-07 14:07:10 -0800140 @staticmethod
141 def check_host(host, timeout=10):
142 """
143 Check if the given host is an adb host.
144
Simran Basi14622bb2015-11-25 13:23:40 -0800145 If SSH connectivity can't be established, check_host will try to use
146 user 'adb' as well. If SSH connectivity still can't be established
147 then the original SSH user is restored.
148
beeps46dadc92013-11-07 14:07:10 -0800149 @param host: An ssh host representing a device.
150 @param timeout: The timeout for the run command.
151
152
153 @return: True if the host device has adb.
154
155 @raises AutoservRunError: If the command failed.
156 @raises AutoservSSHTimeout: Ssh connection has timed out.
157 """
Dan Shi64e130f2015-12-16 14:45:44 -0800158 # host object may not have user attribute if it's a LocalHost object.
159 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800160 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800161 if not (host.hostname == 'localhost' or
162 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700163 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700164 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700165 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700166 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800167 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800168 if current_user is not None:
169 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800170 return False
171 return result.exit_status == 0
172
173
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700174 # TODO(garnold) Remove the 'serials' argument once all clients are made to
175 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700176 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700177 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700178 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700179 """Initialize an ADB Host.
180
181 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700182 test station connected to an Android DUT. This will be the DUT
183 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700184 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700185
186 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700187 @param serials: DEPRECATED (to be removed)
188 @param adb_serial: An ADB device serial. If None, assume a single
189 device is attached (and fail otherwise).
190 @param fastboot_serial: A fastboot device serial. If None, defaults to
191 the ADB serial (or assumes a single device if
192 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800193 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700194 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800195 # Sets up the is_client_install_supported field.
196 super(ADBHost, self)._initialize(hostname=hostname,
197 is_client_install_supported=False,
198 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800199
Kevin Chengd19e6c62015-10-28 16:39:39 -0700200 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800201 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi1bf60eb2015-12-01 16:39:29 -0800202 # TODO (sbasi/kevcheng): Once the teststation host is committed,
203 # refactor the serial retrieval.
204 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800205 self.adb_serial = adb_serial
Dan Shi3a011ed2016-04-26 12:26:53 -0700206 if adb_serial:
207 adb_prefix = any(adb_serial.startswith(p)
208 for p in ADB_DEVICE_PREFIXES)
209 self.fastboot_serial = (fastboot_serial or
210 ('tcp:%s' % adb_serial.split(':')[0] if
211 ':' in adb_serial and not adb_prefix else adb_serial))
212 self._use_tcpip = ':' in adb_serial and not adb_prefix
213 else:
214 self.fastboot_serial = fastboot_serial or adb_serial
215 self._use_tcpip = False
Kevin Cheng85e864a2015-11-30 11:49:34 -0800216 self.teststation = (teststation if teststation
217 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700218
219 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800220 if self.adb_serial:
221 msg += ', ADB serial: %s' % self.adb_serial
222 if self.fastboot_serial:
223 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700224 logging.debug(msg)
225
Simran Basibeb2bb22016-02-03 15:25:48 -0800226 # Try resetting the ADB daemon on the device, however if we are
227 # creating the host to do a repair job, the device maybe inaccesible
228 # via ADB.
229 try:
230 self._reset_adbd_connection()
231 except (error.AutotestHostRunError, error.AutoservRunError) as e:
232 logging.error('Unable to reset the device adb daemon connection: '
233 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800234 self._os_type = None
235
Simran Basi431010f2013-09-04 10:42:41 -0700236
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700237 def _connect_over_tcpip_as_needed(self):
238 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700239 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700240 return
241 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700242 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700243
244
Roshan Pius4d7540c2015-12-16 13:30:32 -0800245 def _restart_adbd_with_root_permissions(self):
246 """Restarts the adb daemon with root permissions."""
Dan Shi922de302016-04-22 15:19:18 -0700247 @retry.retry(error.AutoservRunError, timeout_min=20/60.0, delay_sec=1)
248 def run_adb_root():
249 """Run command `adb root`."""
250 self.adb_run('root')
251
252 # adb command may flake with error "device not found". Retry the root
253 # command to reduce the chance of flake.
254 run_adb_root()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800255 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
256 time.sleep(1)
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300257 self._connect_over_tcpip_as_needed()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800258 self.adb_run('wait-for-device')
259
260
Simran Basi9228a6f2016-03-29 12:03:37 -0700261 def _set_tcp_port(self):
262 """Ensure the device remains in tcp/ip mode after a reboot."""
263 if not self._use_tcpip:
264 return
265 port = self.adb_serial.split(':')[-1]
266 self.run('setprop persist.adb.tcp.port %s' % port)
267
268
Roshan Pius4d7540c2015-12-16 13:30:32 -0800269 def _reset_adbd_connection(self):
270 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800271 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700272 self._restart_adbd_with_root_permissions()
273 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800274
275
Kevin Cheng85e864a2015-11-30 11:49:34 -0800276 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800277 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700278 """Runs an adb command.
279
Kevin Chengd19e6c62015-10-28 16:39:39 -0700280 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700281
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700282 Refer to _device_run method for docstring for parameters.
283 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800284 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700285
286
Kevin Cheng85e864a2015-11-30 11:49:34 -0800287 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800288 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700289 """Runs an fastboot command.
290
Kevin Chengd19e6c62015-10-28 16:39:39 -0700291 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700292
293 Refer to _device_run method for docstring for parameters.
294 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800295 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700296
297
Dan Shi12a4f662016-05-10 14:49:42 -0700298 # pylint: disable=missing-docstring
299 @retry.retry(error.AutoservRunError,
300 timeout_min=DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN)
301 def _fastboot_run_with_retry(self, command, **kwargs):
302 """Runs an fastboot command with retry.
303
304 This command will launch on the test station.
305
306 Refer to _device_run method for docstring for parameters.
307 """
308 return self.fastboot_run(command, **kwargs)
309
310
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700311 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700312 timeout=3600, ignore_status=False, ignore_timeout=False,
313 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
314 connect_timeout=30, options='', stdin=None, verbose=True,
315 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700316 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700317
Kevin Chengd19e6c62015-10-28 16:39:39 -0700318 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700319
Simran Basi431010f2013-09-04 10:42:41 -0700320 @param command: Command to run.
321 @param shell: If true the command runs in the adb shell otherwise if
322 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700323 reboot with shell=False will call 'adb reboot'. This
324 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700325 @param timeout: Time limit in seconds before attempting to
326 kill the running process. The run() function
327 will take a few seconds longer than 'timeout'
328 to complete if it has to kill the process.
329 @param ignore_status: Do not raise an exception, no matter
330 what the exit code of the command is.
331 @param ignore_timeout: Bool True if command timeouts should be
332 ignored. Will return None on command timeout.
333 @param stdout: Redirect stdout.
334 @param stderr: Redirect stderr.
335 @param connect_timeout: Connection timeout (in seconds)
336 @param options: String with additional ssh command options
337 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700338 @param require_sudo: True to require sudo to run the command. Default is
339 False.
Simran Basi431010f2013-09-04 10:42:41 -0700340 @param args: Sequence of strings to pass as arguments to command by
341 quoting them in " and escaping their contents if
342 necessary.
343
344 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700345 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700346 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800347 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700348 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800349 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700350 else:
351 raise NotImplementedError('Mode %s is not supported' % function)
352
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700353 if function != ADB_CMD and shell:
354 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700355
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700356 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700357
358 if serial:
359 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700360
Simran Basi431010f2013-09-04 10:42:41 -0700361 if shell:
362 cmd += '%s ' % SHELL_CMD
363 cmd += command
364
Roshan Pius58e5dd32015-10-16 15:16:42 -0700365 if verbose:
366 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700367
Kevin Cheng85e864a2015-11-30 11:49:34 -0800368 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400369 ignore_status=ignore_status,
370 ignore_timeout=ignore_timeout, stdout_tee=stdout,
371 stderr_tee=stderr, options=options, stdin=stdin,
372 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700373
374
Dan Shie234dea2016-01-20 17:15:17 -0800375 def get_board_name(self):
376 """Get the name of the board, e.g., shamu, dragonboard etc.
377 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700378 product = self.run_output('getprop %s' % BOARD_FILE)
379 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800380
381
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700382 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700383 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700384 """Determine the correct board label for the device.
385
386 @returns a string representing this device's board.
387 """
Dan Shie234dea2016-01-20 17:15:17 -0800388 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700389 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800390 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700391
392
Christopher Wiley08849d52013-11-22 08:57:58 -0800393 def job_start(self):
394 """
395 Disable log collection on adb_hosts.
396
397 TODO(sbasi): crbug.com/305427
Christopher Wiley08849d52013-11-22 08:57:58 -0800398 """
399
400
Simran Basi431010f2013-09-04 10:42:41 -0700401 def run(self, command, timeout=3600, ignore_status=False,
402 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
403 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700404 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700405 """Run a command on the adb device.
406
407 The command given will be ran directly on the adb device; for example
408 'ls' will be ran as: 'abd shell ls'
409
410 @param command: The command line string.
411 @param timeout: Time limit in seconds before attempting to
412 kill the running process. The run() function
413 will take a few seconds longer than 'timeout'
414 to complete if it has to kill the process.
415 @param ignore_status: Do not raise an exception, no matter
416 what the exit code of the command is.
417 @param ignore_timeout: Bool True if command timeouts should be
418 ignored. Will return None on command timeout.
419 @param stdout_tee: Redirect stdout.
420 @param stderr_tee: Redirect stderr.
421 @param connect_timeout: Connection timeout (in seconds).
422 @param options: String with additional ssh command options.
423 @param stdin: Stdin to pass (a string) to the executed command
424 @param args: Sequence of strings to pass as arguments to command by
425 quoting them in " and escaping their contents if
426 necessary.
427
428 @returns A CMDResult object or None if the call timed out and
429 ignore_timeout is True.
430
431 @raises AutoservRunError: If the command failed.
432 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700433 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700434 command = ('"%s; echo %s:\$?"' %
435 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700436 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700437 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700438 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
439 stdout=stdout_tee, stderr=stderr_tee,
440 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700441 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700442 if not result:
443 # In case of timeouts.
444 return None
445
446 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700447 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700448 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700449 'Failed to parse the exit code for command: %s' %
450 command, result)
451 elif parse_output:
452 result.stdout = parse_output.group('OUTPUT')
453 result.exit_status = int(parse_output.group('EXIT_CODE'))
454 if result.exit_status != 0 and not ignore_status:
455 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700456 return result
457
458
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700459 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
460 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700461
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700462 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700463
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700464 @param timeout: Time limit in seconds before returning even if the host
465 is not up.
466 @param command: The command used to test if a device is up, i.e.,
467 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700468
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700469 @returns True if the host was found to be up before the timeout expires,
470 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700471 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700472 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
473 delay_sec=1)
474 def _wait_up():
475 if not self.is_up(command=command):
476 raise error.TimeoutException('Device is still down.')
477 return True
478
479 try:
480 _wait_up()
481 logging.debug('Host %s is now up, and can be accessed by %s.',
482 self.hostname, command)
483 return True
484 except error.TimeoutException:
485 logging.debug('Host %s is still down after waiting %d seconds',
486 self.hostname, timeout)
487 return False
Simran Basi431010f2013-09-04 10:42:41 -0700488
489
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700490 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
491 warning_timer=None, old_boot_id=None, command=ADB_CMD):
492 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700493
494 Overrides wait_down from AbstractSSHHost.
495
496 @param timeout: Time in seconds to wait for the host to go down.
497 @param warning_timer: Time limit in seconds that will generate
498 a warning if the host is not down yet.
499 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700500 @param old_boot_id: Not applicable for adb_host.
501 @param command: `adb`, test if the device can be accessed by adb
502 command, or `fastboot`, test if the device can be accessed by
503 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700504
505 @returns True if the device goes down before the timeout, False
506 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700507 """
508 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
509 delay_sec=1)
510 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700511 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700512 raise error.TimeoutException('Device is still up.')
513 return True
514
515 try:
516 _wait_down()
517 logging.debug('Host %s is now down', self.hostname)
518 return True
519 except error.TimeoutException:
520 logging.debug('Host %s is still up after waiting %d seconds',
521 self.hostname, timeout)
522 return False
523
524
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700525 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700526 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700527
528 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700529 """
530 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700531 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700532 self.adb_run('reboot', timeout=10, ignore_timeout=True)
533 if not self.wait_down():
534 raise error.AutoservRebootError(
535 'ADB Device is still up after reboot')
536 if not self.wait_up():
537 raise error.AutoservRebootError(
538 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800539 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800540
541
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300542 def fastboot_reboot(self):
543 """Do a fastboot reboot to go back to adb.
544
545 @raises AutoservRebootError if reboot failed.
546 """
547 self.fastboot_run('reboot')
548 if not self.wait_down(command=FASTBOOT_CMD):
549 raise error.AutoservRebootError(
550 'Device is still in fastboot mode after reboot')
551 if not self.wait_up():
552 raise error.AutoservRebootError(
553 'Device failed to boot to adb after fastboot reboot.')
554 self._reset_adbd_connection()
555
556
Ralph Nathanb45eb672015-11-18 20:04:39 -0800557 def remount(self):
558 """Remounts paritions on the device read-write.
559
560 Specifically, the /system, /vendor (if present) and /oem (if present)
561 partitions on the device are remounted read-write.
562 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800563 self.adb_run('remount')
564
565
Kevin Cheng549beb42015-11-18 11:42:25 -0800566 @staticmethod
567 def parse_device_serials(devices_output):
568 """Return a list of parsed serials from the output.
569
570 @param devices_output: Output from either an adb or fastboot command.
571
572 @returns List of device serials
573 """
574 devices = []
575 for line in devices_output.splitlines():
576 match = re.search(DEVICE_FINDER_REGEX, line)
577 if match:
578 serial = match.group('SERIAL')
579 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
580 serial = DEVICE_NO_SERIAL_TAG
581 logging.debug('Found Device: %s', serial)
582 devices.append(serial)
583 return devices
584
585
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700586 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700587 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700588
589 @params use_adb: True to get adb accessible devices. Set to False to
590 get fastboot accessible devices.
591
Kevin Chengd19e6c62015-10-28 16:39:39 -0700592 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700593 """
594 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300595 result = self.adb_run('devices').stdout
596 if self.adb_serial and self.adb_serial not in result:
597 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700598 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300599 result = self.fastboot_run('devices').stdout
600 if (self.fastboot_serial and
601 self.fastboot_serial not in result):
602 # fastboot devices won't list the devices using TCP
603 try:
604 if 'product' in self.fastboot_run('getvar product',
605 timeout=2).stderr:
606 result += '\n%s\tfastboot' % self.fastboot_serial
Kevin Chengcfcb2cf2016-04-13 10:04:36 -0700607 # The main reason we do a general Exception catch here instead
608 # of setting ignore_timeout/status to True is because even when
609 # the fastboot process has been nuked, it still stays around and
610 # so bgjob wants to warn us of this and tries to read the
611 # /proc/<pid>/stack file which then promptly returns an
612 # 'Operation not permitted' error since we're running as moblab
613 # and we don't have permission to read those files.
614 except Exception:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300615 pass
616 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700617
618
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700619 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700620 """Get a list of devices currently attached to the test station and
621 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700622 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800623 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700624 raise error.AutoservError(
625 'Not given ADB serial but multiple devices detected')
626 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700627
628
629 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700630 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700631 accessible by fastboot command.
632 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700633 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800634 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700635 raise error.AutoservError(
636 'Not given fastboot serial but multiple devices detected')
637 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700638
639
640 def is_up(self, timeout=0, command=ADB_CMD):
641 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700642
643 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700644 @param command: `adb`, the device can be accessed by adb command,
645 or `fastboot`, the device can be accessed by fastboot command.
646 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700647
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700648 @returns True if the device is detectable by given command, False
649 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700650
651 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700652 if command == ADB_CMD:
653 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800654 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800655 # ADB has a device state, if the device is not online, no
656 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800657 # DUT with single device connected may not have adb_serial set.
658 # Therefore, skip checking if serial is in the list of adb devices
659 # if self.adb_serial is not set.
660 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800661 logging.debug('Waiting for device to enter the ready state.')
662 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700663 elif command == FASTBOOT_CMD:
664 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800665 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700666 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700667 raise NotImplementedError('Mode %s is not supported' % command)
668
669 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700670
671
672 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700673 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700674
675 Called as the test ends. Will return the device to USB mode and kill
676 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700677 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800678 # TODO(sbasi) Originally, we would kill the server after each test to
679 # reduce the opportunity for bad server state to hang around.
680 # Unfortunately, there is a period of time after each kill during which
681 # the Android device becomes unusable, and if we start the next test
682 # too quickly, we'll get an error complaining about no ADB device
683 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700684 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800685 # |close| the associated teststation as well.
686 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700687 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700688
689
690 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700691 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700692
693 @param message String message to log into syslog
694 @param tag String tag prefix for syslog
695
696 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700697 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700698
699
700 def get_autodir(self):
701 """Return the directory to install autotest for client side tests."""
702 return '/data/autotest'
703
Kevin Cheng018db352015-09-20 02:22:08 -0700704
Kris Rambishde8f9d12015-12-16 12:42:41 -0800705 def is_device_ready(self):
706 """Return the if the device is ready for ADB commands."""
Dan Shi7075f552016-04-21 15:42:41 -0700707 try:
708 # Retry to avoid possible flakes.
709 is_ready = client_utils.poll_for_condition(
710 lambda: self.adb_run('get-state').stdout.strip() == 'device',
711 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS, sleep_interval=1,
712 desc='Waiting for device state to be `device`')
713 except client_utils.TimeoutError:
714 is_ready = False
715
716 logging.debug('Device state is %sready', '' if is_ready else 'NOT ')
717 return is_ready
Kris Rambishde8f9d12015-12-16 12:42:41 -0800718
719
Kevin Chengd19e6c62015-10-28 16:39:39 -0700720 def verify_connectivity(self):
721 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800722 if not self.is_device_ready():
723 raise error.AutoservHostError('device state is not in the '
724 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700725
726
Simran Basid3ba3fb2015-09-11 14:35:07 -0700727 def verify_software(self):
728 """Verify working software on an adb_host.
729
Simran Basi38f7ddf2015-09-18 12:25:03 -0700730 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700731 """
Dan Shiab999722015-12-04 14:27:08 -0800732 # Check if adb and fastboot are present.
733 self.teststation.run('which adb')
734 self.teststation.run('which fastboot')
735 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700736
Kevin Cheng018db352015-09-20 02:22:08 -0700737
Simran Basid3ba3fb2015-09-11 14:35:07 -0700738 def verify_job_repo_url(self, tag=''):
739 """Make sure job_repo_url of this host is valid.
740
Simran Basi38f7ddf2015-09-18 12:25:03 -0700741 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700742
743 @param tag: The tag from the server job, in the format
744 <job_id>-<user>/<hostname>, or <hostless> for a server job.
745 """
746 return
Kevin Cheng018db352015-09-20 02:22:08 -0700747
748
Simran Basibeb2bb22016-02-03 15:25:48 -0800749 def repair(self):
750 """Attempt to get the DUT to pass `self.verify()`."""
751 try:
752 self.ensure_adb_mode(timeout=30)
753 return
754 except error.AutoservError as e:
755 logging.error(e)
756 logging.debug('Verifying the device is accessible via fastboot.')
757 self.ensure_bootloader_mode()
758 if not self.job.run_test(
759 'provision_AndroidUpdate', host=self, value=None,
760 force=True, repair=True):
761 raise error.AutoservRepairTotalFailure(
762 'Unable to repair the device.')
763
764
Simran Basi1b023762015-09-25 12:12:20 -0700765 def send_file(self, source, dest, delete_dest=False,
766 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700767 """Copy files from the drone to the device.
768
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400769 Just a note, there is the possibility the test station is localhost
770 which makes some of these steps redundant (e.g. creating tmp dir) but
771 that scenario will undoubtedly be a development scenario (test station
772 is also the moblab) and not the typical live test running scenario so
773 the redundancy I think is harmless.
774
Kevin Cheng018db352015-09-20 02:22:08 -0700775 @param source: The file/directory on the drone to send to the device.
776 @param dest: The destination path on the device to copy to.
777 @param delete_dest: A flag set to choose whether or not to delete
778 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700779 @param preserve_symlinks: Controls if symlinks on the source will be
780 copied as such on the destination or
781 transformed into the referenced
782 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700783 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700784 # If we need to preserve symlinks, let's check if the source is a
785 # symlink itself and if so, just create it on the device.
786 if preserve_symlinks:
787 symlink_target = None
788 try:
789 symlink_target = os.readlink(source)
790 except OSError:
791 # Guess it's not a symlink.
792 pass
793
794 if symlink_target is not None:
795 # Once we create the symlink, let's get out of here.
796 self.run('ln -s %s %s' % (symlink_target, dest))
797 return
798
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400799 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700800 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400801 src_path = os.path.join(tmp_dir, os.path.basename(dest))
802 # Now copy the file over to the test station so you can reference the
803 # file in the push command.
804 self.teststation.send_file(source, src_path,
805 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700806
807 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400808 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700809
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700810 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700811
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400812 # Cleanup the test station.
813 try:
814 self.teststation.run('rm -rf %s' % tmp_dir)
815 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
816 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700817
818
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700819 def _get_file_info(self, dest):
820 """Get permission and possible symlink info about file on the device.
821
822 These files are on the device so we only have shell commands (via adb)
823 to get the info we want. We'll use 'ls' to get it all.
824
825 @param dest: File to get info about.
826
827 @returns a dict of the file permissions and symlink.
828 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800829 # Grab file info.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700830 file_info = self.run_output('ls -ld %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700831 symlink = None
832 perms = 0
833 match = re.match(FILE_INFO_REGEX, file_info)
834 if match:
835 # Check if it's a symlink and grab the linked dest if it is.
836 if match.group('TYPE') == 'l':
837 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
838 if symlink_match:
839 symlink = symlink_match.group('SYMLINK')
840
841 # Set the perms.
842 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
843 if perm != '-':
844 perms |= perm_flag
845
846 return {'perms': perms,
847 'symlink': symlink}
848
849
Simran Basi1b023762015-09-25 12:12:20 -0700850 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
851 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700852 """Copy files from the device to the drone.
853
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400854 Just a note, there is the possibility the test station is localhost
855 which makes some of these steps redundant (e.g. creating tmp dir) but
856 that scenario will undoubtedly be a development scenario (test station
857 is also the moblab) and not the typical live test running scenario so
858 the redundancy I think is harmless.
859
Kevin Cheng018db352015-09-20 02:22:08 -0700860 @param source: The file/directory on the device to copy back to the
861 drone.
862 @param dest: The destination path on the drone to copy to.
863 @param delete_dest: A flag set to choose whether or not to delete
864 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700865 @param preserve_perm: Tells get_file() to try to preserve the sources
866 permissions on files and dirs.
867 @param preserve_symlinks: Try to preserve symlinks instead of
868 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700869 """
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400870 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700871 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400872 dest_path = os.path.join(tmp_dir, os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700873
874 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400875 self.teststation.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700876
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700877 source_info = {}
878 if preserve_symlinks or preserve_perm:
879 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700880
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700881 # If we want to preserve symlinks, just create it here, otherwise pull
882 # the file off the device.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700883 #
884 # TODO(sadmac): Directories containing symlinks won't behave as
885 # expected.
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700886 if preserve_symlinks and source_info['symlink']:
887 os.symlink(source_info['symlink'], dest)
888 else:
Roshan Pius95567142015-11-03 09:56:08 -0800889 self.adb_run('pull %s %s' % (source, dest_path))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700890
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400891 # Copy over the file from the test station and clean up.
892 self.teststation.get_file(dest_path, dest)
893 try:
894 self.teststation.run('rm -rf %s' % tmp_dir)
895 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
896 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700897
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700898 for root, dirs, files in os.walk(dest):
899 rel_root = os.path.relpath(root, dest)
900
901 def process(item, default_perm):
902 info = self._get_file_info(os.path.join(source, rel_root, item))
903
904 if info['perms'] != 0:
905 target = os.path.join(root, item)
906 if preserve_perm:
907 os.chmod(target, info['perms'])
908 else:
909 os.chmod(target, default_perm)
910
911 for f in files:
912 process(f, 0o600)
913
914 for d in dirs:
915 process(f, 0o700)
916
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700917 if preserve_perm:
918 os.chmod(dest, source_info['perms'])
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700919 elif os.path.isdir(dest):
920 os.chmod(dest, 0o700)
921 else:
922 os.chmod(dest, 0o600)
Kevin Cheng018db352015-09-20 02:22:08 -0700923
924
925 def get_release_version(self):
926 """Get the release version from the RELEASE_FILE on the device.
927
928 @returns The release string in the RELEASE_FILE.
929
930 """
931 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700932
933
934 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700935 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700936
Kevin Chengd19e6c62015-10-28 16:39:39 -0700937 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700938
939 @param parent: Parent directory of the returned tmp dir.
940
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700941 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700942 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700943 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
944 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700945 if not parent.startswith(TMP_DIR):
946 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700947 self.run('mkdir -p %s' % parent)
948 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
949 self.tmp_dirs.append(tmp_dir)
950 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700951
952
953 def get_platform(self):
954 """Determine the correct platform label for this host.
955
956 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700957 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700958
959 @returns a string representing this host's platform.
960 """
961 return 'adb'
962
963
Gilad Arnolda76bef02015-09-29 13:55:15 -0700964 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800965 """Get the OS type of the DUT, e.g., android or brillo.
966 """
967 if not self._os_type:
968 if self.run_output('getprop ro.product.brand') == 'Brillo':
969 self._os_type = OS_TYPE_BRILLO
970 else:
971 self._os_type = OS_TYPE_ANDROID
972
973 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700974
975
976 def _forward(self, reverse, args):
977 """Execute a forwarding command.
978
979 @param reverse: Whether this is reverse forwarding (Boolean).
980 @param args: List of command arguments.
981 """
982 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700983 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700984
985
986 def add_forwarding(self, src, dst, reverse=False, rebind=True):
987 """Forward a port between the ADB host and device.
988
989 Port specifications are any strings accepted as such by ADB, for
990 example 'tcp:8080'.
991
992 @param src: Port specification to forward from.
993 @param dst: Port specification to forward to.
994 @param reverse: Do reverse forwarding from device to host (Boolean).
995 @param rebind: Allow rebinding an already bound port (Boolean).
996 """
997 args = []
998 if not rebind:
999 args.append('--no-rebind')
1000 args += [src, dst]
1001 self._forward(reverse, args)
1002
1003
1004 def remove_forwarding(self, src=None, reverse=False):
1005 """Removes forwarding on port.
1006
1007 @param src: Port specification, or None to remove all forwarding.
1008 @param reverse: Whether this is reverse forwarding (Boolean).
1009 """
1010 args = []
1011 if src is None:
1012 args.append('--remove-all')
1013 else:
1014 args += ['--remove', src]
1015 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001016
1017
xixuan6cf6d2f2016-01-29 15:29:00 -08001018 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001019 """
1020 Forwards a port securely through a tunnel process from the server
1021 to the DUT for RPC server connection.
1022 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
1023 to the DUT.
1024
1025 @param port: remote port on the DUT.
1026 @param local_port: local forwarding port.
1027
1028 @return: the tunnel process.
1029 """
1030 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001031 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001032
1033
xixuan6cf6d2f2016-01-29 15:29:00 -08001034 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001035 """
1036 Disconnects a previously forwarded port from the server to the DUT for
1037 RPC server connection.
1038 Remove the previously added 'ADB forward' rule to forward the RPC
1039 packets from the AdbHost to the DUT.
1040
1041 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -08001042 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -07001043 @param port: remote port on the DUT.
1044
1045 """
1046 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001047 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001048
1049
1050 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001051 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001052
1053 @raise: error.AutoservError if the device failed to reboot into
1054 bootloader mode.
1055 """
1056 if self.is_up(command=FASTBOOT_CMD):
1057 return
1058 self.adb_run('reboot bootloader')
1059 if not self.wait_up(command=FASTBOOT_CMD):
1060 raise error.AutoservError(
1061 'The device failed to reboot into bootloader mode.')
1062
1063
Dan Shie4e807b2015-12-10 09:04:03 -08001064 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001065 """Ensure the device is up and can be accessed by adb command.
1066
Dan Shie4e807b2015-12-10 09:04:03 -08001067 @param timeout: Time limit in seconds before returning even if the host
1068 is not up.
1069
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001070 @raise: error.AutoservError if the device failed to reboot into
1071 adb mode.
1072 """
1073 if self.is_up():
1074 return
Dan Shi04980372016-03-22 10:57:47 -07001075 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1076 # check if the device is in adb mode.
1077 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001078 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001079 raise error.AutoservError(
1080 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001081 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001082
1083
1084 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001085 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001086 """Get the Android build information from the build url.
1087
1088 @param build_url: The url to use for downloading Android artifacts.
1089 pattern: http://$devserver:###/static/branch/target/build_id
1090
Dan Shi6450e142016-03-11 11:52:20 -08001091 @return: A dictionary of build information, including keys:
1092 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001093 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001094 """
Dan Shiab999722015-12-04 14:27:08 -08001095 if not build_url:
1096 raise AndroidInstallError('Need build_url to download image files.')
1097
1098 try:
1099 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001100 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001101 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001102 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001103 match.group('BUILD_TYPE'))),
1104 'build_id': match.group('BUILD_ID')}
1105 except (AttributeError, IndexError, ValueError) as e:
1106 raise AndroidInstallError(
1107 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001108
1109
Dan Shia2872172015-10-31 01:16:51 -07001110 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001111 def download_file(self, build_url, file, dest_dir, unzip=False,
1112 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001113 """Download the given file from the build url.
1114
1115 @param build_url: The url to use for downloading Android artifacts.
1116 pattern: http://$devserver:###/static/branch/target/build_id
1117 @param file: Name of the file to be downloaded, e.g., boot.img.
1118 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001119 @param unzip: If True, unzip the downloaded file.
1120 @param unzip_dest: Location to unzip the downloaded file to. If not
1121 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001122 """
Dan Shidb0366c2016-02-19 10:36:18 -08001123 # Append the file name to the url if build_url is linked to the folder
1124 # containing the file.
1125 if not build_url.endswith('/%s' % file):
1126 src_url = os.path.join(build_url, file)
1127 else:
1128 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001129 dest_file = os.path.join(dest_dir, file)
1130 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001131 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001132 if unzip:
1133 unzip_dest = unzip_dest or dest_dir
1134 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1135 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001136 except:
1137 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001138 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001139 raise
1140
1141
Dan Shiab999722015-12-04 14:27:08 -08001142 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001143 """Download required image files from the given build_url to a local
1144 directory in the machine runs fastboot command.
1145
1146 @param build_url: The url to use for downloading Android artifacts.
1147 pattern: http://$devserver:###/static/branch/target/build_id
1148
1149 @return: Path to the directory contains image files.
1150 """
Dan Shi08ff1282016-02-18 19:51:16 -08001151 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001152
1153 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001154 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001155
1156 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001157 self.download_file(build_url, zipped_image_file, image_dir,
1158 unzip=True)
Dan Shi49d451f2016-04-19 09:25:01 -07001159 images = android_utils.AndroidImageFiles.get_standalone_images(
1160 build_info['build_target'])
1161 for image_file in images:
Dan Shidb0366c2016-02-19 10:36:18 -08001162 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001163
Dan Shia2872172015-10-31 01:16:51 -07001164 return image_dir
1165 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001166 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001167 raise
1168
1169
Dan Shiab999722015-12-04 14:27:08 -08001170 def stage_brillo_image_files(self, build_url):
1171 """Download required brillo image files from the given build_url to a
1172 local directory in the machine runs fastboot command.
1173
1174 @param build_url: The url to use for downloading Android artifacts.
1175 pattern: http://$devserver:###/static/branch/target/build_id
1176
1177 @return: Path to the directory contains image files.
1178 """
Dan Shi08ff1282016-02-18 19:51:16 -08001179 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001180
1181 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1182 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1183 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001184
1185 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001186 self.download_file(build_url, zipped_image_file, image_dir,
1187 unzip=True)
1188 self.download_file(build_url, vendor_partitions_file, image_dir,
1189 unzip=True,
1190 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001191 return image_dir
1192 except:
1193 self.teststation.run('rm -rf %s' % image_dir)
1194 raise
1195
1196
Simran Basibeb2bb22016-02-03 15:25:48 -08001197 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001198 """Stage a build on a devserver and return the build_url and devserver.
1199
1200 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001201
Dan Shi225b9042015-11-18 10:25:21 -08001202 @returns a tuple with an update URL like:
1203 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1204 and the devserver instance.
1205 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001206 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001207 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001208 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1209 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001210 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001211 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001212 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001213 devserver.trigger_download(target, build_id, branch,
1214 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001215 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001216
1217
Dan Shie4e807b2015-12-10 09:04:03 -08001218 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001219 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001220 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001221
1222 Following are the steps used here to provision an android device:
1223 1. If build_local_path is not set, download the image zip file, e.g.,
1224 shamu-img-2284311.zip, unzip it.
1225 2. Run fastboot to install following artifacts:
1226 bootloader, radio, boot, system, vendor(only if exists)
1227
1228 Repair is not supported for Android devices yet.
1229
1230 @param build_url: The url to use for downloading Android artifacts.
1231 pattern: http://$devserver:###/static/$build
1232 @param build_local_path: The path to a local folder that contains the
1233 image files needed to provision the device. Note that the folder
1234 is in the machine running adb command, rather than the drone.
1235 @param wipe: If true, userdata will be wiped before flashing.
1236 @param flash_all: If True, all img files found in img_path will be
1237 flashed. Otherwise, only boot and system are flashed.
1238
1239 @raises AndroidInstallError if any error occurs.
1240 """
Dan Shia2872172015-10-31 01:16:51 -07001241 # If the build is not staged in local server yet, clean up the temp
1242 # folder used to store image files after the provision is completed.
1243 delete_build_folder = bool(not build_local_path)
1244
1245 try:
1246 # Download image files needed for provision to a local directory.
1247 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001248 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001249
1250 # Device needs to be in bootloader mode for flashing.
1251 self.ensure_bootloader_mode()
1252
1253 if wipe:
Dan Shi12a4f662016-05-10 14:49:42 -07001254 self._fastboot_run_with_retry('-w')
Dan Shia2872172015-10-31 01:16:51 -07001255
1256 # Get all *.img file in the build_local_path.
1257 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001258 image_files = self.teststation.run(
1259 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001260 images = dict([(os.path.basename(f), f) for f in image_files])
Dan Shi49d451f2016-04-19 09:25:01 -07001261 build_info = self.get_build_info_from_build_url(build_url)
1262 board = build_info['build_target']
1263 all_images = (
1264 android_utils.AndroidImageFiles.get_standalone_images(board)
1265 + android_utils.AndroidImageFiles.get_zipped_images(board))
1266
1267 # Sort images to be flashed, bootloader needs to be the first one.
1268 bootloader = android_utils.AndroidImageFiles.BOOTLOADER
1269 sorted_images = sorted(
1270 images.items(),
1271 key=lambda pair: 0 if pair[0] == bootloader else 1)
1272 for image, image_file in sorted_images:
1273 if image not in all_images:
Dan Shia2872172015-10-31 01:16:51 -07001274 continue
1275 logging.info('Flashing %s...', image_file)
Dan Shi12a4f662016-05-10 14:49:42 -07001276 self._fastboot_run_with_retry('-S 256M flash %s %s' %
1277 (image[:-4], image_file))
Dan Shi49d451f2016-04-19 09:25:01 -07001278 if image == android_utils.AndroidImageFiles.BOOTLOADER:
Dan Shia2872172015-10-31 01:16:51 -07001279 self.fastboot_run('reboot-bootloader')
1280 self.wait_up(command=FASTBOOT_CMD)
1281 except Exception as e:
1282 logging.error('Install Android build failed with error: %s', e)
1283 # Re-raise the exception with type of AndroidInstallError.
1284 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1285 finally:
1286 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001287 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001288 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1289 DEFAULT_WAIT_UP_TIME_SECONDS)
1290 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001291 logging.info('Successfully installed Android build staged at %s.',
1292 build_url)
1293
1294
Dan Shiab999722015-12-04 14:27:08 -08001295 def install_brillo(self, build_url, build_local_path=None):
1296 """Install the Brillo DUT.
1297
1298 Following are the steps used here to provision an android device:
1299 1. If build_local_path is not set, download the image zip file, e.g.,
1300 dragonboard-img-123456.zip, unzip it. And download the vendor
1301 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1302 unzip it to vendor folder.
1303 2. Run provision_device script to install OS images and vendor
1304 partitions.
1305
1306 @param build_url: The url to use for downloading Android artifacts.
1307 pattern: http://$devserver:###/static/$build
1308 @param build_local_path: The path to a local folder that contains the
1309 image files needed to provision the device. Note that the folder
1310 is in the machine running adb command, rather than the drone.
1311
1312 @raises AndroidInstallError if any error occurs.
1313 """
1314 # If the build is not staged in local server yet, clean up the temp
1315 # folder used to store image files after the provision is completed.
1316 delete_build_folder = bool(not build_local_path)
1317
Dan Shiab999722015-12-04 14:27:08 -08001318 try:
1319 # Download image files needed for provision to a local directory.
1320 if not build_local_path:
1321 build_local_path = self.stage_brillo_image_files(build_url)
1322
1323 # Device needs to be in bootloader mode for flashing.
1324 self.ensure_bootloader_mode()
1325
1326 # Run provision_device command to install image files and vendor
1327 # partitions.
1328 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1329 cmd = (BRILLO_PROVISION_CMD %
1330 {'os_image_dir': build_local_path,
1331 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001332 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001333 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001334 self.teststation.run(cmd)
1335 except Exception as e:
1336 logging.error('Install Brillo build failed with error: %s', e)
1337 # Re-raise the exception with type of AndroidInstallError.
1338 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1339 finally:
1340 if delete_build_folder:
1341 self.teststation.run('rm -rf %s' % build_local_path)
1342 self.ensure_adb_mode()
1343 logging.info('Successfully installed Android build staged at %s.',
1344 build_url)
1345
1346
Dan Shibe3636a2016-02-14 22:48:01 -08001347 @property
1348 def job_repo_url_attribute(self):
1349 """Get the host attribute name for job_repo_url, which should append the
1350 adb serial.
1351 """
1352 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1353
1354
Dan Shie4e807b2015-12-10 09:04:03 -08001355 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001356 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001357 """Install the DUT.
1358
1359 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001360 pattern: http://$devserver:###/static/$build. If build_url is
1361 set to None, the code may try _parser.options.image to do the
1362 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001363 @param build_local_path: The path to a local directory that contains the
1364 image files needed to provision the device.
1365 @param wipe: If true, userdata will be wiped before flashing.
1366 @param flash_all: If True, all img files found in img_path will be
1367 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001368
Dan Shibe3636a2016-02-14 22:48:01 -08001369 @returns A tuple of (image_name, host_attributes).
1370 image_name is the name of image installed, e.g.,
1371 git_mnc-release/shamu-userdebug/1234
1372 host_attributes is a dictionary of (attribute, value), which
1373 can be saved to afe_host_attributes table in database. This
1374 method returns a dictionary with a single entry of
1375 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1376 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001377 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001378 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001379 if not build_url and self._parser.options.image:
1380 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001381 self._parser.options.image, os_type=os_type)
1382 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001383 self.install_android(
1384 build_url=build_url, build_local_path=build_local_path,
1385 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001386 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001387 self.install_brillo(
1388 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001389 else:
1390 raise error.InstallError(
1391 'Installation of os type %s is not supported.' %
1392 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001393 return (build_url.split('static/')[-1],
1394 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001395
1396
1397 def list_files_glob(self, path_glob):
1398 """Get a list of files on the device given glob pattern path.
1399
1400 @param path_glob: The path glob that we want to return the list of
1401 files that match the glob. Relative paths will not work as
1402 expected. Supply an absolute path to get the list of files
1403 you're hoping for.
1404
1405 @returns List of files that match the path_glob.
1406 """
1407 # This is just in case path_glob has no path separator.
1408 base_path = os.path.dirname(path_glob) or '.'
1409 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001410 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001411 if result.exit_status != 0:
1412 return []
1413 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001414
1415
Dan Shida995002016-04-25 23:12:58 -07001416 def install_apk(self, apk, force_reinstall=True):
Kevin Cheng31355942016-01-05 14:23:35 -08001417 """Install the specified apk.
1418
1419 This will install the apk and override it if it's already installed and
1420 will also allow for downgraded apks.
1421
1422 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001423 @param force_reinstall: True to reinstall the apk even if it's already
Dan Shida995002016-04-25 23:12:58 -07001424 installed. Default is set to True.
Dan Shidb0366c2016-02-19 10:36:18 -08001425
1426 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001427 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001428 client_utils.poll_for_condition(
1429 lambda: self.run('pm list packages',
1430 ignore_status=True).exit_status == 0,
1431 timeout=120)
Dan Shi043c45b2016-04-11 17:18:49 -07001432 client_utils.poll_for_condition(
1433 lambda: self.run('service list | grep mount',
1434 ignore_status=True).exit_status == 0,
1435 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001436 return self.adb_run('install %s -d %s' %
1437 ('-r' if force_reinstall else '', apk))
1438
1439
1440 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1441 def _confirm_apk_installed(self, package_name):
1442 """Confirm if apk is already installed with the given name.
1443
1444 `pm list packages` command is not reliable some time. The retry helps to
1445 reduce the chance of false negative.
1446
1447 @param package_name: Name of the package, e.g., com.android.phone.
1448
1449 @raise AutoservRunError: If the package is not found or pm list command
1450 failed for any reason.
1451 """
1452 name = 'package:%s' % package_name
1453 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1454
1455
1456 def is_apk_installed(self, package_name):
1457 """Check if apk is already installed with the given name.
1458
1459 @param package_name: Name of the package, e.g., com.android.phone.
1460
1461 @return: True if package is installed. False otherwise.
1462 """
1463 try:
1464 self._confirm_apk_installed(package_name)
1465 return True
1466 except:
1467 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001468
1469
1470 def get_attributes_to_clear_before_provision(self):
1471 """Get a list of attributes to be cleared before machine_install starts.
1472 """
1473 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001474
1475
1476 def get_labels(self):
1477 """Return a list of the labels gathered from the devices connected.
1478
1479 @return: A list of strings that denote the labels from all the devices
1480 connected.
1481 """
1482 return self.labels.get_labels(self)
1483
1484
1485 def update_labels(self):
1486 """Update the labels for this testbed."""
1487 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001488
1489
1490 def stage_server_side_package(self, image=None):
1491 """Stage autotest server-side package on devserver.
1492
1493 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1494
1495 @return: A url to the autotest server-side package. Return None if
1496 server-side package is not supported.
1497 @raise: error.AutoservError if fail to locate the build to test with.
1498 """
1499 if image:
1500 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1501 else:
1502 job_repo_url = afe_utils.get_host_attribute(
1503 self, self.job_repo_url_attribute)
1504 if job_repo_url:
1505 devserver_url, image = (
1506 tools.get_devserver_build_from_package_url(
1507 job_repo_url, True))
1508 ds = dev_server.AndroidBuildServer(devserver_url)
1509 else:
1510 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1511 if not labels:
1512 raise error.AutoservError(
1513 'Failed to stage server-side package. The host has '
1514 'no job_report_url attribute or version label.')
1515 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1516 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1517
1518 branch, target, build_id = utils.parse_launch_control_build(image)
1519 build_target, _ = utils.parse_launch_control_target(target)
1520
1521 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1522 # packaging is not supported.
1523 try:
1524 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1525 logging.warn('Build %s is older than %s. Server side packaging '
1526 'is disabled.', image,
1527 self.MIN_VERSION_SUPPORT_SSP)
1528 return None
1529 except ValueError:
1530 logging.warn('Failed to compare build id in %s with the minimum '
1531 'version that supports server side packaging. Server '
1532 'side packaging is disabled.', image)
1533 return None
1534
1535 ds.stage_artifacts(target, build_id, branch,
1536 artifacts=['autotest_server_package'])
1537 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1538 {'build_target': build_target,
1539 'build_id': build_id})
1540 return '%s/static/%s/%s' % (ds.url(), image,
1541 autotest_server_package_name)