blob: cc664d322983f642e29e64e75eb4ef4795dfd06d [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.
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -07004
5import datetime
Kevin Cheng3a4a57a2015-09-30 12:09:50 -07006import functools
Simran Basi431010f2013-09-04 10:42:41 -07007import logging
Kevin Cheng018db352015-09-20 02:22:08 -07008import os
Simran Basi431010f2013-09-04 10:42:41 -07009import re
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070010import stat
Dan Shia2872172015-10-31 01:16:51 -070011import sys
Simran Basi431010f2013-09-04 10:42:41 -070012import time
13
14import common
15
Simran Basi9c5d3982016-04-01 18:49:44 -070016from autotest_lib.client.bin import utils as client_utils
Dan Shi49d451f2016-04-19 09:25:01 -070017from autotest_lib.client.common_lib import android_utils
Simran Basi431010f2013-09-04 10:42:41 -070018from autotest_lib.client.common_lib import error
Dan Shi6450e142016-03-11 11:52:20 -080019from autotest_lib.client.common_lib import global_config
Dan Shi225b9042015-11-18 10:25:21 -080020from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070021from autotest_lib.client.common_lib.cros import retry
Dan Shi6450e142016-03-11 11:52:20 -080022from autotest_lib.server import afe_utils
Dan Shi225b9042015-11-18 10:25:21 -080023from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070024from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080025from autotest_lib.server import utils
Simran Basi5ace6f22016-01-06 17:30:44 -080026from autotest_lib.server.cros import provision
Dan Shi6450e142016-03-11 11:52:20 -080027from autotest_lib.server.cros.dynamic_suite import tools
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070028from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070029from autotest_lib.server.hosts import abstract_ssh
Kevin Chengc6a645a2015-12-18 11:15:10 -080030from autotest_lib.server.hosts import adb_label
31from autotest_lib.server.hosts import base_label
Kevin Cheng85e864a2015-11-30 11:49:34 -080032from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070033
34
Dan Shi6450e142016-03-11 11:52:20 -080035CONFIG = global_config.global_config
36
Dan Shi6ea3e1c2015-10-28 15:19:04 -070037ADB_CMD = 'adb'
38FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070039SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070040# Some devices have no serial, then `adb serial` has output such as:
41# (no serial number) device
42# ?????????? device
43DEVICE_NO_SERIAL_MSG = '(no serial number)'
44DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070045# Regex to find an adb device. Examples:
46# 0146B5580B01801B device
47# 018e0ecb20c97a62 device
48# 172.22.75.141:5555 device
Kevin Cheng224415e2016-04-22 11:32:10 -070049# localhost:22 device
Alexandru Branciogea380fb2016-04-01 16:01:34 +030050DEVICE_FINDER_REGEX = (r'^(?P<SERIAL>([\w-]+)|((tcp:)?' +
51 '\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}([:]5555)?)|' +
Kevin Cheng224415e2016-04-22 11:32:10 -070052 '((tcp:)?localhost([:]22)?)|' +
Filipe Brandenburger34363392015-08-13 14:57:45 -070053 re.escape(DEVICE_NO_SERIAL_MSG) +
Alexandru Branciogea380fb2016-04-01 16:01:34 +030054 r')[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070055CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
56CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
57 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070058RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070059BOARD_FILE = 'ro.product.device'
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -070060SDK_FILE = 'ro.build.version.sdk'
61LOGCAT_FILE = 'logcat.log'
Simran Basi38f7ddf2015-09-18 12:25:03 -070062TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070063# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080064# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070065FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
66FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
67# List of the perm stats indexed by the order they are listed in the example
68# supplied above.
69FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
70 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
71 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070072
Dan Shi6ea3e1c2015-10-28 15:19:04 -070073# Default maximum number of seconds to wait for a device to be down.
74DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
75# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080076DEFAULT_WAIT_UP_TIME_SECONDS = 300
77# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080078WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070079
Dan Shi7075f552016-04-21 15:42:41 -070080# Default timeout for retrying adb/fastboot command.
81DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS = 10
82
Dan Shia2872172015-10-31 01:16:51 -070083OS_TYPE_ANDROID = 'android'
84OS_TYPE_BRILLO = 'brillo'
85
Dan Shie234dea2016-01-20 17:15:17 -080086# Regex to parse build name to get the detailed build information.
Dan Shi6450e142016-03-11 11:52:20 -080087BUILD_REGEX = ('(?P<BRANCH>([^/]+))/(?P<BUILD_TARGET>([^/]+))-'
Dan Shie234dea2016-01-20 17:15:17 -080088 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))')
Dan Shia2872172015-10-31 01:16:51 -070089# Regex to parse devserver url to get the detailed build information. Sample
90# url: http://$devserver:8080/static/branch/target/build_id
Dan Shie234dea2016-01-20 17:15:17 -080091DEVSERVER_URL_REGEX = '.*/%s/*' % BUILD_REGEX
Dan Shia2872172015-10-31 01:16:51 -070092
Dan Shi6450e142016-03-11 11:52:20 -080093ANDROID_IMAGE_FILE_FMT = '%(build_target)s-img-%(build_id)s.zip'
Dan Shi49d451f2016-04-19 09:25:01 -070094
Dan Shiab999722015-12-04 14:27:08 -080095BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
Dan Shi6450e142016-03-11 11:52:20 -080096 '%(build_target)s-vendor_partitions-%(build_id)s.zip')
97AUTOTEST_SERVER_PACKAGE_FILE_FMT = (
98 '%(build_target)s-autotest_server_package-%(build_id)s.tar.bz2')
Simran Basi9228a6f2016-03-29 12:03:37 -070099ADB_DEVICE_PREFIXES = ['product:', 'model:', 'device:']
Dan Shia2872172015-10-31 01:16:51 -0700100
Simran Basi9c5d3982016-04-01 18:49:44 -0700101# Map of product names to build target name.
102PRODUCT_TARGET_MAP = {'dragon' : 'ryu',
103 'flo' : 'razor',
104 'flo_lte' : 'razorg',
105 'gm4g_sprout' : 'seed_l8150',
106 'flounder' : 'volantis',
107 'flounder_lte' : 'volantisg'}
108
Dan Shiab999722015-12-04 14:27:08 -0800109# Command to provision a Brillo device.
110# os_image_dir: The full path of the directory that contains all the Android image
111# files (from the image zip file).
112# vendor_partition_dir: The full path of the directory that contains all the
113# Brillo vendor partitions, and provision-device script.
114BRILLO_PROVISION_CMD = (
Simran Basi7e52c622016-01-05 15:43:51 -0800115 'sudo ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
Dan Shiab999722015-12-04 14:27:08 -0800116 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
117 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -0700118
Dan Shi12a4f662016-05-10 14:49:42 -0700119# Default timeout in minutes for fastboot commands.
120DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN = 10
121
David Purselle01548b2016-05-11 10:00:42 -0700122# Default permissions for files/dirs copied from the device.
123_DEFAULT_FILE_PERMS = 0o600
124_DEFAULT_DIR_PERMS = 0o700
125
Dan Shi626d5412016-05-16 16:05:13 -0700126# Constants for getprop return value for a given property.
127PROPERTY_VALUE_TRUE = '1'
128
Dan Shia2872172015-10-31 01:16:51 -0700129class AndroidInstallError(error.InstallError):
130 """Generic error for Android installation related exceptions."""
131
132
Simran Basi724b8a52013-09-30 11:19:31 -0700133class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700134 """This class represents a host running an ADB server."""
135
Simran Basi5ace6f22016-01-06 17:30:44 -0800136 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700137 _LABEL_FUNCTIONS = []
138 _DETECTABLE_LABELS = []
139 label_decorator = functools.partial(utils.add_label_detector,
140 _LABEL_FUNCTIONS,
141 _DETECTABLE_LABELS)
142
Dan Shi225b9042015-11-18 10:25:21 -0800143 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700144
Dan Shi6450e142016-03-11 11:52:20 -0800145 # Minimum build id that supports server side packaging. Older builds may
146 # not have server side package built or with Autotest code change to support
147 # server-side packaging.
148 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
149 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
150
beeps46dadc92013-11-07 14:07:10 -0800151 @staticmethod
152 def check_host(host, timeout=10):
153 """
154 Check if the given host is an adb host.
155
Simran Basi14622bb2015-11-25 13:23:40 -0800156 If SSH connectivity can't be established, check_host will try to use
157 user 'adb' as well. If SSH connectivity still can't be established
158 then the original SSH user is restored.
159
beeps46dadc92013-11-07 14:07:10 -0800160 @param host: An ssh host representing a device.
161 @param timeout: The timeout for the run command.
162
163
164 @return: True if the host device has adb.
165
166 @raises AutoservRunError: If the command failed.
167 @raises AutoservSSHTimeout: Ssh connection has timed out.
168 """
Dan Shi64e130f2015-12-16 14:45:44 -0800169 # host object may not have user attribute if it's a LocalHost object.
170 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800171 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800172 if not (host.hostname == 'localhost' or
173 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700174 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700175 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700176 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700177 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800178 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800179 if current_user is not None:
180 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800181 return False
182 return result.exit_status == 0
183
184
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700185 # TODO(garnold) Remove the 'serials' argument once all clients are made to
186 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700187 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700188 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700189 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700190 """Initialize an ADB Host.
191
192 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700193 test station connected to an Android DUT. This will be the DUT
194 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700195 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700196
197 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700198 @param serials: DEPRECATED (to be removed)
199 @param adb_serial: An ADB device serial. If None, assume a single
200 device is attached (and fail otherwise).
201 @param fastboot_serial: A fastboot device serial. If None, defaults to
202 the ADB serial (or assumes a single device if
203 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800204 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700205 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800206 # Sets up the is_client_install_supported field.
207 super(ADBHost, self)._initialize(hostname=hostname,
208 is_client_install_supported=False,
209 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800210
Kevin Chengd19e6c62015-10-28 16:39:39 -0700211 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800212 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi1bf60eb2015-12-01 16:39:29 -0800213 # TODO (sbasi/kevcheng): Once the teststation host is committed,
214 # refactor the serial retrieval.
215 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Simran Basi973bf712016-05-26 13:41:34 -0700216 fastboot_serial = fastboot_serial or self.host_attributes.get(
217 'fastboot_serial', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800218 self.adb_serial = adb_serial
Dan Shi3a011ed2016-04-26 12:26:53 -0700219 if adb_serial:
220 adb_prefix = any(adb_serial.startswith(p)
221 for p in ADB_DEVICE_PREFIXES)
222 self.fastboot_serial = (fastboot_serial or
223 ('tcp:%s' % adb_serial.split(':')[0] if
224 ':' in adb_serial and not adb_prefix else adb_serial))
225 self._use_tcpip = ':' in adb_serial and not adb_prefix
226 else:
227 self.fastboot_serial = fastboot_serial or adb_serial
228 self._use_tcpip = False
Kevin Cheng85e864a2015-11-30 11:49:34 -0800229 self.teststation = (teststation if teststation
230 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700231
232 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800233 if self.adb_serial:
234 msg += ', ADB serial: %s' % self.adb_serial
235 if self.fastboot_serial:
236 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700237 logging.debug(msg)
238
Simran Basibeb2bb22016-02-03 15:25:48 -0800239 # Try resetting the ADB daemon on the device, however if we are
240 # creating the host to do a repair job, the device maybe inaccesible
241 # via ADB.
242 try:
243 self._reset_adbd_connection()
244 except (error.AutotestHostRunError, error.AutoservRunError) as e:
245 logging.error('Unable to reset the device adb daemon connection: '
246 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800247 self._os_type = None
248
Simran Basi431010f2013-09-04 10:42:41 -0700249
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700250 def _connect_over_tcpip_as_needed(self):
251 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700252 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700253 return
254 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700255 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700256
257
Roshan Pius4d7540c2015-12-16 13:30:32 -0800258 def _restart_adbd_with_root_permissions(self):
259 """Restarts the adb daemon with root permissions."""
Dan Shi922de302016-04-22 15:19:18 -0700260 @retry.retry(error.AutoservRunError, timeout_min=20/60.0, delay_sec=1)
261 def run_adb_root():
262 """Run command `adb root`."""
263 self.adb_run('root')
264
265 # adb command may flake with error "device not found". Retry the root
266 # command to reduce the chance of flake.
267 run_adb_root()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800268 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
269 time.sleep(1)
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300270 self._connect_over_tcpip_as_needed()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800271 self.adb_run('wait-for-device')
272
273
Simran Basi9228a6f2016-03-29 12:03:37 -0700274 def _set_tcp_port(self):
275 """Ensure the device remains in tcp/ip mode after a reboot."""
276 if not self._use_tcpip:
277 return
278 port = self.adb_serial.split(':')[-1]
279 self.run('setprop persist.adb.tcp.port %s' % port)
280
281
Roshan Pius4d7540c2015-12-16 13:30:32 -0800282 def _reset_adbd_connection(self):
283 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800284 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700285 self._restart_adbd_with_root_permissions()
286 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800287
288
Kevin Cheng85e864a2015-11-30 11:49:34 -0800289 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800290 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700291 """Runs an adb command.
292
Kevin Chengd19e6c62015-10-28 16:39:39 -0700293 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700294
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700295 Refer to _device_run method for docstring for parameters.
296 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800297 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700298
299
Kevin Cheng85e864a2015-11-30 11:49:34 -0800300 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800301 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700302 """Runs an fastboot command.
303
Kevin Chengd19e6c62015-10-28 16:39:39 -0700304 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700305
306 Refer to _device_run method for docstring for parameters.
307 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800308 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700309
310
Dan Shi12a4f662016-05-10 14:49:42 -0700311 # pylint: disable=missing-docstring
312 @retry.retry(error.AutoservRunError,
313 timeout_min=DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN)
314 def _fastboot_run_with_retry(self, command, **kwargs):
315 """Runs an fastboot command with retry.
316
317 This command will launch on the test station.
318
319 Refer to _device_run method for docstring for parameters.
320 """
321 return self.fastboot_run(command, **kwargs)
322
323
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700324 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700325 timeout=3600, ignore_status=False, ignore_timeout=False,
326 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
327 connect_timeout=30, options='', stdin=None, verbose=True,
328 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700329 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700330
Kevin Chengd19e6c62015-10-28 16:39:39 -0700331 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700332
Simran Basi431010f2013-09-04 10:42:41 -0700333 @param command: Command to run.
334 @param shell: If true the command runs in the adb shell otherwise if
335 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700336 reboot with shell=False will call 'adb reboot'. This
337 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700338 @param timeout: Time limit in seconds before attempting to
339 kill the running process. The run() function
340 will take a few seconds longer than 'timeout'
341 to complete if it has to kill the process.
342 @param ignore_status: Do not raise an exception, no matter
343 what the exit code of the command is.
344 @param ignore_timeout: Bool True if command timeouts should be
345 ignored. Will return None on command timeout.
346 @param stdout: Redirect stdout.
347 @param stderr: Redirect stderr.
348 @param connect_timeout: Connection timeout (in seconds)
349 @param options: String with additional ssh command options
350 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700351 @param require_sudo: True to require sudo to run the command. Default is
352 False.
Simran Basi431010f2013-09-04 10:42:41 -0700353 @param args: Sequence of strings to pass as arguments to command by
354 quoting them in " and escaping their contents if
355 necessary.
356
357 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700358 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700359 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800360 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700361 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800362 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700363 else:
364 raise NotImplementedError('Mode %s is not supported' % function)
365
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700366 if function != ADB_CMD and shell:
367 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700368
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700369 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700370
371 if serial:
372 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700373
Simran Basi431010f2013-09-04 10:42:41 -0700374 if shell:
375 cmd += '%s ' % SHELL_CMD
376 cmd += command
377
Roshan Pius58e5dd32015-10-16 15:16:42 -0700378 if verbose:
379 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700380
Kevin Cheng85e864a2015-11-30 11:49:34 -0800381 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400382 ignore_status=ignore_status,
383 ignore_timeout=ignore_timeout, stdout_tee=stdout,
384 stderr_tee=stderr, options=options, stdin=stdin,
385 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700386
387
Dan Shi8c51bda2016-05-26 12:21:02 -0700388 def _run_output_with_retry(self, cmd):
389 """Call run_output method for the given command with retry.
390
391 adb command can be flaky some time and return empty string. It may take
392 several retries until a value can be returned.
393
394 @param cmd: The command to run.
395
396 @return: Return value from the command after retry.
397 """
398 try:
399 return client_utils.poll_for_condition(
400 lambda: self.run_output(cmd),
401 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS,
402 sleep_interval=0.5,
403 desc='Get return value for command `%s`' % cmd)
404 except client_utils.TimeoutError:
405 return ''
406
407
Dan Shie234dea2016-01-20 17:15:17 -0800408 def get_board_name(self):
409 """Get the name of the board, e.g., shamu, dragonboard etc.
410 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700411 product = self.run_output('getprop %s' % BOARD_FILE)
412 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800413
414
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700415 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700416 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700417 """Determine the correct board label for the device.
418
419 @returns a string representing this device's board.
420 """
Dan Shie234dea2016-01-20 17:15:17 -0800421 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700422 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800423 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700424
425
Christopher Wiley08849d52013-11-22 08:57:58 -0800426 def job_start(self):
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700427 """Overload of parent which intentionally doesn't log certain files.
Dan Shi2d279cf2016-05-27 22:06:10 +0000428
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700429 The parent implementation attempts to log certain Linux files, such as
430 /var/log, which do not exist on Android, thus there is no call to the
431 parent's job_start(). The sync call is made so that logcat logs can be
432 approximately matched to server logs.
Dan Shi2d279cf2016-05-27 22:06:10 +0000433 """
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700434 self._sync_time()
Christopher Wiley08849d52013-11-22 08:57:58 -0800435
436
Simran Basi431010f2013-09-04 10:42:41 -0700437 def run(self, command, timeout=3600, ignore_status=False,
438 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
439 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700440 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700441 """Run a command on the adb device.
442
443 The command given will be ran directly on the adb device; for example
444 'ls' will be ran as: 'abd shell ls'
445
446 @param command: The command line string.
447 @param timeout: Time limit in seconds before attempting to
448 kill the running process. The run() function
449 will take a few seconds longer than 'timeout'
450 to complete if it has to kill the process.
451 @param ignore_status: Do not raise an exception, no matter
452 what the exit code of the command is.
453 @param ignore_timeout: Bool True if command timeouts should be
454 ignored. Will return None on command timeout.
455 @param stdout_tee: Redirect stdout.
456 @param stderr_tee: Redirect stderr.
457 @param connect_timeout: Connection timeout (in seconds).
458 @param options: String with additional ssh command options.
459 @param stdin: Stdin to pass (a string) to the executed command
460 @param args: Sequence of strings to pass as arguments to command by
461 quoting them in " and escaping their contents if
462 necessary.
463
464 @returns A CMDResult object or None if the call timed out and
465 ignore_timeout is True.
466
467 @raises AutoservRunError: If the command failed.
468 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700469 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700470 command = ('"%s; echo %s:\$?"' %
471 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700472 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700473 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700474 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
475 stdout=stdout_tee, stderr=stderr_tee,
476 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700477 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700478 if not result:
479 # In case of timeouts.
480 return None
481
482 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700483 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700484 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700485 'Failed to parse the exit code for command: %s' %
486 command, result)
487 elif parse_output:
488 result.stdout = parse_output.group('OUTPUT')
489 result.exit_status = int(parse_output.group('EXIT_CODE'))
490 if result.exit_status != 0 and not ignore_status:
491 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700492 return result
493
494
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700495 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
496 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700497
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700498 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700499
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700500 @param timeout: Time limit in seconds before returning even if the host
501 is not up.
502 @param command: The command used to test if a device is up, i.e.,
503 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700504
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700505 @returns True if the host was found to be up before the timeout expires,
506 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700507 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700508 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
509 delay_sec=1)
510 def _wait_up():
511 if not self.is_up(command=command):
512 raise error.TimeoutException('Device is still down.')
513 return True
514
515 try:
516 _wait_up()
517 logging.debug('Host %s is now up, and can be accessed by %s.',
518 self.hostname, command)
519 return True
520 except error.TimeoutException:
521 logging.debug('Host %s is still down after waiting %d seconds',
522 self.hostname, timeout)
523 return False
Simran Basi431010f2013-09-04 10:42:41 -0700524
525
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700526 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
527 warning_timer=None, old_boot_id=None, command=ADB_CMD):
528 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700529
530 Overrides wait_down from AbstractSSHHost.
531
532 @param timeout: Time in seconds to wait for the host to go down.
533 @param warning_timer: Time limit in seconds that will generate
534 a warning if the host is not down yet.
535 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700536 @param old_boot_id: Not applicable for adb_host.
537 @param command: `adb`, test if the device can be accessed by adb
538 command, or `fastboot`, test if the device can be accessed by
539 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700540
541 @returns True if the device goes down before the timeout, False
542 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700543 """
544 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
545 delay_sec=1)
546 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700547 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700548 raise error.TimeoutException('Device is still up.')
549 return True
550
551 try:
552 _wait_down()
553 logging.debug('Host %s is now down', self.hostname)
554 return True
555 except error.TimeoutException:
556 logging.debug('Host %s is still up after waiting %d seconds',
557 self.hostname, timeout)
558 return False
559
560
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700561 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700562 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700563
564 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700565 """
566 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700567 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700568 self.adb_run('reboot', timeout=10, ignore_timeout=True)
569 if not self.wait_down():
570 raise error.AutoservRebootError(
571 'ADB Device is still up after reboot')
572 if not self.wait_up():
573 raise error.AutoservRebootError(
574 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800575 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800576
577
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300578 def fastboot_reboot(self):
579 """Do a fastboot reboot to go back to adb.
580
581 @raises AutoservRebootError if reboot failed.
582 """
583 self.fastboot_run('reboot')
584 if not self.wait_down(command=FASTBOOT_CMD):
585 raise error.AutoservRebootError(
586 'Device is still in fastboot mode after reboot')
587 if not self.wait_up():
588 raise error.AutoservRebootError(
589 'Device failed to boot to adb after fastboot reboot.')
590 self._reset_adbd_connection()
591
592
Ralph Nathanb45eb672015-11-18 20:04:39 -0800593 def remount(self):
594 """Remounts paritions on the device read-write.
595
596 Specifically, the /system, /vendor (if present) and /oem (if present)
597 partitions on the device are remounted read-write.
598 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800599 self.adb_run('remount')
600
601
Kevin Cheng549beb42015-11-18 11:42:25 -0800602 @staticmethod
603 def parse_device_serials(devices_output):
604 """Return a list of parsed serials from the output.
605
606 @param devices_output: Output from either an adb or fastboot command.
607
608 @returns List of device serials
609 """
610 devices = []
611 for line in devices_output.splitlines():
612 match = re.search(DEVICE_FINDER_REGEX, line)
613 if match:
614 serial = match.group('SERIAL')
615 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
616 serial = DEVICE_NO_SERIAL_TAG
617 logging.debug('Found Device: %s', serial)
618 devices.append(serial)
619 return devices
620
621
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700622 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700623 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700624
625 @params use_adb: True to get adb accessible devices. Set to False to
626 get fastboot accessible devices.
627
Kevin Chengd19e6c62015-10-28 16:39:39 -0700628 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700629 """
630 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300631 result = self.adb_run('devices').stdout
632 if self.adb_serial and self.adb_serial not in result:
633 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700634 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300635 result = self.fastboot_run('devices').stdout
636 if (self.fastboot_serial and
637 self.fastboot_serial not in result):
638 # fastboot devices won't list the devices using TCP
639 try:
640 if 'product' in self.fastboot_run('getvar product',
641 timeout=2).stderr:
642 result += '\n%s\tfastboot' % self.fastboot_serial
Kevin Chengcfcb2cf2016-04-13 10:04:36 -0700643 # The main reason we do a general Exception catch here instead
644 # of setting ignore_timeout/status to True is because even when
645 # the fastboot process has been nuked, it still stays around and
646 # so bgjob wants to warn us of this and tries to read the
647 # /proc/<pid>/stack file which then promptly returns an
648 # 'Operation not permitted' error since we're running as moblab
649 # and we don't have permission to read those files.
650 except Exception:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300651 pass
652 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700653
654
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700655 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700656 """Get a list of devices currently attached to the test station and
657 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700658 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800659 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700660 raise error.AutoservError(
661 'Not given ADB serial but multiple devices detected')
662 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700663
664
665 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700666 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700667 accessible by fastboot command.
668 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700669 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800670 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700671 raise error.AutoservError(
672 'Not given fastboot serial but multiple devices detected')
673 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700674
675
676 def is_up(self, timeout=0, command=ADB_CMD):
677 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700678
679 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700680 @param command: `adb`, the device can be accessed by adb command,
681 or `fastboot`, the device can be accessed by fastboot command.
682 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700683
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700684 @returns True if the device is detectable by given command, False
685 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700686
687 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700688 if command == ADB_CMD:
689 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800690 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800691 # ADB has a device state, if the device is not online, no
692 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800693 # DUT with single device connected may not have adb_serial set.
694 # Therefore, skip checking if serial is in the list of adb devices
695 # if self.adb_serial is not set.
696 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800697 logging.debug('Waiting for device to enter the ready state.')
698 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700699 elif command == FASTBOOT_CMD:
700 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800701 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700702 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700703 raise NotImplementedError('Mode %s is not supported' % command)
704
705 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700706
707
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700708 def stop_loggers(self):
709 """Inherited stop_loggers function.
710
711 Calls parent function and captures logcat, since the end of the run
712 is logically the end/stop of the logcat log.
713 """
714 super(ADBHost, self).stop_loggers()
715 # Record logcat log to a temporary file on the teststation.
716 tmp_dir = self.teststation.get_tmp_dir()
717 teststation_filename = os.path.join(tmp_dir, LOGCAT_FILE)
718 self.adb_run('logcat -v time -d > "%s"' % (teststation_filename))
719 # Copy-back the log to the drone's results directory.
720 logcat_filename = os.path.join(self.job.resultdir, LOGCAT_FILE)
721 self.teststation.get_file(teststation_filename, logcat_filename)
722 try:
723 self.teststation.run('rm -rf %s' % tmp_dir)
724 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
725 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
726
727
Simran Basi431010f2013-09-04 10:42:41 -0700728 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700729 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700730
731 Called as the test ends. Will return the device to USB mode and kill
732 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700733 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800734 # TODO(sbasi) Originally, we would kill the server after each test to
735 # reduce the opportunity for bad server state to hang around.
736 # Unfortunately, there is a period of time after each kill during which
737 # the Android device becomes unusable, and if we start the next test
738 # too quickly, we'll get an error complaining about no ADB device
739 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700740 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800741 # |close| the associated teststation as well.
742 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700743 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700744
745
746 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700747 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700748
749 @param message String message to log into syslog
750 @param tag String tag prefix for syslog
751
752 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700753 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700754
755
756 def get_autodir(self):
757 """Return the directory to install autotest for client side tests."""
758 return '/data/autotest'
759
Kevin Cheng018db352015-09-20 02:22:08 -0700760
Kris Rambishde8f9d12015-12-16 12:42:41 -0800761 def is_device_ready(self):
762 """Return the if the device is ready for ADB commands."""
Dan Shi7075f552016-04-21 15:42:41 -0700763 try:
764 # Retry to avoid possible flakes.
765 is_ready = client_utils.poll_for_condition(
766 lambda: self.adb_run('get-state').stdout.strip() == 'device',
767 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS, sleep_interval=1,
768 desc='Waiting for device state to be `device`')
769 except client_utils.TimeoutError:
770 is_ready = False
771
772 logging.debug('Device state is %sready', '' if is_ready else 'NOT ')
773 return is_ready
Kris Rambishde8f9d12015-12-16 12:42:41 -0800774
775
Kevin Chengd19e6c62015-10-28 16:39:39 -0700776 def verify_connectivity(self):
777 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800778 if not self.is_device_ready():
779 raise error.AutoservHostError('device state is not in the '
780 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700781
782
Simran Basid3ba3fb2015-09-11 14:35:07 -0700783 def verify_software(self):
784 """Verify working software on an adb_host.
785
Simran Basi38f7ddf2015-09-18 12:25:03 -0700786 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700787 """
Dan Shiab999722015-12-04 14:27:08 -0800788 # Check if adb and fastboot are present.
789 self.teststation.run('which adb')
790 self.teststation.run('which fastboot')
791 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700792
Dan Shi626d5412016-05-16 16:05:13 -0700793 # Apply checks only for Android device.
Dan Shi1e2a98a2016-05-18 12:08:08 -0700794 if self.get_os_type() == OS_TYPE_ANDROID:
Dan Shi626d5412016-05-16 16:05:13 -0700795 # Make sure ro.boot.hardware and ro.build.product match.
Dan Shi8c51bda2016-05-26 12:21:02 -0700796 hardware = self._run_output_with_retry('getprop ro.boot.hardware')
797 product = self._run_output_with_retry('getprop ro.build.product')
Dan Shi1e2a98a2016-05-18 12:08:08 -0700798 if hardware != product:
799 raise error.AutoservHostError('ro.boot.hardware: %s does not '
800 'match to ro.build.product: %s' %
801 (hardware, product))
802
Dan Shi626d5412016-05-16 16:05:13 -0700803 # Check the bootloader is not locked. sys.oem_unlock_allowed is not
804 # applicable to Brillo devices.
Dan Shi8c51bda2016-05-26 12:21:02 -0700805 result = self._run_output_with_retry(
806 'getprop sys.oem_unlock_allowed')
Dan Shi626d5412016-05-16 16:05:13 -0700807 if result != PROPERTY_VALUE_TRUE:
808 raise error.AutoservHostError(
809 'The bootloader is locked. sys.oem_unlock_allowed: %s.'
810 % result)
811
Kevin Cheng018db352015-09-20 02:22:08 -0700812
Simran Basid3ba3fb2015-09-11 14:35:07 -0700813 def verify_job_repo_url(self, tag=''):
814 """Make sure job_repo_url of this host is valid.
815
Simran Basi38f7ddf2015-09-18 12:25:03 -0700816 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700817
818 @param tag: The tag from the server job, in the format
819 <job_id>-<user>/<hostname>, or <hostless> for a server job.
820 """
821 return
Kevin Cheng018db352015-09-20 02:22:08 -0700822
823
Simran Basibeb2bb22016-02-03 15:25:48 -0800824 def repair(self):
825 """Attempt to get the DUT to pass `self.verify()`."""
826 try:
827 self.ensure_adb_mode(timeout=30)
828 return
829 except error.AutoservError as e:
830 logging.error(e)
831 logging.debug('Verifying the device is accessible via fastboot.')
832 self.ensure_bootloader_mode()
833 if not self.job.run_test(
834 'provision_AndroidUpdate', host=self, value=None,
835 force=True, repair=True):
836 raise error.AutoservRepairTotalFailure(
837 'Unable to repair the device.')
838
839
Simran Basi1b023762015-09-25 12:12:20 -0700840 def send_file(self, source, dest, delete_dest=False,
841 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700842 """Copy files from the drone to the device.
843
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400844 Just a note, there is the possibility the test station is localhost
845 which makes some of these steps redundant (e.g. creating tmp dir) but
846 that scenario will undoubtedly be a development scenario (test station
847 is also the moblab) and not the typical live test running scenario so
848 the redundancy I think is harmless.
849
Kevin Cheng018db352015-09-20 02:22:08 -0700850 @param source: The file/directory on the drone to send to the device.
851 @param dest: The destination path on the device to copy to.
852 @param delete_dest: A flag set to choose whether or not to delete
853 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700854 @param preserve_symlinks: Controls if symlinks on the source will be
855 copied as such on the destination or
856 transformed into the referenced
857 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700858 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700859 # If we need to preserve symlinks, let's check if the source is a
860 # symlink itself and if so, just create it on the device.
861 if preserve_symlinks:
862 symlink_target = None
863 try:
864 symlink_target = os.readlink(source)
865 except OSError:
866 # Guess it's not a symlink.
867 pass
868
869 if symlink_target is not None:
870 # Once we create the symlink, let's get out of here.
871 self.run('ln -s %s %s' % (symlink_target, dest))
872 return
873
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400874 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700875 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400876 src_path = os.path.join(tmp_dir, os.path.basename(dest))
877 # Now copy the file over to the test station so you can reference the
878 # file in the push command.
879 self.teststation.send_file(source, src_path,
880 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700881
882 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400883 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700884
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700885 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700886
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400887 # Cleanup the test station.
888 try:
889 self.teststation.run('rm -rf %s' % tmp_dir)
890 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
891 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700892
893
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700894 def _get_file_info(self, dest):
895 """Get permission and possible symlink info about file on the device.
896
897 These files are on the device so we only have shell commands (via adb)
898 to get the info we want. We'll use 'ls' to get it all.
899
900 @param dest: File to get info about.
901
902 @returns a dict of the file permissions and symlink.
903 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800904 # Grab file info.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700905 file_info = self.run_output('ls -ld %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700906 symlink = None
907 perms = 0
908 match = re.match(FILE_INFO_REGEX, file_info)
909 if match:
910 # Check if it's a symlink and grab the linked dest if it is.
911 if match.group('TYPE') == 'l':
912 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
913 if symlink_match:
914 symlink = symlink_match.group('SYMLINK')
915
916 # Set the perms.
917 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
918 if perm != '-':
919 perms |= perm_flag
920
921 return {'perms': perms,
922 'symlink': symlink}
923
924
Simran Basi1b023762015-09-25 12:12:20 -0700925 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
926 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700927 """Copy files from the device to the drone.
928
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400929 Just a note, there is the possibility the test station is localhost
930 which makes some of these steps redundant (e.g. creating tmp dir) but
931 that scenario will undoubtedly be a development scenario (test station
932 is also the moblab) and not the typical live test running scenario so
933 the redundancy I think is harmless.
934
Kevin Cheng018db352015-09-20 02:22:08 -0700935 @param source: The file/directory on the device to copy back to the
936 drone.
937 @param dest: The destination path on the drone to copy to.
938 @param delete_dest: A flag set to choose whether or not to delete
939 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700940 @param preserve_perm: Tells get_file() to try to preserve the sources
941 permissions on files and dirs.
942 @param preserve_symlinks: Try to preserve symlinks instead of
943 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700944 """
David Purselle01548b2016-05-11 10:00:42 -0700945 # Stage the files on the test station under teststation_temp_dir.
946 teststation_temp_dir = self.teststation.get_tmp_dir()
947 teststation_dest = os.path.join(teststation_temp_dir,
948 os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700949
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700950 source_info = {}
951 if preserve_symlinks or preserve_perm:
952 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700953
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700954 # If we want to preserve symlinks, just create it here, otherwise pull
955 # the file off the device.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700956 #
957 # TODO(sadmac): Directories containing symlinks won't behave as
958 # expected.
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700959 if preserve_symlinks and source_info['symlink']:
960 os.symlink(source_info['symlink'], dest)
961 else:
David Purselle01548b2016-05-11 10:00:42 -0700962 self.adb_run('pull %s %s' % (source, teststation_temp_dir))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700963
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400964 # Copy over the file from the test station and clean up.
David Purselle01548b2016-05-11 10:00:42 -0700965 self.teststation.get_file(teststation_dest, dest,
966 delete_dest=delete_dest)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400967 try:
David Purselle01548b2016-05-11 10:00:42 -0700968 self.teststation.run('rm -rf %s' % teststation_temp_dir)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400969 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
David Purselle01548b2016-05-11 10:00:42 -0700970 logging.warn('failed to remove dir %s: %s',
971 teststation_temp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700972
David Pursell788b1b52016-05-19 09:03:31 -0700973 # Source will be copied under dest if either:
974 # 1. Source is a directory and doesn't end with /.
975 # 2. Source is a file and dest is a directory.
976 source_is_dir = self.run('[ -d "$${%s} ]',
977 ignore_status=True).exit_status == 0
978 if ((source_is_dir and not source.endswith(os.sep)) or
979 (not source_is_dir and os.path.isdir(dest))):
980 receive_path = os.path.join(dest, os.path.basename(source))
981 else:
982 receive_path = dest
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700983
David Pursell788b1b52016-05-19 09:03:31 -0700984 # Set the permissions of the received file/dirs.
985 if os.path.isdir(receive_path):
986 for root, _dirs, files in os.walk(receive_path):
987 def process(rel_path, default_perm):
988 info = self._get_file_info(os.path.join(source,
989 rel_path))
990 if info['perms'] != 0:
991 target = os.path.join(receive_path, rel_path)
992 if preserve_perm:
993 os.chmod(target, info['perms'])
994 else:
995 os.chmod(target, default_perm)
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700996
David Pursell788b1b52016-05-19 09:03:31 -0700997 rel_root = os.path.relpath(root, receive_path)
998 process(rel_root, _DEFAULT_DIR_PERMS)
999 for f in files:
1000 process(os.path.join(rel_root, f), _DEFAULT_FILE_PERMS)
1001 elif preserve_perm:
1002 os.chmod(receive_path, source_info['perms'])
1003 else:
1004 os.chmod(receive_path, _DEFAULT_FILE_PERMS)
Kevin Cheng018db352015-09-20 02:22:08 -07001005
1006
1007 def get_release_version(self):
1008 """Get the release version from the RELEASE_FILE on the device.
1009
1010 @returns The release string in the RELEASE_FILE.
1011
1012 """
1013 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -07001014
1015
1016 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001017 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -07001018
Kevin Chengd19e6c62015-10-28 16:39:39 -07001019 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -07001020
1021 @param parent: Parent directory of the returned tmp dir.
1022
Kevin Cheng3a4a57a2015-09-30 12:09:50 -07001023 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -07001024 """
Kevin Chengd19e6c62015-10-28 16:39:39 -07001025 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
1026 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -07001027 if not parent.startswith(TMP_DIR):
1028 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -07001029 self.run('mkdir -p %s' % parent)
1030 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
1031 self.tmp_dirs.append(tmp_dir)
1032 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -07001033
1034
1035 def get_platform(self):
1036 """Determine the correct platform label for this host.
1037
1038 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -07001039 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -07001040
1041 @returns a string representing this host's platform.
1042 """
1043 return 'adb'
1044
1045
Gilad Arnolda76bef02015-09-29 13:55:15 -07001046 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -08001047 """Get the OS type of the DUT, e.g., android or brillo.
1048 """
1049 if not self._os_type:
1050 if self.run_output('getprop ro.product.brand') == 'Brillo':
1051 self._os_type = OS_TYPE_BRILLO
1052 else:
1053 self._os_type = OS_TYPE_ANDROID
1054
1055 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001056
1057
1058 def _forward(self, reverse, args):
1059 """Execute a forwarding command.
1060
1061 @param reverse: Whether this is reverse forwarding (Boolean).
1062 @param args: List of command arguments.
1063 """
1064 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001065 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001066
1067
1068 def add_forwarding(self, src, dst, reverse=False, rebind=True):
1069 """Forward a port between the ADB host and device.
1070
1071 Port specifications are any strings accepted as such by ADB, for
1072 example 'tcp:8080'.
1073
1074 @param src: Port specification to forward from.
1075 @param dst: Port specification to forward to.
1076 @param reverse: Do reverse forwarding from device to host (Boolean).
1077 @param rebind: Allow rebinding an already bound port (Boolean).
1078 """
1079 args = []
1080 if not rebind:
1081 args.append('--no-rebind')
1082 args += [src, dst]
1083 self._forward(reverse, args)
1084
1085
1086 def remove_forwarding(self, src=None, reverse=False):
1087 """Removes forwarding on port.
1088
1089 @param src: Port specification, or None to remove all forwarding.
1090 @param reverse: Whether this is reverse forwarding (Boolean).
1091 """
1092 args = []
1093 if src is None:
1094 args.append('--remove-all')
1095 else:
1096 args += ['--remove', src]
1097 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001098
1099
xixuan6cf6d2f2016-01-29 15:29:00 -08001100 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001101 """
1102 Forwards a port securely through a tunnel process from the server
1103 to the DUT for RPC server connection.
1104 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
1105 to the DUT.
1106
1107 @param port: remote port on the DUT.
1108 @param local_port: local forwarding port.
1109
1110 @return: the tunnel process.
1111 """
1112 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001113 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001114
1115
xixuan6cf6d2f2016-01-29 15:29:00 -08001116 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001117 """
1118 Disconnects a previously forwarded port from the server to the DUT for
1119 RPC server connection.
1120 Remove the previously added 'ADB forward' rule to forward the RPC
1121 packets from the AdbHost to the DUT.
1122
1123 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -08001124 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -07001125 @param port: remote port on the DUT.
1126
1127 """
1128 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001129 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001130
1131
1132 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001133 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001134
1135 @raise: error.AutoservError if the device failed to reboot into
1136 bootloader mode.
1137 """
1138 if self.is_up(command=FASTBOOT_CMD):
1139 return
1140 self.adb_run('reboot bootloader')
1141 if not self.wait_up(command=FASTBOOT_CMD):
1142 raise error.AutoservError(
1143 'The device failed to reboot into bootloader mode.')
1144
1145
Dan Shie4e807b2015-12-10 09:04:03 -08001146 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001147 """Ensure the device is up and can be accessed by adb command.
1148
Dan Shie4e807b2015-12-10 09:04:03 -08001149 @param timeout: Time limit in seconds before returning even if the host
1150 is not up.
1151
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001152 @raise: error.AutoservError if the device failed to reboot into
1153 adb mode.
1154 """
1155 if self.is_up():
1156 return
Dan Shi04980372016-03-22 10:57:47 -07001157 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1158 # check if the device is in adb mode.
1159 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001160 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001161 raise error.AutoservError(
1162 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001163 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001164
1165
1166 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001167 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001168 """Get the Android build information from the build url.
1169
1170 @param build_url: The url to use for downloading Android artifacts.
1171 pattern: http://$devserver:###/static/branch/target/build_id
1172
Dan Shi6450e142016-03-11 11:52:20 -08001173 @return: A dictionary of build information, including keys:
1174 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001175 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001176 """
Dan Shiab999722015-12-04 14:27:08 -08001177 if not build_url:
1178 raise AndroidInstallError('Need build_url to download image files.')
1179
1180 try:
1181 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001182 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001183 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001184 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001185 match.group('BUILD_TYPE'))),
1186 'build_id': match.group('BUILD_ID')}
1187 except (AttributeError, IndexError, ValueError) as e:
1188 raise AndroidInstallError(
1189 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001190
1191
Dan Shia2872172015-10-31 01:16:51 -07001192 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001193 def download_file(self, build_url, file, dest_dir, unzip=False,
1194 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001195 """Download the given file from the build url.
1196
1197 @param build_url: The url to use for downloading Android artifacts.
1198 pattern: http://$devserver:###/static/branch/target/build_id
1199 @param file: Name of the file to be downloaded, e.g., boot.img.
1200 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001201 @param unzip: If True, unzip the downloaded file.
1202 @param unzip_dest: Location to unzip the downloaded file to. If not
1203 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001204 """
Dan Shidb0366c2016-02-19 10:36:18 -08001205 # Append the file name to the url if build_url is linked to the folder
1206 # containing the file.
1207 if not build_url.endswith('/%s' % file):
1208 src_url = os.path.join(build_url, file)
1209 else:
1210 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001211 dest_file = os.path.join(dest_dir, file)
1212 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001213 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001214 if unzip:
1215 unzip_dest = unzip_dest or dest_dir
1216 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1217 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001218 except:
1219 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001220 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001221 raise
1222
1223
Dan Shiab999722015-12-04 14:27:08 -08001224 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001225 """Download required image files from the given build_url to a local
1226 directory in the machine runs fastboot command.
1227
1228 @param build_url: The url to use for downloading Android artifacts.
1229 pattern: http://$devserver:###/static/branch/target/build_id
1230
1231 @return: Path to the directory contains image files.
1232 """
Dan Shi08ff1282016-02-18 19:51:16 -08001233 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001234
1235 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001236 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001237
1238 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001239 self.download_file(build_url, zipped_image_file, image_dir,
1240 unzip=True)
Dan Shi49d451f2016-04-19 09:25:01 -07001241 images = android_utils.AndroidImageFiles.get_standalone_images(
1242 build_info['build_target'])
1243 for image_file in images:
Dan Shidb0366c2016-02-19 10:36:18 -08001244 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001245
Dan Shia2872172015-10-31 01:16:51 -07001246 return image_dir
1247 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001248 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001249 raise
1250
1251
Dan Shiab999722015-12-04 14:27:08 -08001252 def stage_brillo_image_files(self, build_url):
1253 """Download required brillo image files from the given build_url to a
1254 local directory in the machine runs fastboot command.
1255
1256 @param build_url: The url to use for downloading Android artifacts.
1257 pattern: http://$devserver:###/static/branch/target/build_id
1258
1259 @return: Path to the directory contains image files.
1260 """
Dan Shi08ff1282016-02-18 19:51:16 -08001261 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001262
1263 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1264 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1265 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001266
1267 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001268 self.download_file(build_url, zipped_image_file, image_dir,
1269 unzip=True)
1270 self.download_file(build_url, vendor_partitions_file, image_dir,
1271 unzip=True,
1272 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001273 return image_dir
1274 except:
1275 self.teststation.run('rm -rf %s' % image_dir)
1276 raise
1277
1278
Simran Basibeb2bb22016-02-03 15:25:48 -08001279 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001280 """Stage a build on a devserver and return the build_url and devserver.
1281
1282 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001283
Dan Shi225b9042015-11-18 10:25:21 -08001284 @returns a tuple with an update URL like:
1285 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1286 and the devserver instance.
1287 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001288 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001289 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001290 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1291 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001292 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001293 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001294 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001295 devserver.trigger_download(target, build_id, branch,
1296 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001297 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001298
1299
Dan Shie4e807b2015-12-10 09:04:03 -08001300 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001301 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001302 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001303
1304 Following are the steps used here to provision an android device:
1305 1. If build_local_path is not set, download the image zip file, e.g.,
1306 shamu-img-2284311.zip, unzip it.
1307 2. Run fastboot to install following artifacts:
1308 bootloader, radio, boot, system, vendor(only if exists)
1309
1310 Repair is not supported for Android devices yet.
1311
1312 @param build_url: The url to use for downloading Android artifacts.
1313 pattern: http://$devserver:###/static/$build
1314 @param build_local_path: The path to a local folder that contains the
1315 image files needed to provision the device. Note that the folder
1316 is in the machine running adb command, rather than the drone.
1317 @param wipe: If true, userdata will be wiped before flashing.
1318 @param flash_all: If True, all img files found in img_path will be
1319 flashed. Otherwise, only boot and system are flashed.
1320
1321 @raises AndroidInstallError if any error occurs.
1322 """
Dan Shia2872172015-10-31 01:16:51 -07001323 # If the build is not staged in local server yet, clean up the temp
1324 # folder used to store image files after the provision is completed.
1325 delete_build_folder = bool(not build_local_path)
1326
1327 try:
1328 # Download image files needed for provision to a local directory.
1329 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001330 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001331
1332 # Device needs to be in bootloader mode for flashing.
1333 self.ensure_bootloader_mode()
1334
1335 if wipe:
Dan Shi12a4f662016-05-10 14:49:42 -07001336 self._fastboot_run_with_retry('-w')
Dan Shia2872172015-10-31 01:16:51 -07001337
1338 # Get all *.img file in the build_local_path.
1339 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001340 image_files = self.teststation.run(
1341 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001342 images = dict([(os.path.basename(f), f) for f in image_files])
Dan Shi49d451f2016-04-19 09:25:01 -07001343 build_info = self.get_build_info_from_build_url(build_url)
1344 board = build_info['build_target']
1345 all_images = (
1346 android_utils.AndroidImageFiles.get_standalone_images(board)
1347 + android_utils.AndroidImageFiles.get_zipped_images(board))
1348
1349 # Sort images to be flashed, bootloader needs to be the first one.
1350 bootloader = android_utils.AndroidImageFiles.BOOTLOADER
1351 sorted_images = sorted(
1352 images.items(),
1353 key=lambda pair: 0 if pair[0] == bootloader else 1)
1354 for image, image_file in sorted_images:
1355 if image not in all_images:
Dan Shia2872172015-10-31 01:16:51 -07001356 continue
1357 logging.info('Flashing %s...', image_file)
Dan Shi12a4f662016-05-10 14:49:42 -07001358 self._fastboot_run_with_retry('-S 256M flash %s %s' %
1359 (image[:-4], image_file))
Dan Shi49d451f2016-04-19 09:25:01 -07001360 if image == android_utils.AndroidImageFiles.BOOTLOADER:
Dan Shia2872172015-10-31 01:16:51 -07001361 self.fastboot_run('reboot-bootloader')
1362 self.wait_up(command=FASTBOOT_CMD)
1363 except Exception as e:
1364 logging.error('Install Android build failed with error: %s', e)
1365 # Re-raise the exception with type of AndroidInstallError.
1366 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1367 finally:
1368 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001369 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001370 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1371 DEFAULT_WAIT_UP_TIME_SECONDS)
1372 self.ensure_adb_mode(timeout=timeout)
Simran Basiac86aee2016-05-17 17:31:56 -07001373 # Skip the setup wizard.
1374 self.run('am start -n com.google.android.setupwizard/'
1375 '.SetupWizardExitActivity')
Dan Shia2872172015-10-31 01:16:51 -07001376 logging.info('Successfully installed Android build staged at %s.',
1377 build_url)
1378
1379
Dan Shiab999722015-12-04 14:27:08 -08001380 def install_brillo(self, build_url, build_local_path=None):
1381 """Install the Brillo DUT.
1382
1383 Following are the steps used here to provision an android device:
1384 1. If build_local_path is not set, download the image zip file, e.g.,
1385 dragonboard-img-123456.zip, unzip it. And download the vendor
1386 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1387 unzip it to vendor folder.
1388 2. Run provision_device script to install OS images and vendor
1389 partitions.
1390
1391 @param build_url: The url to use for downloading Android artifacts.
1392 pattern: http://$devserver:###/static/$build
1393 @param build_local_path: The path to a local folder that contains the
1394 image files needed to provision the device. Note that the folder
1395 is in the machine running adb command, rather than the drone.
1396
1397 @raises AndroidInstallError if any error occurs.
1398 """
1399 # If the build is not staged in local server yet, clean up the temp
1400 # folder used to store image files after the provision is completed.
1401 delete_build_folder = bool(not build_local_path)
1402
Dan Shiab999722015-12-04 14:27:08 -08001403 try:
1404 # Download image files needed for provision to a local directory.
1405 if not build_local_path:
1406 build_local_path = self.stage_brillo_image_files(build_url)
1407
1408 # Device needs to be in bootloader mode for flashing.
1409 self.ensure_bootloader_mode()
1410
1411 # Run provision_device command to install image files and vendor
1412 # partitions.
1413 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1414 cmd = (BRILLO_PROVISION_CMD %
1415 {'os_image_dir': build_local_path,
1416 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001417 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001418 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001419 self.teststation.run(cmd)
1420 except Exception as e:
1421 logging.error('Install Brillo build failed with error: %s', e)
1422 # Re-raise the exception with type of AndroidInstallError.
1423 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1424 finally:
1425 if delete_build_folder:
1426 self.teststation.run('rm -rf %s' % build_local_path)
1427 self.ensure_adb_mode()
1428 logging.info('Successfully installed Android build staged at %s.',
1429 build_url)
1430
1431
Dan Shibe3636a2016-02-14 22:48:01 -08001432 @property
1433 def job_repo_url_attribute(self):
1434 """Get the host attribute name for job_repo_url, which should append the
1435 adb serial.
1436 """
1437 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1438
1439
Dan Shie4e807b2015-12-10 09:04:03 -08001440 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001441 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001442 """Install the DUT.
1443
1444 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001445 pattern: http://$devserver:###/static/$build. If build_url is
1446 set to None, the code may try _parser.options.image to do the
1447 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001448 @param build_local_path: The path to a local directory that contains the
1449 image files needed to provision the device.
1450 @param wipe: If true, userdata will be wiped before flashing.
1451 @param flash_all: If True, all img files found in img_path will be
1452 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001453
Dan Shibe3636a2016-02-14 22:48:01 -08001454 @returns A tuple of (image_name, host_attributes).
1455 image_name is the name of image installed, e.g.,
1456 git_mnc-release/shamu-userdebug/1234
1457 host_attributes is a dictionary of (attribute, value), which
1458 can be saved to afe_host_attributes table in database. This
1459 method returns a dictionary with a single entry of
1460 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1461 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001462 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001463 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001464 if not build_url and self._parser.options.image:
1465 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001466 self._parser.options.image, os_type=os_type)
1467 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001468 self.install_android(
1469 build_url=build_url, build_local_path=build_local_path,
1470 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001471 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001472 self.install_brillo(
1473 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001474 else:
1475 raise error.InstallError(
1476 'Installation of os type %s is not supported.' %
1477 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001478 return (build_url.split('static/')[-1],
1479 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001480
1481
1482 def list_files_glob(self, path_glob):
1483 """Get a list of files on the device given glob pattern path.
1484
1485 @param path_glob: The path glob that we want to return the list of
1486 files that match the glob. Relative paths will not work as
1487 expected. Supply an absolute path to get the list of files
1488 you're hoping for.
1489
1490 @returns List of files that match the path_glob.
1491 """
1492 # This is just in case path_glob has no path separator.
1493 base_path = os.path.dirname(path_glob) or '.'
1494 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001495 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001496 if result.exit_status != 0:
1497 return []
1498 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001499
1500
Dan Shida995002016-04-25 23:12:58 -07001501 def install_apk(self, apk, force_reinstall=True):
Kevin Cheng31355942016-01-05 14:23:35 -08001502 """Install the specified apk.
1503
1504 This will install the apk and override it if it's already installed and
1505 will also allow for downgraded apks.
1506
1507 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001508 @param force_reinstall: True to reinstall the apk even if it's already
Dan Shida995002016-04-25 23:12:58 -07001509 installed. Default is set to True.
Dan Shidb0366c2016-02-19 10:36:18 -08001510
1511 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001512 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001513 client_utils.poll_for_condition(
1514 lambda: self.run('pm list packages',
1515 ignore_status=True).exit_status == 0,
1516 timeout=120)
Dan Shi043c45b2016-04-11 17:18:49 -07001517 client_utils.poll_for_condition(
1518 lambda: self.run('service list | grep mount',
1519 ignore_status=True).exit_status == 0,
1520 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001521 return self.adb_run('install %s -d %s' %
1522 ('-r' if force_reinstall else '', apk))
1523
1524
1525 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1526 def _confirm_apk_installed(self, package_name):
1527 """Confirm if apk is already installed with the given name.
1528
1529 `pm list packages` command is not reliable some time. The retry helps to
1530 reduce the chance of false negative.
1531
1532 @param package_name: Name of the package, e.g., com.android.phone.
1533
1534 @raise AutoservRunError: If the package is not found or pm list command
1535 failed for any reason.
1536 """
1537 name = 'package:%s' % package_name
1538 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1539
1540
1541 def is_apk_installed(self, package_name):
1542 """Check if apk is already installed with the given name.
1543
1544 @param package_name: Name of the package, e.g., com.android.phone.
1545
1546 @return: True if package is installed. False otherwise.
1547 """
1548 try:
1549 self._confirm_apk_installed(package_name)
1550 return True
1551 except:
1552 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001553
1554
1555 def get_attributes_to_clear_before_provision(self):
1556 """Get a list of attributes to be cleared before machine_install starts.
1557 """
1558 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001559
1560
1561 def get_labels(self):
1562 """Return a list of the labels gathered from the devices connected.
1563
1564 @return: A list of strings that denote the labels from all the devices
1565 connected.
1566 """
1567 return self.labels.get_labels(self)
1568
1569
1570 def update_labels(self):
1571 """Update the labels for this testbed."""
1572 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001573
1574
1575 def stage_server_side_package(self, image=None):
1576 """Stage autotest server-side package on devserver.
1577
1578 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1579
1580 @return: A url to the autotest server-side package. Return None if
1581 server-side package is not supported.
1582 @raise: error.AutoservError if fail to locate the build to test with.
1583 """
1584 if image:
1585 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1586 else:
1587 job_repo_url = afe_utils.get_host_attribute(
1588 self, self.job_repo_url_attribute)
1589 if job_repo_url:
1590 devserver_url, image = (
1591 tools.get_devserver_build_from_package_url(
1592 job_repo_url, True))
1593 ds = dev_server.AndroidBuildServer(devserver_url)
1594 else:
1595 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1596 if not labels:
1597 raise error.AutoservError(
1598 'Failed to stage server-side package. The host has '
1599 'no job_report_url attribute or version label.')
1600 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1601 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1602
1603 branch, target, build_id = utils.parse_launch_control_build(image)
1604 build_target, _ = utils.parse_launch_control_target(target)
1605
1606 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1607 # packaging is not supported.
1608 try:
1609 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1610 logging.warn('Build %s is older than %s. Server side packaging '
1611 'is disabled.', image,
1612 self.MIN_VERSION_SUPPORT_SSP)
1613 return None
1614 except ValueError:
1615 logging.warn('Failed to compare build id in %s with the minimum '
1616 'version that supports server side packaging. Server '
1617 'side packaging is disabled.', image)
1618 return None
1619
1620 ds.stage_artifacts(target, build_id, branch,
1621 artifacts=['autotest_server_package'])
1622 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1623 {'build_target': build_target,
1624 'build_id': build_id})
1625 return '%s/static/%s/%s' % (ds.url(), image,
1626 autotest_server_package_name)
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -07001627
1628
1629 def _sync_time(self):
1630 """Approximate synchronization of time between host and ADB device.
1631
1632 This sets the ADB/Android device's clock to approximately the same
1633 time as the Autotest host for the purposes of comparing Android system
1634 logs such as logcat to logs from the Autotest host system.
1635 """
1636 command = 'date '
1637 sdk_version = int(self.run('getprop %s' % SDK_FILE).stdout)
1638 if sdk_version < 23:
1639 # Android L and earlier use this format: date -s (format).
1640 command += ('-s %s' %
1641 datetime.datetime.now().strftime('%Y%m%d.%H%M%S'))
1642 else:
1643 # Android M and later use this format: date (format).
1644 command += datetime.datetime.now().strftime('%m%d%H%M%Y.%S')
1645 self.run(command)