blob: 828bf085260841559bc2e42e8d077ea7738c2cde [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
14from autotest_lib.client.common_lib import error
Dan Shi225b9042015-11-18 10:25:21 -080015from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070016from autotest_lib.client.common_lib.cros import retry
Dan Shi225b9042015-11-18 10:25:21 -080017from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070018from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080019from autotest_lib.server import utils
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070020from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070021from autotest_lib.server.hosts import abstract_ssh
Kevin Cheng85e864a2015-11-30 11:49:34 -080022from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070023
24
Dan Shi6ea3e1c2015-10-28 15:19:04 -070025ADB_CMD = 'adb'
26FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070027SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070028# Some devices have no serial, then `adb serial` has output such as:
29# (no serial number) device
30# ?????????? device
31DEVICE_NO_SERIAL_MSG = '(no serial number)'
32DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070033# Regex to find an adb device. Examples:
34# 0146B5580B01801B device
35# 018e0ecb20c97a62 device
36# 172.22.75.141:5555 device
Filipe Brandenburger34363392015-08-13 14:57:45 -070037DEVICE_FINDER_REGEX = ('^(?P<SERIAL>([\w]+)|(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})|' +
38 re.escape(DEVICE_NO_SERIAL_MSG) +
Dan Shi6ea3e1c2015-10-28 15:19:04 -070039 ')([:]5555)?[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070040CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
41CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
42 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070043RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070044BOARD_FILE = 'ro.product.device'
Simran Basi38f7ddf2015-09-18 12:25:03 -070045TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070046# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080047# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070048FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
49FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
50# List of the perm stats indexed by the order they are listed in the example
51# supplied above.
52FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
53 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
54 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070055
Dan Shi6ea3e1c2015-10-28 15:19:04 -070056# Default maximum number of seconds to wait for a device to be down.
57DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
58# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080059DEFAULT_WAIT_UP_TIME_SECONDS = 300
60# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080061WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070062
Dan Shia2872172015-10-31 01:16:51 -070063OS_TYPE_ANDROID = 'android'
64OS_TYPE_BRILLO = 'brillo'
65
66# Regex to parse devserver url to get the detailed build information. Sample
67# url: http://$devserver:8080/static/branch/target/build_id
68DEVSERVER_URL_REGEX = ('.*/(?P<BRANCH>([^/]+))/(?P<BOARD>([^/]+))-'
69 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))/*')
70
71ANDROID_IMAGE_FILE_FMT = '%(board)s-img-%(build_id)s.zip'
72ANDROID_BOOTLOADER = 'bootloader.img'
73ANDROID_RADIO = 'radio.img'
74ANDROID_BOOT = 'boot.img'
75ANDROID_SYSTEM = 'system.img'
76ANDROID_VENDOR = 'vendor.img'
Dan Shiab999722015-12-04 14:27:08 -080077BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
78 '%(board)s-vendor_partitions-%(build_id)s.zip')
Dan Shia2872172015-10-31 01:16:51 -070079
80# Image files not inside the image zip file. These files should be downloaded
81# directly from devserver.
82ANDROID_STANDALONE_IMAGES = [ANDROID_BOOTLOADER, ANDROID_RADIO]
83# Image files that are packaged in a zip file, e.g., shamu-img-123456.zip
84ANDROID_ZIPPED_IMAGES = [ANDROID_BOOT, ANDROID_SYSTEM, ANDROID_VENDOR]
85# All image files to be flashed to an Android device.
86ANDROID_IMAGES = ANDROID_STANDALONE_IMAGES + ANDROID_ZIPPED_IMAGES
87
Dan Shiab999722015-12-04 14:27:08 -080088# Command to provision a Brillo device.
89# os_image_dir: The full path of the directory that contains all the Android image
90# files (from the image zip file).
91# vendor_partition_dir: The full path of the directory that contains all the
92# Brillo vendor partitions, and provision-device script.
93BRILLO_PROVISION_CMD = (
94 'ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
95 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
96 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -070097
98class AndroidInstallError(error.InstallError):
99 """Generic error for Android installation related exceptions."""
100
101
Simran Basi724b8a52013-09-30 11:19:31 -0700102class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700103 """This class represents a host running an ADB server."""
104
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700105 _LABEL_FUNCTIONS = []
106 _DETECTABLE_LABELS = []
107 label_decorator = functools.partial(utils.add_label_detector,
108 _LABEL_FUNCTIONS,
109 _DETECTABLE_LABELS)
110
Dan Shi225b9042015-11-18 10:25:21 -0800111 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700112
beeps46dadc92013-11-07 14:07:10 -0800113 @staticmethod
114 def check_host(host, timeout=10):
115 """
116 Check if the given host is an adb host.
117
Simran Basi14622bb2015-11-25 13:23:40 -0800118 If SSH connectivity can't be established, check_host will try to use
119 user 'adb' as well. If SSH connectivity still can't be established
120 then the original SSH user is restored.
121
beeps46dadc92013-11-07 14:07:10 -0800122 @param host: An ssh host representing a device.
123 @param timeout: The timeout for the run command.
124
125
126 @return: True if the host device has adb.
127
128 @raises AutoservRunError: If the command failed.
129 @raises AutoservSSHTimeout: Ssh connection has timed out.
130 """
Dan Shi64e130f2015-12-16 14:45:44 -0800131 # host object may not have user attribute if it's a LocalHost object.
132 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800133 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800134 if not (host.hostname == 'localhost' or
135 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700136 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700137 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700138 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700139 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800140 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800141 if current_user is not None:
142 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800143 return False
144 return result.exit_status == 0
145
146
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700147 # TODO(garnold) Remove the 'serials' argument once all clients are made to
148 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700149 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700150 adb_serial=None, fastboot_serial=None,
Kevin Cheng549beb42015-11-18 11:42:25 -0800151 device_hostname=None, teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700152 """Initialize an ADB Host.
153
154 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700155 test station connected to an Android DUT. This will be the DUT
156 to test with. If there are multiple, serial must be specified or an
157 exception will be raised. If device_hostname is supplied then all
158 ADB commands will run over TCP/IP.
Simran Basi431010f2013-09-04 10:42:41 -0700159
160 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700161 @param serials: DEPRECATED (to be removed)
162 @param adb_serial: An ADB device serial. If None, assume a single
163 device is attached (and fail otherwise).
164 @param fastboot_serial: A fastboot device serial. If None, defaults to
165 the ADB serial (or assumes a single device if
166 the latter is None).
Simran Basi431010f2013-09-04 10:42:41 -0700167 @param device_hostname: Hostname or IP of the android device we want to
168 interact with. If supplied all ADB interactions
169 run over TCP/IP.
Kevin Cheng549beb42015-11-18 11:42:25 -0800170 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700171 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800172 # Sets up the is_client_install_supported field.
173 super(ADBHost, self)._initialize(hostname=hostname,
174 is_client_install_supported=False,
175 *args, **dargs)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700176 if device_hostname and (adb_serial or fastboot_serial):
177 raise error.AutoservError(
178 'TCP/IP and USB modes are mutually exclusive')
179
Kevin Cheng85e864a2015-11-30 11:49:34 -0800180
Kevin Chengd19e6c62015-10-28 16:39:39 -0700181 self.tmp_dirs = []
Simran Basi431010f2013-09-04 10:42:41 -0700182 self._device_hostname = device_hostname
183 self._use_tcpip = False
Simran Basi1bf60eb2015-12-01 16:39:29 -0800184 # TODO (sbasi/kevcheng): Once the teststation host is committed,
185 # refactor the serial retrieval.
186 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800187 self.adb_serial = adb_serial
188 self.fastboot_serial = fastboot_serial or adb_serial
Kevin Cheng85e864a2015-11-30 11:49:34 -0800189 self.teststation = (teststation if teststation
190 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700191
192 msg ='Initializing ADB device on host: %s' % hostname
193 if self._device_hostname:
194 msg += ', device hostname: %s' % self._device_hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800195 if self.adb_serial:
196 msg += ', ADB serial: %s' % self.adb_serial
197 if self.fastboot_serial:
198 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700199 logging.debug(msg)
200
Roshan Pius4d7540c2015-12-16 13:30:32 -0800201 self._reset_adbd_connection()
Dan Shiab999722015-12-04 14:27:08 -0800202 self._os_type = None
203
Simran Basi431010f2013-09-04 10:42:41 -0700204
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700205 def _connect_over_tcpip_as_needed(self):
206 """Connect to the ADB device over TCP/IP if so configured."""
207 if not self._device_hostname:
208 return
209 logging.debug('Connecting to device over TCP/IP')
Dan Shi50a412a2016-01-05 10:52:40 -0800210 if self._device_hostname == self.adb_serial:
Simran Basi431010f2013-09-04 10:42:41 -0700211 # We previously had a connection to this device, restart the ADB
212 # server.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700213 self.adb_run('kill-server')
Simran Basi431010f2013-09-04 10:42:41 -0700214 # Ensure that connection commands don't run over TCP/IP.
215 self._use_tcpip = False
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700216 self.adb_run('tcpip 5555', timeout=10, ignore_timeout=True)
Simran Basi431010f2013-09-04 10:42:41 -0700217 time.sleep(2)
218 try:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700219 self.adb_run('connect %s' % self._device_hostname)
Simran Basi431010f2013-09-04 10:42:41 -0700220 except (error.AutoservRunError, error.CmdError) as e:
221 raise error.AutoservError('Failed to connect via TCP/IP: %s' % e)
222 # Allow ADB a bit of time after connecting before interacting with the
223 # device.
224 time.sleep(5)
225 # Switch back to using TCP/IP.
226 self._use_tcpip = True
227
228
Roshan Pius4d7540c2015-12-16 13:30:32 -0800229 def _restart_adbd_with_root_permissions(self):
230 """Restarts the adb daemon with root permissions."""
231 self.adb_run('root')
232 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
233 time.sleep(1)
234 self.adb_run('wait-for-device')
235
236
237 def _reset_adbd_connection(self):
238 """Resets adbd connection to the device after a reboot/initialization"""
239 self._restart_adbd_with_root_permissions()
240 self._connect_over_tcpip_as_needed()
241
242
Kevin Cheng85e864a2015-11-30 11:49:34 -0800243 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800244 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700245 """Runs an adb command.
246
Kevin Chengd19e6c62015-10-28 16:39:39 -0700247 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700248
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700249 Refer to _device_run method for docstring for parameters.
250 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800251 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700252
253
Kevin Cheng85e864a2015-11-30 11:49:34 -0800254 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800255 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700256 """Runs an fastboot command.
257
Kevin Chengd19e6c62015-10-28 16:39:39 -0700258 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700259
260 Refer to _device_run method for docstring for parameters.
261 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800262 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700263
264
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700265 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700266 timeout=3600, ignore_status=False, ignore_timeout=False,
267 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
268 connect_timeout=30, options='', stdin=None, verbose=True,
269 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700270 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700271
Kevin Chengd19e6c62015-10-28 16:39:39 -0700272 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700273
Simran Basi431010f2013-09-04 10:42:41 -0700274 @param command: Command to run.
275 @param shell: If true the command runs in the adb shell otherwise if
276 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700277 reboot with shell=False will call 'adb reboot'. This
278 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700279 @param timeout: Time limit in seconds before attempting to
280 kill the running process. The run() function
281 will take a few seconds longer than 'timeout'
282 to complete if it has to kill the process.
283 @param ignore_status: Do not raise an exception, no matter
284 what the exit code of the command is.
285 @param ignore_timeout: Bool True if command timeouts should be
286 ignored. Will return None on command timeout.
287 @param stdout: Redirect stdout.
288 @param stderr: Redirect stderr.
289 @param connect_timeout: Connection timeout (in seconds)
290 @param options: String with additional ssh command options
291 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700292 @param require_sudo: True to require sudo to run the command. Default is
293 False.
Simran Basi431010f2013-09-04 10:42:41 -0700294 @param args: Sequence of strings to pass as arguments to command by
295 quoting them in " and escaping their contents if
296 necessary.
297
298 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700299 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700300 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800301 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700302 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800303 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700304 else:
305 raise NotImplementedError('Mode %s is not supported' % function)
306
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700307 if function != ADB_CMD and shell:
308 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700309
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700310 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700311
312 if serial:
313 cmd += '-s %s ' % serial
314 elif self._use_tcpip:
Simran Basi431010f2013-09-04 10:42:41 -0700315 cmd += '-s %s:5555 ' % self._device_hostname
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700316
Simran Basi431010f2013-09-04 10:42:41 -0700317 if shell:
318 cmd += '%s ' % SHELL_CMD
319 cmd += command
320
Roshan Pius58e5dd32015-10-16 15:16:42 -0700321 if verbose:
322 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700323
Kevin Cheng85e864a2015-11-30 11:49:34 -0800324 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400325 ignore_status=ignore_status,
326 ignore_timeout=ignore_timeout, stdout_tee=stdout,
327 stderr_tee=stderr, options=options, stdin=stdin,
328 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700329
330
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700331 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700332 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700333 """Determine the correct board label for the device.
334
335 @returns a string representing this device's board.
336 """
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700337 board = self.run_output('getprop %s' % BOARD_FILE)
338 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800339 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700340
341
Christopher Wiley08849d52013-11-22 08:57:58 -0800342 def job_start(self):
343 """
344 Disable log collection on adb_hosts.
345
346 TODO(sbasi): crbug.com/305427
Christopher Wiley08849d52013-11-22 08:57:58 -0800347 """
348
349
Simran Basi431010f2013-09-04 10:42:41 -0700350 def run(self, command, timeout=3600, ignore_status=False,
351 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
352 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700353 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700354 """Run a command on the adb device.
355
356 The command given will be ran directly on the adb device; for example
357 'ls' will be ran as: 'abd shell ls'
358
359 @param command: The command line string.
360 @param timeout: Time limit in seconds before attempting to
361 kill the running process. The run() function
362 will take a few seconds longer than 'timeout'
363 to complete if it has to kill the process.
364 @param ignore_status: Do not raise an exception, no matter
365 what the exit code of the command is.
366 @param ignore_timeout: Bool True if command timeouts should be
367 ignored. Will return None on command timeout.
368 @param stdout_tee: Redirect stdout.
369 @param stderr_tee: Redirect stderr.
370 @param connect_timeout: Connection timeout (in seconds).
371 @param options: String with additional ssh command options.
372 @param stdin: Stdin to pass (a string) to the executed command
373 @param args: Sequence of strings to pass as arguments to command by
374 quoting them in " and escaping their contents if
375 necessary.
376
377 @returns A CMDResult object or None if the call timed out and
378 ignore_timeout is True.
379
380 @raises AutoservRunError: If the command failed.
381 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700382 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700383 command = ('"%s; echo %s:\$?"' %
384 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700385 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700386 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700387 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
388 stdout=stdout_tee, stderr=stderr_tee,
389 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700390 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700391 if not result:
392 # In case of timeouts.
393 return None
394
395 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700396 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700397 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700398 'Failed to parse the exit code for command: %s' %
399 command, result)
400 elif parse_output:
401 result.stdout = parse_output.group('OUTPUT')
402 result.exit_status = int(parse_output.group('EXIT_CODE'))
403 if result.exit_status != 0 and not ignore_status:
404 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700405 return result
406
407
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700408 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
409 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700410
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700411 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700412
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700413 @param timeout: Time limit in seconds before returning even if the host
414 is not up.
415 @param command: The command used to test if a device is up, i.e.,
416 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700417
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700418 @returns True if the host was found to be up before the timeout expires,
419 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700420 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700421 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
422 delay_sec=1)
423 def _wait_up():
424 if not self.is_up(command=command):
425 raise error.TimeoutException('Device is still down.')
426 return True
427
428 try:
429 _wait_up()
430 logging.debug('Host %s is now up, and can be accessed by %s.',
431 self.hostname, command)
432 return True
433 except error.TimeoutException:
434 logging.debug('Host %s is still down after waiting %d seconds',
435 self.hostname, timeout)
436 return False
Simran Basi431010f2013-09-04 10:42:41 -0700437
438
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700439 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
440 warning_timer=None, old_boot_id=None, command=ADB_CMD):
441 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700442
443 Overrides wait_down from AbstractSSHHost.
444
445 @param timeout: Time in seconds to wait for the host to go down.
446 @param warning_timer: Time limit in seconds that will generate
447 a warning if the host is not down yet.
448 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700449 @param old_boot_id: Not applicable for adb_host.
450 @param command: `adb`, test if the device can be accessed by adb
451 command, or `fastboot`, test if the device can be accessed by
452 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700453
454 @returns True if the device goes down before the timeout, False
455 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700456 """
457 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
458 delay_sec=1)
459 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700460 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700461 raise error.TimeoutException('Device is still up.')
462 return True
463
464 try:
465 _wait_down()
466 logging.debug('Host %s is now down', self.hostname)
467 return True
468 except error.TimeoutException:
469 logging.debug('Host %s is still up after waiting %d seconds',
470 self.hostname, timeout)
471 return False
472
473
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700474 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700475 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700476
477 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700478 """
479 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700480 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700481 self.adb_run('reboot', timeout=10, ignore_timeout=True)
482 if not self.wait_down():
483 raise error.AutoservRebootError(
484 'ADB Device is still up after reboot')
485 if not self.wait_up():
486 raise error.AutoservRebootError(
487 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800488 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800489
490
Ralph Nathanb45eb672015-11-18 20:04:39 -0800491 def remount(self):
492 """Remounts paritions on the device read-write.
493
494 Specifically, the /system, /vendor (if present) and /oem (if present)
495 partitions on the device are remounted read-write.
496 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800497 self.adb_run('remount')
498
499
Kevin Cheng549beb42015-11-18 11:42:25 -0800500 @staticmethod
501 def parse_device_serials(devices_output):
502 """Return a list of parsed serials from the output.
503
504 @param devices_output: Output from either an adb or fastboot command.
505
506 @returns List of device serials
507 """
508 devices = []
509 for line in devices_output.splitlines():
510 match = re.search(DEVICE_FINDER_REGEX, line)
511 if match:
512 serial = match.group('SERIAL')
513 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
514 serial = DEVICE_NO_SERIAL_TAG
515 logging.debug('Found Device: %s', serial)
516 devices.append(serial)
517 return devices
518
519
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700520 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700521 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700522
523 @params use_adb: True to get adb accessible devices. Set to False to
524 get fastboot accessible devices.
525
Kevin Chengd19e6c62015-10-28 16:39:39 -0700526 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700527 """
528 if use_adb:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700529 result = self.adb_run('devices')
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700530 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700531 result = self.fastboot_run('devices')
Kevin Cheng549beb42015-11-18 11:42:25 -0800532 return self.parse_device_serials(result.stdout)
Simran Basi431010f2013-09-04 10:42:41 -0700533
534
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700535 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700536 """Get a list of devices currently attached to the test station and
537 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700538 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800539 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700540 raise error.AutoservError(
541 'Not given ADB serial but multiple devices detected')
542 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700543
544
545 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700546 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700547 accessible by fastboot command.
548 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700549 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800550 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700551 raise error.AutoservError(
552 'Not given fastboot serial but multiple devices detected')
553 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700554
555
556 def is_up(self, timeout=0, command=ADB_CMD):
557 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700558
559 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700560 @param command: `adb`, the device can be accessed by adb command,
561 or `fastboot`, the device can be accessed by fastboot command.
562 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700563
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700564 @returns True if the device is detectable by given command, False
565 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700566
567 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700568 if command == ADB_CMD:
569 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800570 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800571 # ADB has a device state, if the device is not online, no
572 # subsequent ADB command will complete.
573 if len(devices) == 0 or not self.is_device_ready():
574 logging.debug('Waiting for device to enter the ready state.')
575 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700576 elif command == FASTBOOT_CMD:
577 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800578 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700579 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700580 raise NotImplementedError('Mode %s is not supported' % command)
581
582 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700583
584
585 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700586 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700587
588 Called as the test ends. Will return the device to USB mode and kill
589 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700590 """
591 if self._use_tcpip:
592 # Return the device to usb mode.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400593 self.adb_run('usb')
Christopher Wiley08849d52013-11-22 08:57:58 -0800594 # TODO(sbasi) Originally, we would kill the server after each test to
595 # reduce the opportunity for bad server state to hang around.
596 # Unfortunately, there is a period of time after each kill during which
597 # the Android device becomes unusable, and if we start the next test
598 # too quickly, we'll get an error complaining about no ADB device
599 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700600 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800601 # |close| the associated teststation as well.
602 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700603 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700604
605
606 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700607 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700608
609 @param message String message to log into syslog
610 @param tag String tag prefix for syslog
611
612 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700613 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700614
615
616 def get_autodir(self):
617 """Return the directory to install autotest for client side tests."""
618 return '/data/autotest'
619
Kevin Cheng018db352015-09-20 02:22:08 -0700620
Kris Rambishde8f9d12015-12-16 12:42:41 -0800621 def is_device_ready(self):
622 """Return the if the device is ready for ADB commands."""
623 dev_state = self.adb_run('get-state').stdout.strip()
624 logging.debug('Current device state: %s', dev_state)
625 return dev_state == 'device'
626
627
Kevin Chengd19e6c62015-10-28 16:39:39 -0700628 def verify_connectivity(self):
629 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800630 if not self.is_device_ready():
631 raise error.AutoservHostError('device state is not in the '
632 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700633
634
Simran Basid3ba3fb2015-09-11 14:35:07 -0700635 def verify_software(self):
636 """Verify working software on an adb_host.
637
Simran Basi38f7ddf2015-09-18 12:25:03 -0700638 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700639 """
Dan Shiab999722015-12-04 14:27:08 -0800640 # Check if adb and fastboot are present.
641 self.teststation.run('which adb')
642 self.teststation.run('which fastboot')
643 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700644
Kevin Cheng018db352015-09-20 02:22:08 -0700645
Simran Basid3ba3fb2015-09-11 14:35:07 -0700646 def verify_job_repo_url(self, tag=''):
647 """Make sure job_repo_url of this host is valid.
648
Simran Basi38f7ddf2015-09-18 12:25:03 -0700649 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700650
651 @param tag: The tag from the server job, in the format
652 <job_id>-<user>/<hostname>, or <hostless> for a server job.
653 """
654 return
Kevin Cheng018db352015-09-20 02:22:08 -0700655
656
Simran Basi1b023762015-09-25 12:12:20 -0700657 def send_file(self, source, dest, delete_dest=False,
658 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700659 """Copy files from the drone to the device.
660
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400661 Just a note, there is the possibility the test station is localhost
662 which makes some of these steps redundant (e.g. creating tmp dir) but
663 that scenario will undoubtedly be a development scenario (test station
664 is also the moblab) and not the typical live test running scenario so
665 the redundancy I think is harmless.
666
Kevin Cheng018db352015-09-20 02:22:08 -0700667 @param source: The file/directory on the drone to send to the device.
668 @param dest: The destination path on the device to copy to.
669 @param delete_dest: A flag set to choose whether or not to delete
670 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700671 @param preserve_symlinks: Controls if symlinks on the source will be
672 copied as such on the destination or
673 transformed into the referenced
674 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700675 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700676 # If we need to preserve symlinks, let's check if the source is a
677 # symlink itself and if so, just create it on the device.
678 if preserve_symlinks:
679 symlink_target = None
680 try:
681 symlink_target = os.readlink(source)
682 except OSError:
683 # Guess it's not a symlink.
684 pass
685
686 if symlink_target is not None:
687 # Once we create the symlink, let's get out of here.
688 self.run('ln -s %s %s' % (symlink_target, dest))
689 return
690
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400691 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700692 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400693 src_path = os.path.join(tmp_dir, os.path.basename(dest))
694 # Now copy the file over to the test station so you can reference the
695 # file in the push command.
696 self.teststation.send_file(source, src_path,
697 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700698
699 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400700 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700701
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700702 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700703
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400704 # Cleanup the test station.
705 try:
706 self.teststation.run('rm -rf %s' % tmp_dir)
707 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
708 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700709
710
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700711 def _get_file_info(self, dest):
712 """Get permission and possible symlink info about file on the device.
713
714 These files are on the device so we only have shell commands (via adb)
715 to get the info we want. We'll use 'ls' to get it all.
716
717 @param dest: File to get info about.
718
719 @returns a dict of the file permissions and symlink.
720 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800721 # Grab file info.
722 file_info = self.run_output('ls -l %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700723 symlink = None
724 perms = 0
725 match = re.match(FILE_INFO_REGEX, file_info)
726 if match:
727 # Check if it's a symlink and grab the linked dest if it is.
728 if match.group('TYPE') == 'l':
729 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
730 if symlink_match:
731 symlink = symlink_match.group('SYMLINK')
732
733 # Set the perms.
734 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
735 if perm != '-':
736 perms |= perm_flag
737
738 return {'perms': perms,
739 'symlink': symlink}
740
741
Simran Basi1b023762015-09-25 12:12:20 -0700742 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
743 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700744 """Copy files from the device to the drone.
745
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400746 Just a note, there is the possibility the test station is localhost
747 which makes some of these steps redundant (e.g. creating tmp dir) but
748 that scenario will undoubtedly be a development scenario (test station
749 is also the moblab) and not the typical live test running scenario so
750 the redundancy I think is harmless.
751
Kevin Cheng018db352015-09-20 02:22:08 -0700752 @param source: The file/directory on the device to copy back to the
753 drone.
754 @param dest: The destination path on the drone to copy to.
755 @param delete_dest: A flag set to choose whether or not to delete
756 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700757 @param preserve_perm: Tells get_file() to try to preserve the sources
758 permissions on files and dirs.
759 @param preserve_symlinks: Try to preserve symlinks instead of
760 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700761 """
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400762 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700763 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400764 dest_path = os.path.join(tmp_dir, os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700765
766 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400767 self.teststation.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700768
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700769 source_info = {}
770 if preserve_symlinks or preserve_perm:
771 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700772
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700773 # If we want to preserve symlinks, just create it here, otherwise pull
774 # the file off the device.
775 if preserve_symlinks and source_info['symlink']:
776 os.symlink(source_info['symlink'], dest)
777 else:
Roshan Pius95567142015-11-03 09:56:08 -0800778 self.adb_run('pull %s %s' % (source, dest_path))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700779
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400780 # Copy over the file from the test station and clean up.
781 self.teststation.get_file(dest_path, dest)
782 try:
783 self.teststation.run('rm -rf %s' % tmp_dir)
784 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
785 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700786
787 if preserve_perm:
788 os.chmod(dest, source_info['perms'])
Kevin Cheng018db352015-09-20 02:22:08 -0700789
790
791 def get_release_version(self):
792 """Get the release version from the RELEASE_FILE on the device.
793
794 @returns The release string in the RELEASE_FILE.
795
796 """
797 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700798
799
800 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700801 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700802
Kevin Chengd19e6c62015-10-28 16:39:39 -0700803 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700804
805 @param parent: Parent directory of the returned tmp dir.
806
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700807 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700808 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700809 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
810 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700811 if not parent.startswith(TMP_DIR):
812 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700813 self.run('mkdir -p %s' % parent)
814 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
815 self.tmp_dirs.append(tmp_dir)
816 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700817
818
819 def get_platform(self):
820 """Determine the correct platform label for this host.
821
822 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700823 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700824
825 @returns a string representing this host's platform.
826 """
827 return 'adb'
828
829
Gilad Arnolda76bef02015-09-29 13:55:15 -0700830 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800831 """Get the OS type of the DUT, e.g., android or brillo.
832 """
833 if not self._os_type:
834 if self.run_output('getprop ro.product.brand') == 'Brillo':
835 self._os_type = OS_TYPE_BRILLO
836 else:
837 self._os_type = OS_TYPE_ANDROID
838
839 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700840
841
842 def _forward(self, reverse, args):
843 """Execute a forwarding command.
844
845 @param reverse: Whether this is reverse forwarding (Boolean).
846 @param args: List of command arguments.
847 """
848 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700849 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700850
851
852 def add_forwarding(self, src, dst, reverse=False, rebind=True):
853 """Forward a port between the ADB host and device.
854
855 Port specifications are any strings accepted as such by ADB, for
856 example 'tcp:8080'.
857
858 @param src: Port specification to forward from.
859 @param dst: Port specification to forward to.
860 @param reverse: Do reverse forwarding from device to host (Boolean).
861 @param rebind: Allow rebinding an already bound port (Boolean).
862 """
863 args = []
864 if not rebind:
865 args.append('--no-rebind')
866 args += [src, dst]
867 self._forward(reverse, args)
868
869
870 def remove_forwarding(self, src=None, reverse=False):
871 """Removes forwarding on port.
872
873 @param src: Port specification, or None to remove all forwarding.
874 @param reverse: Whether this is reverse forwarding (Boolean).
875 """
876 args = []
877 if src is None:
878 args.append('--remove-all')
879 else:
880 args += ['--remove', src]
881 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700882
883
884 def rpc_port_forward(self, port, local_port):
885 """
886 Forwards a port securely through a tunnel process from the server
887 to the DUT for RPC server connection.
888 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
889 to the DUT.
890
891 @param port: remote port on the DUT.
892 @param local_port: local forwarding port.
893
894 @return: the tunnel process.
895 """
896 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
897 return super(ADBHost, self).rpc_port_forward(port, local_port)
898
899
900 def rpc_port_disconnect(self, tunnel_proc, port):
901 """
902 Disconnects a previously forwarded port from the server to the DUT for
903 RPC server connection.
904 Remove the previously added 'ADB forward' rule to forward the RPC
905 packets from the AdbHost to the DUT.
906
907 @param tunnel_proc: the original tunnel process returned from
908 |rpc_port_forward|.
909 @param port: remote port on the DUT.
910
911 """
912 self.remove_forwarding('tcp:%s' % port)
913 super(ADBHost, self).rpc_port_disconnect(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700914
915
916 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700917 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700918
919 @raise: error.AutoservError if the device failed to reboot into
920 bootloader mode.
921 """
922 if self.is_up(command=FASTBOOT_CMD):
923 return
924 self.adb_run('reboot bootloader')
925 if not self.wait_up(command=FASTBOOT_CMD):
926 raise error.AutoservError(
927 'The device failed to reboot into bootloader mode.')
928
929
Dan Shie4e807b2015-12-10 09:04:03 -0800930 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700931 """Ensure the device is up and can be accessed by adb command.
932
Dan Shie4e807b2015-12-10 09:04:03 -0800933 @param timeout: Time limit in seconds before returning even if the host
934 is not up.
935
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700936 @raise: error.AutoservError if the device failed to reboot into
937 adb mode.
938 """
939 if self.is_up():
940 return
941 self.fastboot_run('reboot')
Dan Shie4e807b2015-12-10 09:04:03 -0800942 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700943 raise error.AutoservError(
944 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800945 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -0700946
947
948 @classmethod
949 def _get_build_info_from_build_url(cls, build_url):
950 """Get the Android build information from the build url.
951
952 @param build_url: The url to use for downloading Android artifacts.
953 pattern: http://$devserver:###/static/branch/target/build_id
954
955 @return: A dictionary of build information, including keys: board,
956 branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -0800957 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -0700958 """
Dan Shiab999722015-12-04 14:27:08 -0800959 if not build_url:
960 raise AndroidInstallError('Need build_url to download image files.')
961
962 try:
963 match = re.match(DEVSERVER_URL_REGEX, build_url)
964 return {'board': match.group('BOARD'),
965 'branch': match.group('BRANCH'),
966 'target': ('%s-%s' % (match.group('BOARD'),
967 match.group('BUILD_TYPE'))),
968 'build_id': match.group('BUILD_ID')}
969 except (AttributeError, IndexError, ValueError) as e:
970 raise AndroidInstallError(
971 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -0700972
973
Dan Shia2872172015-10-31 01:16:51 -0700974 @retry.retry(error.AutoservRunError, timeout_min=10)
975 def _download_file(self, build_url, file, dest_dir):
976 """Download the given file from the build url.
977
978 @param build_url: The url to use for downloading Android artifacts.
979 pattern: http://$devserver:###/static/branch/target/build_id
980 @param file: Name of the file to be downloaded, e.g., boot.img.
981 @param dest_dir: Destination folder for the file to be downloaded to.
982 """
983 src_url = os.path.join(build_url, file)
984 dest_file = os.path.join(dest_dir, file)
985 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400986 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Dan Shia2872172015-10-31 01:16:51 -0700987 except:
988 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400989 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -0700990 raise
991
992
Dan Shiab999722015-12-04 14:27:08 -0800993 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -0700994 """Download required image files from the given build_url to a local
995 directory in the machine runs fastboot command.
996
997 @param build_url: The url to use for downloading Android artifacts.
998 pattern: http://$devserver:###/static/branch/target/build_id
999
1000 @return: Path to the directory contains image files.
1001 """
Dan Shiab999722015-12-04 14:27:08 -08001002 build_info = self._get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001003
1004 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001005 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001006 image_files = [zipped_image_file] + ANDROID_STANDALONE_IMAGES
1007
1008 try:
1009 for image_file in image_files:
1010 self._download_file(build_url, image_file, image_dir)
1011
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001012 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1013 (image_dir, zipped_image_file, image_dir))
Dan Shia2872172015-10-31 01:16:51 -07001014
1015 return image_dir
1016 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001017 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001018 raise
1019
1020
Dan Shiab999722015-12-04 14:27:08 -08001021 def stage_brillo_image_files(self, build_url):
1022 """Download required brillo image files from the given build_url to a
1023 local directory in the machine runs fastboot command.
1024
1025 @param build_url: The url to use for downloading Android artifacts.
1026 pattern: http://$devserver:###/static/branch/target/build_id
1027
1028 @return: Path to the directory contains image files.
1029 """
1030 build_info = self._get_build_info_from_build_url(build_url)
1031
1032 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1033 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1034 image_dir = self.teststation.get_tmp_dir()
1035 image_files = [zipped_image_file, vendor_partitions_file]
1036
1037 try:
1038 for image_file in image_files:
1039 self._download_file(build_url, image_file, image_dir)
1040
1041 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1042 (image_dir, zipped_image_file, image_dir))
1043 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1044 (image_dir, vendor_partitions_file,
1045 os.path.join(image_dir, 'vendor')))
1046 return image_dir
1047 except:
1048 self.teststation.run('rm -rf %s' % image_dir)
1049 raise
1050
1051
Dan Shi50a412a2016-01-05 10:52:40 -08001052 def stage_build_for_install(self, build_name):
Dan Shi225b9042015-11-18 10:25:21 -08001053 """Stage a build on a devserver and return the build_url and devserver.
1054
1055 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001056
Dan Shi225b9042015-11-18 10:25:21 -08001057 @returns a tuple with an update URL like:
1058 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1059 and the devserver instance.
1060 """
1061 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001062 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1063 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001064 build_name = devserver.translate(build_name)
1065 branch, target, build_id = utils.parse_android_build(build_name)
Dan Shiab999722015-12-04 14:27:08 -08001066 is_brillo = self.get_os_type() == OS_TYPE_BRILLO
1067 devserver.trigger_download(target, build_id, branch, is_brillo,
1068 synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001069 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001070
1071
Dan Shie4e807b2015-12-10 09:04:03 -08001072 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001073 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001074 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001075
1076 Following are the steps used here to provision an android device:
1077 1. If build_local_path is not set, download the image zip file, e.g.,
1078 shamu-img-2284311.zip, unzip it.
1079 2. Run fastboot to install following artifacts:
1080 bootloader, radio, boot, system, vendor(only if exists)
1081
1082 Repair is not supported for Android devices yet.
1083
1084 @param build_url: The url to use for downloading Android artifacts.
1085 pattern: http://$devserver:###/static/$build
1086 @param build_local_path: The path to a local folder that contains the
1087 image files needed to provision the device. Note that the folder
1088 is in the machine running adb command, rather than the drone.
1089 @param wipe: If true, userdata will be wiped before flashing.
1090 @param flash_all: If True, all img files found in img_path will be
1091 flashed. Otherwise, only boot and system are flashed.
1092
1093 @raises AndroidInstallError if any error occurs.
1094 """
Dan Shia2872172015-10-31 01:16:51 -07001095 # If the build is not staged in local server yet, clean up the temp
1096 # folder used to store image files after the provision is completed.
1097 delete_build_folder = bool(not build_local_path)
1098
Dan Shi225b9042015-11-18 10:25:21 -08001099 if not build_url and self._parser.options.image:
Dan Shi50a412a2016-01-05 10:52:40 -08001100 build_url, _ = self.stage_build_for_install(
Dan Shi225b9042015-11-18 10:25:21 -08001101 self._parser.options.image)
1102
Dan Shia2872172015-10-31 01:16:51 -07001103 try:
1104 # Download image files needed for provision to a local directory.
1105 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001106 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001107
1108 # Device needs to be in bootloader mode for flashing.
1109 self.ensure_bootloader_mode()
1110
1111 if wipe:
Dan Shie4e807b2015-12-10 09:04:03 -08001112 self.fastboot_run('-w')
Dan Shia2872172015-10-31 01:16:51 -07001113
1114 # Get all *.img file in the build_local_path.
1115 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001116 image_files = self.teststation.run(
1117 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001118 images = dict([(os.path.basename(f), f) for f in image_files])
1119 for image, image_file in images.items():
1120 if image not in ANDROID_IMAGES:
1121 continue
1122 logging.info('Flashing %s...', image_file)
1123 self.fastboot_run('flash %s %s' % (image[:-4], image_file))
1124 if image == ANDROID_BOOTLOADER:
1125 self.fastboot_run('reboot-bootloader')
1126 self.wait_up(command=FASTBOOT_CMD)
1127 except Exception as e:
1128 logging.error('Install Android build failed with error: %s', e)
1129 # Re-raise the exception with type of AndroidInstallError.
1130 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1131 finally:
1132 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001133 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001134 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1135 DEFAULT_WAIT_UP_TIME_SECONDS)
1136 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001137 logging.info('Successfully installed Android build staged at %s.',
1138 build_url)
1139
1140
Dan Shiab999722015-12-04 14:27:08 -08001141 def install_brillo(self, build_url, build_local_path=None):
1142 """Install the Brillo DUT.
1143
1144 Following are the steps used here to provision an android device:
1145 1. If build_local_path is not set, download the image zip file, e.g.,
1146 dragonboard-img-123456.zip, unzip it. And download the vendor
1147 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1148 unzip it to vendor folder.
1149 2. Run provision_device script to install OS images and vendor
1150 partitions.
1151
1152 @param build_url: The url to use for downloading Android artifacts.
1153 pattern: http://$devserver:###/static/$build
1154 @param build_local_path: The path to a local folder that contains the
1155 image files needed to provision the device. Note that the folder
1156 is in the machine running adb command, rather than the drone.
1157
1158 @raises AndroidInstallError if any error occurs.
1159 """
1160 # If the build is not staged in local server yet, clean up the temp
1161 # folder used to store image files after the provision is completed.
1162 delete_build_folder = bool(not build_local_path)
1163
1164 if not build_url and self._parser.options.image:
Dan Shi50a412a2016-01-05 10:52:40 -08001165 build_url, _ = self.stage_build_for_install(
Dan Shiab999722015-12-04 14:27:08 -08001166 self._parser.options.image)
1167
1168 try:
1169 # Download image files needed for provision to a local directory.
1170 if not build_local_path:
1171 build_local_path = self.stage_brillo_image_files(build_url)
1172
1173 # Device needs to be in bootloader mode for flashing.
1174 self.ensure_bootloader_mode()
1175
1176 # Run provision_device command to install image files and vendor
1177 # partitions.
1178 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1179 cmd = (BRILLO_PROVISION_CMD %
1180 {'os_image_dir': build_local_path,
1181 'vendor_partition_dir': vendor_partition_dir})
1182 self.teststation.run(cmd)
1183 except Exception as e:
1184 logging.error('Install Brillo build failed with error: %s', e)
1185 # Re-raise the exception with type of AndroidInstallError.
1186 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1187 finally:
1188 if delete_build_folder:
1189 self.teststation.run('rm -rf %s' % build_local_path)
1190 self.ensure_adb_mode()
1191 logging.info('Successfully installed Android build staged at %s.',
1192 build_url)
1193
1194
Dan Shie4e807b2015-12-10 09:04:03 -08001195 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001196 flash_all=False):
1197 """Install the DUT.
1198
1199 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001200 pattern: http://$devserver:###/static/$build. If build_url is
1201 set to None, the code may try _parser.options.image to do the
1202 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001203 @param build_local_path: The path to a local directory that contains the
1204 image files needed to provision the device.
1205 @param wipe: If true, userdata will be wiped before flashing.
1206 @param flash_all: If True, all img files found in img_path will be
1207 flashed. Otherwise, only boot and system are flashed.
1208 """
1209 if self.get_os_type() == OS_TYPE_ANDROID:
1210 self.install_android(
1211 build_url=build_url, build_local_path=build_local_path,
1212 wipe=wipe, flash_all=flash_all)
Dan Shiab999722015-12-04 14:27:08 -08001213 elif self.get_os_type() == OS_TYPE_BRILLO:
1214 self.install_brillo(
1215 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001216 else:
1217 raise error.InstallError(
1218 'Installation of os type %s is not supported.' %
1219 self.get_os_type())
Kevin Chengd19e6c62015-10-28 16:39:39 -07001220
1221
1222 def list_files_glob(self, path_glob):
1223 """Get a list of files on the device given glob pattern path.
1224
1225 @param path_glob: The path glob that we want to return the list of
1226 files that match the glob. Relative paths will not work as
1227 expected. Supply an absolute path to get the list of files
1228 you're hoping for.
1229
1230 @returns List of files that match the path_glob.
1231 """
1232 # This is just in case path_glob has no path separator.
1233 base_path = os.path.dirname(path_glob) or '.'
1234 result = self.run('find %s -path \'%s\' -print' %
1235 (base_path, path_glob))
1236 if result.exit_status != 0:
1237 return []
1238 return result.stdout.splitlines()