blob: 12a77a9f865c0f03a95efbfcdd52e1f0319dec0b [file] [log] [blame]
Simran Basi431010f2013-09-04 10:42:41 -07001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -07004import functools
Simran Basi431010f2013-09-04 10:42:41 -07005import logging
Kevin Cheng018db352015-09-20 02:22:08 -07006import os
Simran Basi431010f2013-09-04 10:42:41 -07007import re
Kevin Cheng92fe6ae2015-10-21 11:45:34 -07008import stat
Dan Shia2872172015-10-31 01:16:51 -07009import sys
Simran Basi431010f2013-09-04 10:42:41 -070010import time
11
12import common
13
Simran Basi9c5d3982016-04-01 18:49:44 -070014from autotest_lib.client.bin import utils as client_utils
Dan Shi49d451f2016-04-19 09:25:01 -070015from autotest_lib.client.common_lib import android_utils
Simran Basi431010f2013-09-04 10:42:41 -070016from autotest_lib.client.common_lib import error
Dan Shi6450e142016-03-11 11:52:20 -080017from autotest_lib.client.common_lib import global_config
Dan Shi225b9042015-11-18 10:25:21 -080018from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070019from autotest_lib.client.common_lib.cros import retry
Dan Shi6450e142016-03-11 11:52:20 -080020from autotest_lib.server import afe_utils
Dan Shi225b9042015-11-18 10:25:21 -080021from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070022from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080023from autotest_lib.server import utils
Simran Basi5ace6f22016-01-06 17:30:44 -080024from autotest_lib.server.cros import provision
Dan Shi6450e142016-03-11 11:52:20 -080025from autotest_lib.server.cros.dynamic_suite import tools
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070026from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070027from autotest_lib.server.hosts import abstract_ssh
Kevin Chengc6a645a2015-12-18 11:15:10 -080028from autotest_lib.server.hosts import adb_label
29from autotest_lib.server.hosts import base_label
Kevin Cheng85e864a2015-11-30 11:49:34 -080030from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070031
32
Dan Shi6450e142016-03-11 11:52:20 -080033CONFIG = global_config.global_config
34
Dan Shi6ea3e1c2015-10-28 15:19:04 -070035ADB_CMD = 'adb'
36FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070037SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070038# Some devices have no serial, then `adb serial` has output such as:
39# (no serial number) device
40# ?????????? device
41DEVICE_NO_SERIAL_MSG = '(no serial number)'
42DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070043# Regex to find an adb device. Examples:
44# 0146B5580B01801B device
45# 018e0ecb20c97a62 device
46# 172.22.75.141:5555 device
Kevin Cheng224415e2016-04-22 11:32:10 -070047# localhost:22 device
Alexandru Branciogea380fb2016-04-01 16:01:34 +030048DEVICE_FINDER_REGEX = (r'^(?P<SERIAL>([\w-]+)|((tcp:)?' +
49 '\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}([:]5555)?)|' +
Kevin Cheng224415e2016-04-22 11:32:10 -070050 '((tcp:)?localhost([:]22)?)|' +
Filipe Brandenburger34363392015-08-13 14:57:45 -070051 re.escape(DEVICE_NO_SERIAL_MSG) +
Alexandru Branciogea380fb2016-04-01 16:01:34 +030052 r')[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070053CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
54CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
55 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070056RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070057BOARD_FILE = 'ro.product.device'
Simran Basi38f7ddf2015-09-18 12:25:03 -070058TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070059# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080060# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070061FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
62FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
63# List of the perm stats indexed by the order they are listed in the example
64# supplied above.
65FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
66 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
67 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070068
Dan Shi6ea3e1c2015-10-28 15:19:04 -070069# Default maximum number of seconds to wait for a device to be down.
70DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
71# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080072DEFAULT_WAIT_UP_TIME_SECONDS = 300
73# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080074WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070075
Dan Shi7075f552016-04-21 15:42:41 -070076# Default timeout for retrying adb/fastboot command.
77DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS = 10
78
Dan Shia2872172015-10-31 01:16:51 -070079OS_TYPE_ANDROID = 'android'
80OS_TYPE_BRILLO = 'brillo'
81
Dan Shie234dea2016-01-20 17:15:17 -080082# Regex to parse build name to get the detailed build information.
Dan Shi6450e142016-03-11 11:52:20 -080083BUILD_REGEX = ('(?P<BRANCH>([^/]+))/(?P<BUILD_TARGET>([^/]+))-'
Dan Shie234dea2016-01-20 17:15:17 -080084 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))')
Dan Shia2872172015-10-31 01:16:51 -070085# Regex to parse devserver url to get the detailed build information. Sample
86# url: http://$devserver:8080/static/branch/target/build_id
Dan Shie234dea2016-01-20 17:15:17 -080087DEVSERVER_URL_REGEX = '.*/%s/*' % BUILD_REGEX
Dan Shia2872172015-10-31 01:16:51 -070088
Dan Shi6450e142016-03-11 11:52:20 -080089ANDROID_IMAGE_FILE_FMT = '%(build_target)s-img-%(build_id)s.zip'
Dan Shi49d451f2016-04-19 09:25:01 -070090
Dan Shiab999722015-12-04 14:27:08 -080091BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
Dan Shi6450e142016-03-11 11:52:20 -080092 '%(build_target)s-vendor_partitions-%(build_id)s.zip')
93AUTOTEST_SERVER_PACKAGE_FILE_FMT = (
94 '%(build_target)s-autotest_server_package-%(build_id)s.tar.bz2')
Simran Basi9228a6f2016-03-29 12:03:37 -070095ADB_DEVICE_PREFIXES = ['product:', 'model:', 'device:']
Dan Shia2872172015-10-31 01:16:51 -070096
Simran Basi9c5d3982016-04-01 18:49:44 -070097# Map of product names to build target name.
98PRODUCT_TARGET_MAP = {'dragon' : 'ryu',
99 'flo' : 'razor',
100 'flo_lte' : 'razorg',
101 'gm4g_sprout' : 'seed_l8150',
102 'flounder' : 'volantis',
103 'flounder_lte' : 'volantisg'}
104
Dan Shiab999722015-12-04 14:27:08 -0800105# Command to provision a Brillo device.
106# os_image_dir: The full path of the directory that contains all the Android image
107# files (from the image zip file).
108# vendor_partition_dir: The full path of the directory that contains all the
109# Brillo vendor partitions, and provision-device script.
110BRILLO_PROVISION_CMD = (
Simran Basi7e52c622016-01-05 15:43:51 -0800111 'sudo ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
Dan Shiab999722015-12-04 14:27:08 -0800112 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
113 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -0700114
115class AndroidInstallError(error.InstallError):
116 """Generic error for Android installation related exceptions."""
117
118
Simran Basi724b8a52013-09-30 11:19:31 -0700119class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700120 """This class represents a host running an ADB server."""
121
Simran Basi5ace6f22016-01-06 17:30:44 -0800122 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700123 _LABEL_FUNCTIONS = []
124 _DETECTABLE_LABELS = []
125 label_decorator = functools.partial(utils.add_label_detector,
126 _LABEL_FUNCTIONS,
127 _DETECTABLE_LABELS)
128
Dan Shi225b9042015-11-18 10:25:21 -0800129 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700130
Dan Shi6450e142016-03-11 11:52:20 -0800131 # Minimum build id that supports server side packaging. Older builds may
132 # not have server side package built or with Autotest code change to support
133 # server-side packaging.
134 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
135 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
136
beeps46dadc92013-11-07 14:07:10 -0800137 @staticmethod
138 def check_host(host, timeout=10):
139 """
140 Check if the given host is an adb host.
141
Simran Basi14622bb2015-11-25 13:23:40 -0800142 If SSH connectivity can't be established, check_host will try to use
143 user 'adb' as well. If SSH connectivity still can't be established
144 then the original SSH user is restored.
145
beeps46dadc92013-11-07 14:07:10 -0800146 @param host: An ssh host representing a device.
147 @param timeout: The timeout for the run command.
148
149
150 @return: True if the host device has adb.
151
152 @raises AutoservRunError: If the command failed.
153 @raises AutoservSSHTimeout: Ssh connection has timed out.
154 """
Dan Shi64e130f2015-12-16 14:45:44 -0800155 # host object may not have user attribute if it's a LocalHost object.
156 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800157 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800158 if not (host.hostname == 'localhost' or
159 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700160 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700161 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700162 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700163 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800164 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800165 if current_user is not None:
166 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800167 return False
168 return result.exit_status == 0
169
170
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700171 # TODO(garnold) Remove the 'serials' argument once all clients are made to
172 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700173 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700174 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700175 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700176 """Initialize an ADB Host.
177
178 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700179 test station connected to an Android DUT. This will be the DUT
180 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700181 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700182
183 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700184 @param serials: DEPRECATED (to be removed)
185 @param adb_serial: An ADB device serial. If None, assume a single
186 device is attached (and fail otherwise).
187 @param fastboot_serial: A fastboot device serial. If None, defaults to
188 the ADB serial (or assumes a single device if
189 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800190 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700191 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800192 # Sets up the is_client_install_supported field.
193 super(ADBHost, self)._initialize(hostname=hostname,
194 is_client_install_supported=False,
195 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800196
Kevin Chengd19e6c62015-10-28 16:39:39 -0700197 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800198 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi1bf60eb2015-12-01 16:39:29 -0800199 # TODO (sbasi/kevcheng): Once the teststation host is committed,
200 # refactor the serial retrieval.
201 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800202 self.adb_serial = adb_serial
Dan Shi3a011ed2016-04-26 12:26:53 -0700203 if adb_serial:
204 adb_prefix = any(adb_serial.startswith(p)
205 for p in ADB_DEVICE_PREFIXES)
206 self.fastboot_serial = (fastboot_serial or
207 ('tcp:%s' % adb_serial.split(':')[0] if
208 ':' in adb_serial and not adb_prefix else adb_serial))
209 self._use_tcpip = ':' in adb_serial and not adb_prefix
210 else:
211 self.fastboot_serial = fastboot_serial or adb_serial
212 self._use_tcpip = False
Kevin Cheng85e864a2015-11-30 11:49:34 -0800213 self.teststation = (teststation if teststation
214 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700215
216 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800217 if self.adb_serial:
218 msg += ', ADB serial: %s' % self.adb_serial
219 if self.fastboot_serial:
220 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700221 logging.debug(msg)
222
Simran Basibeb2bb22016-02-03 15:25:48 -0800223 # Try resetting the ADB daemon on the device, however if we are
224 # creating the host to do a repair job, the device maybe inaccesible
225 # via ADB.
226 try:
227 self._reset_adbd_connection()
228 except (error.AutotestHostRunError, error.AutoservRunError) as e:
229 logging.error('Unable to reset the device adb daemon connection: '
230 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800231 self._os_type = None
232
Simran Basi431010f2013-09-04 10:42:41 -0700233
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700234 def _connect_over_tcpip_as_needed(self):
235 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700236 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700237 return
238 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700239 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700240
241
Roshan Pius4d7540c2015-12-16 13:30:32 -0800242 def _restart_adbd_with_root_permissions(self):
243 """Restarts the adb daemon with root permissions."""
Dan Shi922de302016-04-22 15:19:18 -0700244 @retry.retry(error.AutoservRunError, timeout_min=20/60.0, delay_sec=1)
245 def run_adb_root():
246 """Run command `adb root`."""
247 self.adb_run('root')
248
249 # adb command may flake with error "device not found". Retry the root
250 # command to reduce the chance of flake.
251 run_adb_root()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800252 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
253 time.sleep(1)
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300254 self._connect_over_tcpip_as_needed()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800255 self.adb_run('wait-for-device')
256
257
Simran Basi9228a6f2016-03-29 12:03:37 -0700258 def _set_tcp_port(self):
259 """Ensure the device remains in tcp/ip mode after a reboot."""
260 if not self._use_tcpip:
261 return
262 port = self.adb_serial.split(':')[-1]
263 self.run('setprop persist.adb.tcp.port %s' % port)
264
265
Roshan Pius4d7540c2015-12-16 13:30:32 -0800266 def _reset_adbd_connection(self):
267 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800268 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700269 self._restart_adbd_with_root_permissions()
270 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800271
272
Kevin Cheng85e864a2015-11-30 11:49:34 -0800273 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800274 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700275 """Runs an adb command.
276
Kevin Chengd19e6c62015-10-28 16:39:39 -0700277 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700278
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700279 Refer to _device_run method for docstring for parameters.
280 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800281 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700282
283
Kevin Cheng85e864a2015-11-30 11:49:34 -0800284 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800285 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700286 """Runs an fastboot command.
287
Kevin Chengd19e6c62015-10-28 16:39:39 -0700288 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700289
290 Refer to _device_run method for docstring for parameters.
291 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800292 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700293
294
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700295 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700296 timeout=3600, ignore_status=False, ignore_timeout=False,
297 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
298 connect_timeout=30, options='', stdin=None, verbose=True,
299 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700300 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700301
Kevin Chengd19e6c62015-10-28 16:39:39 -0700302 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700303
Simran Basi431010f2013-09-04 10:42:41 -0700304 @param command: Command to run.
305 @param shell: If true the command runs in the adb shell otherwise if
306 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700307 reboot with shell=False will call 'adb reboot'. This
308 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700309 @param timeout: Time limit in seconds before attempting to
310 kill the running process. The run() function
311 will take a few seconds longer than 'timeout'
312 to complete if it has to kill the process.
313 @param ignore_status: Do not raise an exception, no matter
314 what the exit code of the command is.
315 @param ignore_timeout: Bool True if command timeouts should be
316 ignored. Will return None on command timeout.
317 @param stdout: Redirect stdout.
318 @param stderr: Redirect stderr.
319 @param connect_timeout: Connection timeout (in seconds)
320 @param options: String with additional ssh command options
321 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700322 @param require_sudo: True to require sudo to run the command. Default is
323 False.
Simran Basi431010f2013-09-04 10:42:41 -0700324 @param args: Sequence of strings to pass as arguments to command by
325 quoting them in " and escaping their contents if
326 necessary.
327
328 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700329 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700330 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800331 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700332 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800333 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700334 else:
335 raise NotImplementedError('Mode %s is not supported' % function)
336
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700337 if function != ADB_CMD and shell:
338 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700339
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700340 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700341
342 if serial:
343 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700344
Simran Basi431010f2013-09-04 10:42:41 -0700345 if shell:
346 cmd += '%s ' % SHELL_CMD
347 cmd += command
348
Roshan Pius58e5dd32015-10-16 15:16:42 -0700349 if verbose:
350 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700351
Kevin Cheng85e864a2015-11-30 11:49:34 -0800352 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400353 ignore_status=ignore_status,
354 ignore_timeout=ignore_timeout, stdout_tee=stdout,
355 stderr_tee=stderr, options=options, stdin=stdin,
356 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700357
358
Dan Shie234dea2016-01-20 17:15:17 -0800359 def get_board_name(self):
360 """Get the name of the board, e.g., shamu, dragonboard etc.
361 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700362 product = self.run_output('getprop %s' % BOARD_FILE)
363 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800364
365
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700366 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700367 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700368 """Determine the correct board label for the device.
369
370 @returns a string representing this device's board.
371 """
Dan Shie234dea2016-01-20 17:15:17 -0800372 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700373 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800374 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700375
376
Christopher Wiley08849d52013-11-22 08:57:58 -0800377 def job_start(self):
378 """
379 Disable log collection on adb_hosts.
380
381 TODO(sbasi): crbug.com/305427
Christopher Wiley08849d52013-11-22 08:57:58 -0800382 """
383
384
Simran Basi431010f2013-09-04 10:42:41 -0700385 def run(self, command, timeout=3600, ignore_status=False,
386 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
387 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700388 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700389 """Run a command on the adb device.
390
391 The command given will be ran directly on the adb device; for example
392 'ls' will be ran as: 'abd shell ls'
393
394 @param command: The command line string.
395 @param timeout: Time limit in seconds before attempting to
396 kill the running process. The run() function
397 will take a few seconds longer than 'timeout'
398 to complete if it has to kill the process.
399 @param ignore_status: Do not raise an exception, no matter
400 what the exit code of the command is.
401 @param ignore_timeout: Bool True if command timeouts should be
402 ignored. Will return None on command timeout.
403 @param stdout_tee: Redirect stdout.
404 @param stderr_tee: Redirect stderr.
405 @param connect_timeout: Connection timeout (in seconds).
406 @param options: String with additional ssh command options.
407 @param stdin: Stdin to pass (a string) to the executed command
408 @param args: Sequence of strings to pass as arguments to command by
409 quoting them in " and escaping their contents if
410 necessary.
411
412 @returns A CMDResult object or None if the call timed out and
413 ignore_timeout is True.
414
415 @raises AutoservRunError: If the command failed.
416 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700417 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700418 command = ('"%s; echo %s:\$?"' %
419 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700420 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700421 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700422 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
423 stdout=stdout_tee, stderr=stderr_tee,
424 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700425 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700426 if not result:
427 # In case of timeouts.
428 return None
429
430 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700431 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700432 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700433 'Failed to parse the exit code for command: %s' %
434 command, result)
435 elif parse_output:
436 result.stdout = parse_output.group('OUTPUT')
437 result.exit_status = int(parse_output.group('EXIT_CODE'))
438 if result.exit_status != 0 and not ignore_status:
439 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700440 return result
441
442
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700443 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
444 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700445
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700446 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700447
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700448 @param timeout: Time limit in seconds before returning even if the host
449 is not up.
450 @param command: The command used to test if a device is up, i.e.,
451 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700452
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700453 @returns True if the host was found to be up before the timeout expires,
454 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700455 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700456 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
457 delay_sec=1)
458 def _wait_up():
459 if not self.is_up(command=command):
460 raise error.TimeoutException('Device is still down.')
461 return True
462
463 try:
464 _wait_up()
465 logging.debug('Host %s is now up, and can be accessed by %s.',
466 self.hostname, command)
467 return True
468 except error.TimeoutException:
469 logging.debug('Host %s is still down after waiting %d seconds',
470 self.hostname, timeout)
471 return False
Simran Basi431010f2013-09-04 10:42:41 -0700472
473
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700474 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
475 warning_timer=None, old_boot_id=None, command=ADB_CMD):
476 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700477
478 Overrides wait_down from AbstractSSHHost.
479
480 @param timeout: Time in seconds to wait for the host to go down.
481 @param warning_timer: Time limit in seconds that will generate
482 a warning if the host is not down yet.
483 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700484 @param old_boot_id: Not applicable for adb_host.
485 @param command: `adb`, test if the device can be accessed by adb
486 command, or `fastboot`, test if the device can be accessed by
487 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700488
489 @returns True if the device goes down before the timeout, False
490 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700491 """
492 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
493 delay_sec=1)
494 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700495 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700496 raise error.TimeoutException('Device is still up.')
497 return True
498
499 try:
500 _wait_down()
501 logging.debug('Host %s is now down', self.hostname)
502 return True
503 except error.TimeoutException:
504 logging.debug('Host %s is still up after waiting %d seconds',
505 self.hostname, timeout)
506 return False
507
508
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700509 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700510 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700511
512 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700513 """
514 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700515 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700516 self.adb_run('reboot', timeout=10, ignore_timeout=True)
517 if not self.wait_down():
518 raise error.AutoservRebootError(
519 'ADB Device is still up after reboot')
520 if not self.wait_up():
521 raise error.AutoservRebootError(
522 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800523 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800524
525
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300526 def fastboot_reboot(self):
527 """Do a fastboot reboot to go back to adb.
528
529 @raises AutoservRebootError if reboot failed.
530 """
531 self.fastboot_run('reboot')
532 if not self.wait_down(command=FASTBOOT_CMD):
533 raise error.AutoservRebootError(
534 'Device is still in fastboot mode after reboot')
535 if not self.wait_up():
536 raise error.AutoservRebootError(
537 'Device failed to boot to adb after fastboot reboot.')
538 self._reset_adbd_connection()
539
540
Ralph Nathanb45eb672015-11-18 20:04:39 -0800541 def remount(self):
542 """Remounts paritions on the device read-write.
543
544 Specifically, the /system, /vendor (if present) and /oem (if present)
545 partitions on the device are remounted read-write.
546 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800547 self.adb_run('remount')
548
549
Kevin Cheng549beb42015-11-18 11:42:25 -0800550 @staticmethod
551 def parse_device_serials(devices_output):
552 """Return a list of parsed serials from the output.
553
554 @param devices_output: Output from either an adb or fastboot command.
555
556 @returns List of device serials
557 """
558 devices = []
559 for line in devices_output.splitlines():
560 match = re.search(DEVICE_FINDER_REGEX, line)
561 if match:
562 serial = match.group('SERIAL')
563 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
564 serial = DEVICE_NO_SERIAL_TAG
565 logging.debug('Found Device: %s', serial)
566 devices.append(serial)
567 return devices
568
569
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700570 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700571 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700572
573 @params use_adb: True to get adb accessible devices. Set to False to
574 get fastboot accessible devices.
575
Kevin Chengd19e6c62015-10-28 16:39:39 -0700576 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700577 """
578 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300579 result = self.adb_run('devices').stdout
580 if self.adb_serial and self.adb_serial not in result:
581 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700582 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300583 result = self.fastboot_run('devices').stdout
584 if (self.fastboot_serial and
585 self.fastboot_serial not in result):
586 # fastboot devices won't list the devices using TCP
587 try:
588 if 'product' in self.fastboot_run('getvar product',
589 timeout=2).stderr:
590 result += '\n%s\tfastboot' % self.fastboot_serial
Kevin Chengcfcb2cf2016-04-13 10:04:36 -0700591 # The main reason we do a general Exception catch here instead
592 # of setting ignore_timeout/status to True is because even when
593 # the fastboot process has been nuked, it still stays around and
594 # so bgjob wants to warn us of this and tries to read the
595 # /proc/<pid>/stack file which then promptly returns an
596 # 'Operation not permitted' error since we're running as moblab
597 # and we don't have permission to read those files.
598 except Exception:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300599 pass
600 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700601
602
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700603 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700604 """Get a list of devices currently attached to the test station and
605 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700606 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800607 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700608 raise error.AutoservError(
609 'Not given ADB serial but multiple devices detected')
610 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700611
612
613 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700614 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700615 accessible by fastboot command.
616 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700617 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800618 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700619 raise error.AutoservError(
620 'Not given fastboot serial but multiple devices detected')
621 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700622
623
624 def is_up(self, timeout=0, command=ADB_CMD):
625 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700626
627 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700628 @param command: `adb`, the device can be accessed by adb command,
629 or `fastboot`, the device can be accessed by fastboot command.
630 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700631
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700632 @returns True if the device is detectable by given command, False
633 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700634
635 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700636 if command == ADB_CMD:
637 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800638 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800639 # ADB has a device state, if the device is not online, no
640 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800641 # DUT with single device connected may not have adb_serial set.
642 # Therefore, skip checking if serial is in the list of adb devices
643 # if self.adb_serial is not set.
644 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800645 logging.debug('Waiting for device to enter the ready state.')
646 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700647 elif command == FASTBOOT_CMD:
648 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800649 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700650 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700651 raise NotImplementedError('Mode %s is not supported' % command)
652
653 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700654
655
656 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700657 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700658
659 Called as the test ends. Will return the device to USB mode and kill
660 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700661 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800662 # TODO(sbasi) Originally, we would kill the server after each test to
663 # reduce the opportunity for bad server state to hang around.
664 # Unfortunately, there is a period of time after each kill during which
665 # the Android device becomes unusable, and if we start the next test
666 # too quickly, we'll get an error complaining about no ADB device
667 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700668 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800669 # |close| the associated teststation as well.
670 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700671 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700672
673
674 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700675 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700676
677 @param message String message to log into syslog
678 @param tag String tag prefix for syslog
679
680 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700681 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700682
683
684 def get_autodir(self):
685 """Return the directory to install autotest for client side tests."""
686 return '/data/autotest'
687
Kevin Cheng018db352015-09-20 02:22:08 -0700688
Kris Rambishde8f9d12015-12-16 12:42:41 -0800689 def is_device_ready(self):
690 """Return the if the device is ready for ADB commands."""
Dan Shi7075f552016-04-21 15:42:41 -0700691 try:
692 # Retry to avoid possible flakes.
693 is_ready = client_utils.poll_for_condition(
694 lambda: self.adb_run('get-state').stdout.strip() == 'device',
695 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS, sleep_interval=1,
696 desc='Waiting for device state to be `device`')
697 except client_utils.TimeoutError:
698 is_ready = False
699
700 logging.debug('Device state is %sready', '' if is_ready else 'NOT ')
701 return is_ready
Kris Rambishde8f9d12015-12-16 12:42:41 -0800702
703
Kevin Chengd19e6c62015-10-28 16:39:39 -0700704 def verify_connectivity(self):
705 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800706 if not self.is_device_ready():
707 raise error.AutoservHostError('device state is not in the '
708 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700709
710
Simran Basid3ba3fb2015-09-11 14:35:07 -0700711 def verify_software(self):
712 """Verify working software on an adb_host.
713
Simran Basi38f7ddf2015-09-18 12:25:03 -0700714 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700715 """
Dan Shiab999722015-12-04 14:27:08 -0800716 # Check if adb and fastboot are present.
717 self.teststation.run('which adb')
718 self.teststation.run('which fastboot')
719 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700720
Kevin Cheng018db352015-09-20 02:22:08 -0700721
Simran Basid3ba3fb2015-09-11 14:35:07 -0700722 def verify_job_repo_url(self, tag=''):
723 """Make sure job_repo_url of this host is valid.
724
Simran Basi38f7ddf2015-09-18 12:25:03 -0700725 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700726
727 @param tag: The tag from the server job, in the format
728 <job_id>-<user>/<hostname>, or <hostless> for a server job.
729 """
730 return
Kevin Cheng018db352015-09-20 02:22:08 -0700731
732
Simran Basibeb2bb22016-02-03 15:25:48 -0800733 def repair(self):
734 """Attempt to get the DUT to pass `self.verify()`."""
735 try:
736 self.ensure_adb_mode(timeout=30)
737 return
738 except error.AutoservError as e:
739 logging.error(e)
740 logging.debug('Verifying the device is accessible via fastboot.')
741 self.ensure_bootloader_mode()
742 if not self.job.run_test(
743 'provision_AndroidUpdate', host=self, value=None,
744 force=True, repair=True):
745 raise error.AutoservRepairTotalFailure(
746 'Unable to repair the device.')
747
748
Simran Basi1b023762015-09-25 12:12:20 -0700749 def send_file(self, source, dest, delete_dest=False,
750 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700751 """Copy files from the drone to the device.
752
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400753 Just a note, there is the possibility the test station is localhost
754 which makes some of these steps redundant (e.g. creating tmp dir) but
755 that scenario will undoubtedly be a development scenario (test station
756 is also the moblab) and not the typical live test running scenario so
757 the redundancy I think is harmless.
758
Kevin Cheng018db352015-09-20 02:22:08 -0700759 @param source: The file/directory on the drone to send to the device.
760 @param dest: The destination path on the device to copy to.
761 @param delete_dest: A flag set to choose whether or not to delete
762 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700763 @param preserve_symlinks: Controls if symlinks on the source will be
764 copied as such on the destination or
765 transformed into the referenced
766 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700767 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700768 # If we need to preserve symlinks, let's check if the source is a
769 # symlink itself and if so, just create it on the device.
770 if preserve_symlinks:
771 symlink_target = None
772 try:
773 symlink_target = os.readlink(source)
774 except OSError:
775 # Guess it's not a symlink.
776 pass
777
778 if symlink_target is not None:
779 # Once we create the symlink, let's get out of here.
780 self.run('ln -s %s %s' % (symlink_target, dest))
781 return
782
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400783 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700784 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400785 src_path = os.path.join(tmp_dir, os.path.basename(dest))
786 # Now copy the file over to the test station so you can reference the
787 # file in the push command.
788 self.teststation.send_file(source, src_path,
789 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700790
791 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400792 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700793
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700794 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700795
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400796 # Cleanup the test station.
797 try:
798 self.teststation.run('rm -rf %s' % tmp_dir)
799 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
800 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700801
802
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700803 def _get_file_info(self, dest):
804 """Get permission and possible symlink info about file on the device.
805
806 These files are on the device so we only have shell commands (via adb)
807 to get the info we want. We'll use 'ls' to get it all.
808
809 @param dest: File to get info about.
810
811 @returns a dict of the file permissions and symlink.
812 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800813 # Grab file info.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700814 file_info = self.run_output('ls -ld %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700815 symlink = None
816 perms = 0
817 match = re.match(FILE_INFO_REGEX, file_info)
818 if match:
819 # Check if it's a symlink and grab the linked dest if it is.
820 if match.group('TYPE') == 'l':
821 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
822 if symlink_match:
823 symlink = symlink_match.group('SYMLINK')
824
825 # Set the perms.
826 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
827 if perm != '-':
828 perms |= perm_flag
829
830 return {'perms': perms,
831 'symlink': symlink}
832
833
Simran Basi1b023762015-09-25 12:12:20 -0700834 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
835 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700836 """Copy files from the device to the drone.
837
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400838 Just a note, there is the possibility the test station is localhost
839 which makes some of these steps redundant (e.g. creating tmp dir) but
840 that scenario will undoubtedly be a development scenario (test station
841 is also the moblab) and not the typical live test running scenario so
842 the redundancy I think is harmless.
843
Kevin Cheng018db352015-09-20 02:22:08 -0700844 @param source: The file/directory on the device to copy back to the
845 drone.
846 @param dest: The destination path on the drone to copy to.
847 @param delete_dest: A flag set to choose whether or not to delete
848 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700849 @param preserve_perm: Tells get_file() to try to preserve the sources
850 permissions on files and dirs.
851 @param preserve_symlinks: Try to preserve symlinks instead of
852 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700853 """
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400854 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700855 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400856 dest_path = os.path.join(tmp_dir, os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700857
858 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400859 self.teststation.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700860
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700861 source_info = {}
862 if preserve_symlinks or preserve_perm:
863 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700864
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700865 # If we want to preserve symlinks, just create it here, otherwise pull
866 # the file off the device.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700867 #
868 # TODO(sadmac): Directories containing symlinks won't behave as
869 # expected.
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700870 if preserve_symlinks and source_info['symlink']:
871 os.symlink(source_info['symlink'], dest)
872 else:
Roshan Pius95567142015-11-03 09:56:08 -0800873 self.adb_run('pull %s %s' % (source, dest_path))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700874
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400875 # Copy over the file from the test station and clean up.
876 self.teststation.get_file(dest_path, dest)
877 try:
878 self.teststation.run('rm -rf %s' % tmp_dir)
879 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
880 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700881
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700882 for root, dirs, files in os.walk(dest):
883 rel_root = os.path.relpath(root, dest)
884
885 def process(item, default_perm):
886 info = self._get_file_info(os.path.join(source, rel_root, item))
887
888 if info['perms'] != 0:
889 target = os.path.join(root, item)
890 if preserve_perm:
891 os.chmod(target, info['perms'])
892 else:
893 os.chmod(target, default_perm)
894
895 for f in files:
896 process(f, 0o600)
897
898 for d in dirs:
899 process(f, 0o700)
900
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700901 if preserve_perm:
902 os.chmod(dest, source_info['perms'])
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700903 elif os.path.isdir(dest):
904 os.chmod(dest, 0o700)
905 else:
906 os.chmod(dest, 0o600)
Kevin Cheng018db352015-09-20 02:22:08 -0700907
908
909 def get_release_version(self):
910 """Get the release version from the RELEASE_FILE on the device.
911
912 @returns The release string in the RELEASE_FILE.
913
914 """
915 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700916
917
918 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700919 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700920
Kevin Chengd19e6c62015-10-28 16:39:39 -0700921 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700922
923 @param parent: Parent directory of the returned tmp dir.
924
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700925 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700926 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700927 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
928 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700929 if not parent.startswith(TMP_DIR):
930 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700931 self.run('mkdir -p %s' % parent)
932 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
933 self.tmp_dirs.append(tmp_dir)
934 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700935
936
937 def get_platform(self):
938 """Determine the correct platform label for this host.
939
940 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700941 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700942
943 @returns a string representing this host's platform.
944 """
945 return 'adb'
946
947
Gilad Arnolda76bef02015-09-29 13:55:15 -0700948 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800949 """Get the OS type of the DUT, e.g., android or brillo.
950 """
951 if not self._os_type:
952 if self.run_output('getprop ro.product.brand') == 'Brillo':
953 self._os_type = OS_TYPE_BRILLO
954 else:
955 self._os_type = OS_TYPE_ANDROID
956
957 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700958
959
960 def _forward(self, reverse, args):
961 """Execute a forwarding command.
962
963 @param reverse: Whether this is reverse forwarding (Boolean).
964 @param args: List of command arguments.
965 """
966 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700967 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700968
969
970 def add_forwarding(self, src, dst, reverse=False, rebind=True):
971 """Forward a port between the ADB host and device.
972
973 Port specifications are any strings accepted as such by ADB, for
974 example 'tcp:8080'.
975
976 @param src: Port specification to forward from.
977 @param dst: Port specification to forward to.
978 @param reverse: Do reverse forwarding from device to host (Boolean).
979 @param rebind: Allow rebinding an already bound port (Boolean).
980 """
981 args = []
982 if not rebind:
983 args.append('--no-rebind')
984 args += [src, dst]
985 self._forward(reverse, args)
986
987
988 def remove_forwarding(self, src=None, reverse=False):
989 """Removes forwarding on port.
990
991 @param src: Port specification, or None to remove all forwarding.
992 @param reverse: Whether this is reverse forwarding (Boolean).
993 """
994 args = []
995 if src is None:
996 args.append('--remove-all')
997 else:
998 args += ['--remove', src]
999 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001000
1001
xixuan6cf6d2f2016-01-29 15:29:00 -08001002 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001003 """
1004 Forwards a port securely through a tunnel process from the server
1005 to the DUT for RPC server connection.
1006 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
1007 to the DUT.
1008
1009 @param port: remote port on the DUT.
1010 @param local_port: local forwarding port.
1011
1012 @return: the tunnel process.
1013 """
1014 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001015 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001016
1017
xixuan6cf6d2f2016-01-29 15:29:00 -08001018 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001019 """
1020 Disconnects a previously forwarded port from the server to the DUT for
1021 RPC server connection.
1022 Remove the previously added 'ADB forward' rule to forward the RPC
1023 packets from the AdbHost to the DUT.
1024
1025 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -08001026 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -07001027 @param port: remote port on the DUT.
1028
1029 """
1030 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001031 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001032
1033
1034 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001035 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001036
1037 @raise: error.AutoservError if the device failed to reboot into
1038 bootloader mode.
1039 """
1040 if self.is_up(command=FASTBOOT_CMD):
1041 return
1042 self.adb_run('reboot bootloader')
1043 if not self.wait_up(command=FASTBOOT_CMD):
1044 raise error.AutoservError(
1045 'The device failed to reboot into bootloader mode.')
1046
1047
Dan Shie4e807b2015-12-10 09:04:03 -08001048 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001049 """Ensure the device is up and can be accessed by adb command.
1050
Dan Shie4e807b2015-12-10 09:04:03 -08001051 @param timeout: Time limit in seconds before returning even if the host
1052 is not up.
1053
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001054 @raise: error.AutoservError if the device failed to reboot into
1055 adb mode.
1056 """
1057 if self.is_up():
1058 return
Dan Shi04980372016-03-22 10:57:47 -07001059 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1060 # check if the device is in adb mode.
1061 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001062 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001063 raise error.AutoservError(
1064 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001065 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001066
1067
1068 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001069 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001070 """Get the Android build information from the build url.
1071
1072 @param build_url: The url to use for downloading Android artifacts.
1073 pattern: http://$devserver:###/static/branch/target/build_id
1074
Dan Shi6450e142016-03-11 11:52:20 -08001075 @return: A dictionary of build information, including keys:
1076 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001077 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001078 """
Dan Shiab999722015-12-04 14:27:08 -08001079 if not build_url:
1080 raise AndroidInstallError('Need build_url to download image files.')
1081
1082 try:
1083 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001084 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001085 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001086 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001087 match.group('BUILD_TYPE'))),
1088 'build_id': match.group('BUILD_ID')}
1089 except (AttributeError, IndexError, ValueError) as e:
1090 raise AndroidInstallError(
1091 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001092
1093
Dan Shia2872172015-10-31 01:16:51 -07001094 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001095 def download_file(self, build_url, file, dest_dir, unzip=False,
1096 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001097 """Download the given file from the build url.
1098
1099 @param build_url: The url to use for downloading Android artifacts.
1100 pattern: http://$devserver:###/static/branch/target/build_id
1101 @param file: Name of the file to be downloaded, e.g., boot.img.
1102 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001103 @param unzip: If True, unzip the downloaded file.
1104 @param unzip_dest: Location to unzip the downloaded file to. If not
1105 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001106 """
Dan Shidb0366c2016-02-19 10:36:18 -08001107 # Append the file name to the url if build_url is linked to the folder
1108 # containing the file.
1109 if not build_url.endswith('/%s' % file):
1110 src_url = os.path.join(build_url, file)
1111 else:
1112 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001113 dest_file = os.path.join(dest_dir, file)
1114 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001115 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001116 if unzip:
1117 unzip_dest = unzip_dest or dest_dir
1118 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1119 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001120 except:
1121 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001122 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001123 raise
1124
1125
Dan Shiab999722015-12-04 14:27:08 -08001126 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001127 """Download required image files from the given build_url to a local
1128 directory in the machine runs fastboot command.
1129
1130 @param build_url: The url to use for downloading Android artifacts.
1131 pattern: http://$devserver:###/static/branch/target/build_id
1132
1133 @return: Path to the directory contains image files.
1134 """
Dan Shi08ff1282016-02-18 19:51:16 -08001135 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001136
1137 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001138 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001139
1140 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001141 self.download_file(build_url, zipped_image_file, image_dir,
1142 unzip=True)
Dan Shi49d451f2016-04-19 09:25:01 -07001143 images = android_utils.AndroidImageFiles.get_standalone_images(
1144 build_info['build_target'])
1145 for image_file in images:
Dan Shidb0366c2016-02-19 10:36:18 -08001146 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001147
Dan Shia2872172015-10-31 01:16:51 -07001148 return image_dir
1149 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001150 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001151 raise
1152
1153
Dan Shiab999722015-12-04 14:27:08 -08001154 def stage_brillo_image_files(self, build_url):
1155 """Download required brillo image files from the given build_url to a
1156 local directory in the machine runs fastboot command.
1157
1158 @param build_url: The url to use for downloading Android artifacts.
1159 pattern: http://$devserver:###/static/branch/target/build_id
1160
1161 @return: Path to the directory contains image files.
1162 """
Dan Shi08ff1282016-02-18 19:51:16 -08001163 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001164
1165 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1166 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1167 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001168
1169 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001170 self.download_file(build_url, zipped_image_file, image_dir,
1171 unzip=True)
1172 self.download_file(build_url, vendor_partitions_file, image_dir,
1173 unzip=True,
1174 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001175 return image_dir
1176 except:
1177 self.teststation.run('rm -rf %s' % image_dir)
1178 raise
1179
1180
Simran Basibeb2bb22016-02-03 15:25:48 -08001181 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001182 """Stage a build on a devserver and return the build_url and devserver.
1183
1184 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001185
Dan Shi225b9042015-11-18 10:25:21 -08001186 @returns a tuple with an update URL like:
1187 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1188 and the devserver instance.
1189 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001190 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001191 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001192 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1193 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001194 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001195 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001196 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001197 devserver.trigger_download(target, build_id, branch,
1198 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001199 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001200
1201
Dan Shie4e807b2015-12-10 09:04:03 -08001202 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001203 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001204 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001205
1206 Following are the steps used here to provision an android device:
1207 1. If build_local_path is not set, download the image zip file, e.g.,
1208 shamu-img-2284311.zip, unzip it.
1209 2. Run fastboot to install following artifacts:
1210 bootloader, radio, boot, system, vendor(only if exists)
1211
1212 Repair is not supported for Android devices yet.
1213
1214 @param build_url: The url to use for downloading Android artifacts.
1215 pattern: http://$devserver:###/static/$build
1216 @param build_local_path: The path to a local folder that contains the
1217 image files needed to provision the device. Note that the folder
1218 is in the machine running adb command, rather than the drone.
1219 @param wipe: If true, userdata will be wiped before flashing.
1220 @param flash_all: If True, all img files found in img_path will be
1221 flashed. Otherwise, only boot and system are flashed.
1222
1223 @raises AndroidInstallError if any error occurs.
1224 """
Dan Shia2872172015-10-31 01:16:51 -07001225 # If the build is not staged in local server yet, clean up the temp
1226 # folder used to store image files after the provision is completed.
1227 delete_build_folder = bool(not build_local_path)
1228
1229 try:
1230 # Download image files needed for provision to a local directory.
1231 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001232 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001233
1234 # Device needs to be in bootloader mode for flashing.
1235 self.ensure_bootloader_mode()
1236
1237 if wipe:
Dan Shie4e807b2015-12-10 09:04:03 -08001238 self.fastboot_run('-w')
Dan Shia2872172015-10-31 01:16:51 -07001239
1240 # Get all *.img file in the build_local_path.
1241 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001242 image_files = self.teststation.run(
1243 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001244 images = dict([(os.path.basename(f), f) for f in image_files])
Dan Shi49d451f2016-04-19 09:25:01 -07001245 build_info = self.get_build_info_from_build_url(build_url)
1246 board = build_info['build_target']
1247 all_images = (
1248 android_utils.AndroidImageFiles.get_standalone_images(board)
1249 + android_utils.AndroidImageFiles.get_zipped_images(board))
1250
1251 # Sort images to be flashed, bootloader needs to be the first one.
1252 bootloader = android_utils.AndroidImageFiles.BOOTLOADER
1253 sorted_images = sorted(
1254 images.items(),
1255 key=lambda pair: 0 if pair[0] == bootloader else 1)
1256 for image, image_file in sorted_images:
1257 if image not in all_images:
Dan Shia2872172015-10-31 01:16:51 -07001258 continue
1259 logging.info('Flashing %s...', image_file)
Dan Shi70c30192016-03-22 23:14:12 -07001260 self.fastboot_run('-S 256M flash %s %s' %
Dan Shie9913d32016-03-09 14:17:26 -08001261 (image[:-4], image_file))
Dan Shi49d451f2016-04-19 09:25:01 -07001262 if image == android_utils.AndroidImageFiles.BOOTLOADER:
Dan Shia2872172015-10-31 01:16:51 -07001263 self.fastboot_run('reboot-bootloader')
1264 self.wait_up(command=FASTBOOT_CMD)
1265 except Exception as e:
1266 logging.error('Install Android build failed with error: %s', e)
1267 # Re-raise the exception with type of AndroidInstallError.
1268 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1269 finally:
1270 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001271 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001272 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1273 DEFAULT_WAIT_UP_TIME_SECONDS)
1274 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001275 logging.info('Successfully installed Android build staged at %s.',
1276 build_url)
1277
1278
Dan Shiab999722015-12-04 14:27:08 -08001279 def install_brillo(self, build_url, build_local_path=None):
1280 """Install the Brillo DUT.
1281
1282 Following are the steps used here to provision an android device:
1283 1. If build_local_path is not set, download the image zip file, e.g.,
1284 dragonboard-img-123456.zip, unzip it. And download the vendor
1285 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1286 unzip it to vendor folder.
1287 2. Run provision_device script to install OS images and vendor
1288 partitions.
1289
1290 @param build_url: The url to use for downloading Android artifacts.
1291 pattern: http://$devserver:###/static/$build
1292 @param build_local_path: The path to a local folder that contains the
1293 image files needed to provision the device. Note that the folder
1294 is in the machine running adb command, rather than the drone.
1295
1296 @raises AndroidInstallError if any error occurs.
1297 """
1298 # If the build is not staged in local server yet, clean up the temp
1299 # folder used to store image files after the provision is completed.
1300 delete_build_folder = bool(not build_local_path)
1301
Dan Shiab999722015-12-04 14:27:08 -08001302 try:
1303 # Download image files needed for provision to a local directory.
1304 if not build_local_path:
1305 build_local_path = self.stage_brillo_image_files(build_url)
1306
1307 # Device needs to be in bootloader mode for flashing.
1308 self.ensure_bootloader_mode()
1309
1310 # Run provision_device command to install image files and vendor
1311 # partitions.
1312 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1313 cmd = (BRILLO_PROVISION_CMD %
1314 {'os_image_dir': build_local_path,
1315 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001316 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001317 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001318 self.teststation.run(cmd)
1319 except Exception as e:
1320 logging.error('Install Brillo build failed with error: %s', e)
1321 # Re-raise the exception with type of AndroidInstallError.
1322 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1323 finally:
1324 if delete_build_folder:
1325 self.teststation.run('rm -rf %s' % build_local_path)
1326 self.ensure_adb_mode()
1327 logging.info('Successfully installed Android build staged at %s.',
1328 build_url)
1329
1330
Dan Shibe3636a2016-02-14 22:48:01 -08001331 @property
1332 def job_repo_url_attribute(self):
1333 """Get the host attribute name for job_repo_url, which should append the
1334 adb serial.
1335 """
1336 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1337
1338
Dan Shie4e807b2015-12-10 09:04:03 -08001339 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001340 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001341 """Install the DUT.
1342
1343 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001344 pattern: http://$devserver:###/static/$build. If build_url is
1345 set to None, the code may try _parser.options.image to do the
1346 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001347 @param build_local_path: The path to a local directory that contains the
1348 image files needed to provision the device.
1349 @param wipe: If true, userdata will be wiped before flashing.
1350 @param flash_all: If True, all img files found in img_path will be
1351 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001352
Dan Shibe3636a2016-02-14 22:48:01 -08001353 @returns A tuple of (image_name, host_attributes).
1354 image_name is the name of image installed, e.g.,
1355 git_mnc-release/shamu-userdebug/1234
1356 host_attributes is a dictionary of (attribute, value), which
1357 can be saved to afe_host_attributes table in database. This
1358 method returns a dictionary with a single entry of
1359 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1360 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001361 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001362 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001363 if not build_url and self._parser.options.image:
1364 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001365 self._parser.options.image, os_type=os_type)
1366 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001367 self.install_android(
1368 build_url=build_url, build_local_path=build_local_path,
1369 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001370 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001371 self.install_brillo(
1372 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001373 else:
1374 raise error.InstallError(
1375 'Installation of os type %s is not supported.' %
1376 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001377 return (build_url.split('static/')[-1],
1378 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001379
1380
1381 def list_files_glob(self, path_glob):
1382 """Get a list of files on the device given glob pattern path.
1383
1384 @param path_glob: The path glob that we want to return the list of
1385 files that match the glob. Relative paths will not work as
1386 expected. Supply an absolute path to get the list of files
1387 you're hoping for.
1388
1389 @returns List of files that match the path_glob.
1390 """
1391 # This is just in case path_glob has no path separator.
1392 base_path = os.path.dirname(path_glob) or '.'
1393 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001394 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001395 if result.exit_status != 0:
1396 return []
1397 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001398
1399
Dan Shida995002016-04-25 23:12:58 -07001400 def install_apk(self, apk, force_reinstall=True):
Kevin Cheng31355942016-01-05 14:23:35 -08001401 """Install the specified apk.
1402
1403 This will install the apk and override it if it's already installed and
1404 will also allow for downgraded apks.
1405
1406 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001407 @param force_reinstall: True to reinstall the apk even if it's already
Dan Shida995002016-04-25 23:12:58 -07001408 installed. Default is set to True.
Dan Shidb0366c2016-02-19 10:36:18 -08001409
1410 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001411 """
Simran Basi9c5d3982016-04-01 18:49:44 -07001412 client_utils.poll_for_condition(
1413 lambda: self.run('pm list packages',
1414 ignore_status=True).exit_status == 0,
1415 timeout=120)
Dan Shi043c45b2016-04-11 17:18:49 -07001416 client_utils.poll_for_condition(
1417 lambda: self.run('service list | grep mount',
1418 ignore_status=True).exit_status == 0,
1419 timeout=120)
Dan Shidb0366c2016-02-19 10:36:18 -08001420 return self.adb_run('install %s -d %s' %
1421 ('-r' if force_reinstall else '', apk))
1422
1423
1424 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1425 def _confirm_apk_installed(self, package_name):
1426 """Confirm if apk is already installed with the given name.
1427
1428 `pm list packages` command is not reliable some time. The retry helps to
1429 reduce the chance of false negative.
1430
1431 @param package_name: Name of the package, e.g., com.android.phone.
1432
1433 @raise AutoservRunError: If the package is not found or pm list command
1434 failed for any reason.
1435 """
1436 name = 'package:%s' % package_name
1437 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1438
1439
1440 def is_apk_installed(self, package_name):
1441 """Check if apk is already installed with the given name.
1442
1443 @param package_name: Name of the package, e.g., com.android.phone.
1444
1445 @return: True if package is installed. False otherwise.
1446 """
1447 try:
1448 self._confirm_apk_installed(package_name)
1449 return True
1450 except:
1451 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001452
1453
1454 def get_attributes_to_clear_before_provision(self):
1455 """Get a list of attributes to be cleared before machine_install starts.
1456 """
1457 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001458
1459
1460 def get_labels(self):
1461 """Return a list of the labels gathered from the devices connected.
1462
1463 @return: A list of strings that denote the labels from all the devices
1464 connected.
1465 """
1466 return self.labels.get_labels(self)
1467
1468
1469 def update_labels(self):
1470 """Update the labels for this testbed."""
1471 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001472
1473
1474 def stage_server_side_package(self, image=None):
1475 """Stage autotest server-side package on devserver.
1476
1477 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1478
1479 @return: A url to the autotest server-side package. Return None if
1480 server-side package is not supported.
1481 @raise: error.AutoservError if fail to locate the build to test with.
1482 """
1483 if image:
1484 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1485 else:
1486 job_repo_url = afe_utils.get_host_attribute(
1487 self, self.job_repo_url_attribute)
1488 if job_repo_url:
1489 devserver_url, image = (
1490 tools.get_devserver_build_from_package_url(
1491 job_repo_url, True))
1492 ds = dev_server.AndroidBuildServer(devserver_url)
1493 else:
1494 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1495 if not labels:
1496 raise error.AutoservError(
1497 'Failed to stage server-side package. The host has '
1498 'no job_report_url attribute or version label.')
1499 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1500 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1501
1502 branch, target, build_id = utils.parse_launch_control_build(image)
1503 build_target, _ = utils.parse_launch_control_target(target)
1504
1505 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1506 # packaging is not supported.
1507 try:
1508 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1509 logging.warn('Build %s is older than %s. Server side packaging '
1510 'is disabled.', image,
1511 self.MIN_VERSION_SUPPORT_SSP)
1512 return None
1513 except ValueError:
1514 logging.warn('Failed to compare build id in %s with the minimum '
1515 'version that supports server side packaging. Server '
1516 'side packaging is disabled.', image)
1517 return None
1518
1519 ds.stage_artifacts(target, build_id, branch,
1520 artifacts=['autotest_server_package'])
1521 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1522 {'build_target': build_target,
1523 'build_id': build_id})
1524 return '%s/static/%s/%s' % (ds.url(), image,
1525 autotest_server_package_name)