blob: 52a6a509376f7f8ebe5d9849b35b4a88d14dd59e [file] [log] [blame]
Simran Basi431010f2013-09-04 10:42:41 -07001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -07004import functools
Simran Basi431010f2013-09-04 10:42:41 -07005import logging
Kevin Cheng018db352015-09-20 02:22:08 -07006import os
Simran Basi431010f2013-09-04 10:42:41 -07007import re
Kevin Cheng92fe6ae2015-10-21 11:45:34 -07008import stat
Dan Shia2872172015-10-31 01:16:51 -07009import sys
Simran Basi431010f2013-09-04 10:42:41 -070010import time
11
12import common
13
14from autotest_lib.client.common_lib import error
Dan Shi6450e142016-03-11 11:52:20 -080015from autotest_lib.client.common_lib import global_config
Dan Shi225b9042015-11-18 10:25:21 -080016from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070017from autotest_lib.client.common_lib.cros import retry
Dan Shi6450e142016-03-11 11:52:20 -080018from autotest_lib.server import afe_utils
Dan Shi225b9042015-11-18 10:25:21 -080019from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070020from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080021from autotest_lib.server import utils
Simran Basi5ace6f22016-01-06 17:30:44 -080022from autotest_lib.server.cros import provision
Dan Shi6450e142016-03-11 11:52:20 -080023from autotest_lib.server.cros.dynamic_suite import tools
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070024from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070025from autotest_lib.server.hosts import abstract_ssh
Kevin Chengc6a645a2015-12-18 11:15:10 -080026from autotest_lib.server.hosts import adb_label
27from autotest_lib.server.hosts import base_label
Kevin Cheng85e864a2015-11-30 11:49:34 -080028from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070029
30
Dan Shi6450e142016-03-11 11:52:20 -080031CONFIG = global_config.global_config
32
Dan Shi6ea3e1c2015-10-28 15:19:04 -070033ADB_CMD = 'adb'
34FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070035SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070036# Some devices have no serial, then `adb serial` has output such as:
37# (no serial number) device
38# ?????????? device
39DEVICE_NO_SERIAL_MSG = '(no serial number)'
40DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070041# Regex to find an adb device. Examples:
42# 0146B5580B01801B device
43# 018e0ecb20c97a62 device
44# 172.22.75.141:5555 device
Mike Frysinger5d7a7092016-02-23 15:14:42 -050045DEVICE_FINDER_REGEX = (r'^(?P<SERIAL>([\w-]+)|(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})|' +
Filipe Brandenburger34363392015-08-13 14:57:45 -070046 re.escape(DEVICE_NO_SERIAL_MSG) +
Mike Frysinger5d7a7092016-02-23 15:14:42 -050047 r')([:]5555)?[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070048CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
49CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
50 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070051RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070052BOARD_FILE = 'ro.product.device'
Simran Basi38f7ddf2015-09-18 12:25:03 -070053TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070054# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080055# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070056FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
57FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
58# List of the perm stats indexed by the order they are listed in the example
59# supplied above.
60FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
61 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
62 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070063
Dan Shi6ea3e1c2015-10-28 15:19:04 -070064# Default maximum number of seconds to wait for a device to be down.
65DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
66# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080067DEFAULT_WAIT_UP_TIME_SECONDS = 300
68# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080069WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070070
Dan Shia2872172015-10-31 01:16:51 -070071OS_TYPE_ANDROID = 'android'
72OS_TYPE_BRILLO = 'brillo'
73
Dan Shie234dea2016-01-20 17:15:17 -080074# Regex to parse build name to get the detailed build information.
Dan Shi6450e142016-03-11 11:52:20 -080075BUILD_REGEX = ('(?P<BRANCH>([^/]+))/(?P<BUILD_TARGET>([^/]+))-'
Dan Shie234dea2016-01-20 17:15:17 -080076 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))')
Dan Shia2872172015-10-31 01:16:51 -070077# Regex to parse devserver url to get the detailed build information. Sample
78# url: http://$devserver:8080/static/branch/target/build_id
Dan Shie234dea2016-01-20 17:15:17 -080079DEVSERVER_URL_REGEX = '.*/%s/*' % BUILD_REGEX
Dan Shia2872172015-10-31 01:16:51 -070080
Dan Shi6450e142016-03-11 11:52:20 -080081ANDROID_IMAGE_FILE_FMT = '%(build_target)s-img-%(build_id)s.zip'
Dan Shia2872172015-10-31 01:16:51 -070082ANDROID_BOOTLOADER = 'bootloader.img'
83ANDROID_RADIO = 'radio.img'
84ANDROID_BOOT = 'boot.img'
85ANDROID_SYSTEM = 'system.img'
86ANDROID_VENDOR = 'vendor.img'
Dan Shiab999722015-12-04 14:27:08 -080087BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
Dan Shi6450e142016-03-11 11:52:20 -080088 '%(build_target)s-vendor_partitions-%(build_id)s.zip')
89AUTOTEST_SERVER_PACKAGE_FILE_FMT = (
90 '%(build_target)s-autotest_server_package-%(build_id)s.tar.bz2')
Simran Basi9228a6f2016-03-29 12:03:37 -070091ADB_DEVICE_PREFIXES = ['product:', 'model:', 'device:']
Dan Shia2872172015-10-31 01:16:51 -070092
93# Image files not inside the image zip file. These files should be downloaded
94# directly from devserver.
95ANDROID_STANDALONE_IMAGES = [ANDROID_BOOTLOADER, ANDROID_RADIO]
96# Image files that are packaged in a zip file, e.g., shamu-img-123456.zip
97ANDROID_ZIPPED_IMAGES = [ANDROID_BOOT, ANDROID_SYSTEM, ANDROID_VENDOR]
98# All image files to be flashed to an Android device.
99ANDROID_IMAGES = ANDROID_STANDALONE_IMAGES + ANDROID_ZIPPED_IMAGES
100
Dan Shiab999722015-12-04 14:27:08 -0800101# Command to provision a Brillo device.
102# os_image_dir: The full path of the directory that contains all the Android image
103# files (from the image zip file).
104# vendor_partition_dir: The full path of the directory that contains all the
105# Brillo vendor partitions, and provision-device script.
106BRILLO_PROVISION_CMD = (
Simran Basi7e52c622016-01-05 15:43:51 -0800107 'sudo ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
Dan Shiab999722015-12-04 14:27:08 -0800108 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
109 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -0700110
111class AndroidInstallError(error.InstallError):
112 """Generic error for Android installation related exceptions."""
113
114
Simran Basi724b8a52013-09-30 11:19:31 -0700115class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700116 """This class represents a host running an ADB server."""
117
Simran Basi5ace6f22016-01-06 17:30:44 -0800118 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700119 _LABEL_FUNCTIONS = []
120 _DETECTABLE_LABELS = []
121 label_decorator = functools.partial(utils.add_label_detector,
122 _LABEL_FUNCTIONS,
123 _DETECTABLE_LABELS)
124
Dan Shi225b9042015-11-18 10:25:21 -0800125 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700126
Dan Shi6450e142016-03-11 11:52:20 -0800127 # Minimum build id that supports server side packaging. Older builds may
128 # not have server side package built or with Autotest code change to support
129 # server-side packaging.
130 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
131 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
132
beeps46dadc92013-11-07 14:07:10 -0800133 @staticmethod
134 def check_host(host, timeout=10):
135 """
136 Check if the given host is an adb host.
137
Simran Basi14622bb2015-11-25 13:23:40 -0800138 If SSH connectivity can't be established, check_host will try to use
139 user 'adb' as well. If SSH connectivity still can't be established
140 then the original SSH user is restored.
141
beeps46dadc92013-11-07 14:07:10 -0800142 @param host: An ssh host representing a device.
143 @param timeout: The timeout for the run command.
144
145
146 @return: True if the host device has adb.
147
148 @raises AutoservRunError: If the command failed.
149 @raises AutoservSSHTimeout: Ssh connection has timed out.
150 """
Dan Shi64e130f2015-12-16 14:45:44 -0800151 # host object may not have user attribute if it's a LocalHost object.
152 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800153 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800154 if not (host.hostname == 'localhost' or
155 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700156 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700157 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700158 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700159 timeout=timeout)
beeps46dadc92013-11-07 14:07:10 -0800160 except (error.AutoservRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800161 if current_user is not None:
162 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800163 return False
164 return result.exit_status == 0
165
166
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700167 # TODO(garnold) Remove the 'serials' argument once all clients are made to
168 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700169 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700170 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700171 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700172 """Initialize an ADB Host.
173
174 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700175 test station connected to an Android DUT. This will be the DUT
176 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700177 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700178
179 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700180 @param serials: DEPRECATED (to be removed)
181 @param adb_serial: An ADB device serial. If None, assume a single
182 device is attached (and fail otherwise).
183 @param fastboot_serial: A fastboot device serial. If None, defaults to
184 the ADB serial (or assumes a single device if
185 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800186 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700187 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800188 # Sets up the is_client_install_supported field.
189 super(ADBHost, self)._initialize(hostname=hostname,
190 is_client_install_supported=False,
191 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800192
Kevin Chengd19e6c62015-10-28 16:39:39 -0700193 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800194 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Simran Basi1bf60eb2015-12-01 16:39:29 -0800195 # TODO (sbasi/kevcheng): Once the teststation host is committed,
196 # refactor the serial retrieval.
197 adb_serial = adb_serial or self.host_attributes.get('serials', None)
Dan Shi50a412a2016-01-05 10:52:40 -0800198 self.adb_serial = adb_serial
199 self.fastboot_serial = fastboot_serial or adb_serial
Kevin Cheng85e864a2015-11-30 11:49:34 -0800200 self.teststation = (teststation if teststation
201 else teststation_host.create_teststationhost(hostname=hostname))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700202
203 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800204 if self.adb_serial:
205 msg += ', ADB serial: %s' % self.adb_serial
206 if self.fastboot_serial:
207 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700208 logging.debug(msg)
209
Simran Basi9228a6f2016-03-29 12:03:37 -0700210 adb_prefix = any(adb_serial.startswith(p) for p in ADB_DEVICE_PREFIXES)
211 self._use_tcpip = ':' in adb_serial and not adb_prefix
Simran Basibeb2bb22016-02-03 15:25:48 -0800212 # Try resetting the ADB daemon on the device, however if we are
213 # creating the host to do a repair job, the device maybe inaccesible
214 # via ADB.
215 try:
216 self._reset_adbd_connection()
217 except (error.AutotestHostRunError, error.AutoservRunError) as e:
218 logging.error('Unable to reset the device adb daemon connection: '
219 '%s.', e)
Dan Shiab999722015-12-04 14:27:08 -0800220 self._os_type = None
221
Simran Basi431010f2013-09-04 10:42:41 -0700222
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700223 def _connect_over_tcpip_as_needed(self):
224 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700225 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700226 return
227 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700228 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700229
230
Roshan Pius4d7540c2015-12-16 13:30:32 -0800231 def _restart_adbd_with_root_permissions(self):
232 """Restarts the adb daemon with root permissions."""
233 self.adb_run('root')
234 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
235 time.sleep(1)
236 self.adb_run('wait-for-device')
237
238
Simran Basi9228a6f2016-03-29 12:03:37 -0700239 def _set_tcp_port(self):
240 """Ensure the device remains in tcp/ip mode after a reboot."""
241 if not self._use_tcpip:
242 return
243 port = self.adb_serial.split(':')[-1]
244 self.run('setprop persist.adb.tcp.port %s' % port)
245
246
Roshan Pius4d7540c2015-12-16 13:30:32 -0800247 def _reset_adbd_connection(self):
248 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800249 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700250 self._restart_adbd_with_root_permissions()
251 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800252
253
Kevin Cheng85e864a2015-11-30 11:49:34 -0800254 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800255 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700256 """Runs an adb command.
257
Kevin Chengd19e6c62015-10-28 16:39:39 -0700258 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700259
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700260 Refer to _device_run method for docstring for parameters.
261 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800262 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700263
264
Kevin Cheng85e864a2015-11-30 11:49:34 -0800265 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800266 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700267 """Runs an fastboot command.
268
Kevin Chengd19e6c62015-10-28 16:39:39 -0700269 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700270
271 Refer to _device_run method for docstring for parameters.
272 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800273 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700274
275
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700276 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700277 timeout=3600, ignore_status=False, ignore_timeout=False,
278 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
279 connect_timeout=30, options='', stdin=None, verbose=True,
280 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700281 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700282
Kevin Chengd19e6c62015-10-28 16:39:39 -0700283 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700284
Simran Basi431010f2013-09-04 10:42:41 -0700285 @param command: Command to run.
286 @param shell: If true the command runs in the adb shell otherwise if
287 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700288 reboot with shell=False will call 'adb reboot'. This
289 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700290 @param timeout: Time limit in seconds before attempting to
291 kill the running process. The run() function
292 will take a few seconds longer than 'timeout'
293 to complete if it has to kill the process.
294 @param ignore_status: Do not raise an exception, no matter
295 what the exit code of the command is.
296 @param ignore_timeout: Bool True if command timeouts should be
297 ignored. Will return None on command timeout.
298 @param stdout: Redirect stdout.
299 @param stderr: Redirect stderr.
300 @param connect_timeout: Connection timeout (in seconds)
301 @param options: String with additional ssh command options
302 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700303 @param require_sudo: True to require sudo to run the command. Default is
304 False.
Simran Basi431010f2013-09-04 10:42:41 -0700305 @param args: Sequence of strings to pass as arguments to command by
306 quoting them in " and escaping their contents if
307 necessary.
308
309 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700310 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700311 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800312 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700313 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800314 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700315 else:
316 raise NotImplementedError('Mode %s is not supported' % function)
317
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700318 if function != ADB_CMD and shell:
319 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700320
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700321 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700322
323 if serial:
324 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700325
Simran Basi431010f2013-09-04 10:42:41 -0700326 if shell:
327 cmd += '%s ' % SHELL_CMD
328 cmd += command
329
Roshan Pius58e5dd32015-10-16 15:16:42 -0700330 if verbose:
331 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700332
Kevin Cheng85e864a2015-11-30 11:49:34 -0800333 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400334 ignore_status=ignore_status,
335 ignore_timeout=ignore_timeout, stdout_tee=stdout,
336 stderr_tee=stderr, options=options, stdin=stdin,
337 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700338
339
Dan Shie234dea2016-01-20 17:15:17 -0800340 def get_board_name(self):
341 """Get the name of the board, e.g., shamu, dragonboard etc.
342 """
343 return self.run_output('getprop %s' % BOARD_FILE)
344
345
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700346 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700347 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700348 """Determine the correct board label for the device.
349
350 @returns a string representing this device's board.
351 """
Dan Shie234dea2016-01-20 17:15:17 -0800352 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700353 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800354 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700355
356
Christopher Wiley08849d52013-11-22 08:57:58 -0800357 def job_start(self):
358 """
359 Disable log collection on adb_hosts.
360
361 TODO(sbasi): crbug.com/305427
Christopher Wiley08849d52013-11-22 08:57:58 -0800362 """
363
364
Simran Basi431010f2013-09-04 10:42:41 -0700365 def run(self, command, timeout=3600, ignore_status=False,
366 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
367 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700368 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700369 """Run a command on the adb device.
370
371 The command given will be ran directly on the adb device; for example
372 'ls' will be ran as: 'abd shell ls'
373
374 @param command: The command line string.
375 @param timeout: Time limit in seconds before attempting to
376 kill the running process. The run() function
377 will take a few seconds longer than 'timeout'
378 to complete if it has to kill the process.
379 @param ignore_status: Do not raise an exception, no matter
380 what the exit code of the command is.
381 @param ignore_timeout: Bool True if command timeouts should be
382 ignored. Will return None on command timeout.
383 @param stdout_tee: Redirect stdout.
384 @param stderr_tee: Redirect stderr.
385 @param connect_timeout: Connection timeout (in seconds).
386 @param options: String with additional ssh command options.
387 @param stdin: Stdin to pass (a string) to the executed command
388 @param args: Sequence of strings to pass as arguments to command by
389 quoting them in " and escaping their contents if
390 necessary.
391
392 @returns A CMDResult object or None if the call timed out and
393 ignore_timeout is True.
394
395 @raises AutoservRunError: If the command failed.
396 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700397 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700398 command = ('"%s; echo %s:\$?"' %
399 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700400 result = self.adb_run(
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700401 command, shell=True, timeout=timeout,
Simran Basi431010f2013-09-04 10:42:41 -0700402 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
403 stdout=stdout_tee, stderr=stderr_tee,
404 connect_timeout=connect_timeout, options=options, stdin=stdin,
Roshan Pius58e5dd32015-10-16 15:16:42 -0700405 verbose=verbose, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700406 if not result:
407 # In case of timeouts.
408 return None
409
410 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
Roshan Pius5ba5d182015-10-28 09:19:41 -0700411 if not parse_output and not ignore_status:
Simran Basi431010f2013-09-04 10:42:41 -0700412 raise error.AutoservRunError(
Roshan Pius5ba5d182015-10-28 09:19:41 -0700413 'Failed to parse the exit code for command: %s' %
414 command, result)
415 elif parse_output:
416 result.stdout = parse_output.group('OUTPUT')
417 result.exit_status = int(parse_output.group('EXIT_CODE'))
418 if result.exit_status != 0 and not ignore_status:
419 raise error.AutoservRunError(command, result)
Simran Basi431010f2013-09-04 10:42:41 -0700420 return result
421
422
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700423 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
424 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700425
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700426 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700427
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700428 @param timeout: Time limit in seconds before returning even if the host
429 is not up.
430 @param command: The command used to test if a device is up, i.e.,
431 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700432
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700433 @returns True if the host was found to be up before the timeout expires,
434 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700435 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700436 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
437 delay_sec=1)
438 def _wait_up():
439 if not self.is_up(command=command):
440 raise error.TimeoutException('Device is still down.')
441 return True
442
443 try:
444 _wait_up()
445 logging.debug('Host %s is now up, and can be accessed by %s.',
446 self.hostname, command)
447 return True
448 except error.TimeoutException:
449 logging.debug('Host %s is still down after waiting %d seconds',
450 self.hostname, timeout)
451 return False
Simran Basi431010f2013-09-04 10:42:41 -0700452
453
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700454 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
455 warning_timer=None, old_boot_id=None, command=ADB_CMD):
456 """Wait till the host goes down, i.e., not accessible by given command.
Simran Basi431010f2013-09-04 10:42:41 -0700457
458 Overrides wait_down from AbstractSSHHost.
459
460 @param timeout: Time in seconds to wait for the host to go down.
461 @param warning_timer: Time limit in seconds that will generate
462 a warning if the host is not down yet.
463 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700464 @param old_boot_id: Not applicable for adb_host.
465 @param command: `adb`, test if the device can be accessed by adb
466 command, or `fastboot`, test if the device can be accessed by
467 fastboot command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700468
469 @returns True if the device goes down before the timeout, False
470 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700471 """
472 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
473 delay_sec=1)
474 def _wait_down():
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700475 if self.is_up(command=command):
Simran Basi431010f2013-09-04 10:42:41 -0700476 raise error.TimeoutException('Device is still up.')
477 return True
478
479 try:
480 _wait_down()
481 logging.debug('Host %s is now down', self.hostname)
482 return True
483 except error.TimeoutException:
484 logging.debug('Host %s is still up after waiting %d seconds',
485 self.hostname, timeout)
486 return False
487
488
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700489 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700490 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700491
492 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700493 """
494 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700495 # the test station we are running ADB on.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700496 self.adb_run('reboot', timeout=10, ignore_timeout=True)
497 if not self.wait_down():
498 raise error.AutoservRebootError(
499 'ADB Device is still up after reboot')
500 if not self.wait_up():
501 raise error.AutoservRebootError(
502 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800503 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800504
505
Ralph Nathanb45eb672015-11-18 20:04:39 -0800506 def remount(self):
507 """Remounts paritions on the device read-write.
508
509 Specifically, the /system, /vendor (if present) and /oem (if present)
510 partitions on the device are remounted read-write.
511 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800512 self.adb_run('remount')
513
514
Kevin Cheng549beb42015-11-18 11:42:25 -0800515 @staticmethod
516 def parse_device_serials(devices_output):
517 """Return a list of parsed serials from the output.
518
519 @param devices_output: Output from either an adb or fastboot command.
520
521 @returns List of device serials
522 """
523 devices = []
524 for line in devices_output.splitlines():
525 match = re.search(DEVICE_FINDER_REGEX, line)
526 if match:
527 serial = match.group('SERIAL')
528 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
529 serial = DEVICE_NO_SERIAL_TAG
530 logging.debug('Found Device: %s', serial)
531 devices.append(serial)
532 return devices
533
534
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700535 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700536 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700537
538 @params use_adb: True to get adb accessible devices. Set to False to
539 get fastboot accessible devices.
540
Kevin Chengd19e6c62015-10-28 16:39:39 -0700541 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700542 """
543 if use_adb:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700544 result = self.adb_run('devices')
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700545 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700546 result = self.fastboot_run('devices')
Kevin Cheng549beb42015-11-18 11:42:25 -0800547 return self.parse_device_serials(result.stdout)
Simran Basi431010f2013-09-04 10:42:41 -0700548
549
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700550 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700551 """Get a list of devices currently attached to the test station and
552 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700553 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800554 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700555 raise error.AutoservError(
556 'Not given ADB serial but multiple devices detected')
557 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700558
559
560 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700561 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700562 accessible by fastboot command.
563 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700564 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800565 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700566 raise error.AutoservError(
567 'Not given fastboot serial but multiple devices detected')
568 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700569
570
571 def is_up(self, timeout=0, command=ADB_CMD):
572 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700573
574 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700575 @param command: `adb`, the device can be accessed by adb command,
576 or `fastboot`, the device can be accessed by fastboot command.
577 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700578
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700579 @returns True if the device is detectable by given command, False
580 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700581
582 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700583 if command == ADB_CMD:
584 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800585 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800586 # ADB has a device state, if the device is not online, no
587 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800588 # DUT with single device connected may not have adb_serial set.
589 # Therefore, skip checking if serial is in the list of adb devices
590 # if self.adb_serial is not set.
591 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800592 logging.debug('Waiting for device to enter the ready state.')
593 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700594 elif command == FASTBOOT_CMD:
595 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800596 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700597 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700598 raise NotImplementedError('Mode %s is not supported' % command)
599
600 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700601
602
603 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700604 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700605
606 Called as the test ends. Will return the device to USB mode and kill
607 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700608 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800609 # TODO(sbasi) Originally, we would kill the server after each test to
610 # reduce the opportunity for bad server state to hang around.
611 # Unfortunately, there is a period of time after each kill during which
612 # the Android device becomes unusable, and if we start the next test
613 # too quickly, we'll get an error complaining about no ADB device
614 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700615 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800616 # |close| the associated teststation as well.
617 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700618 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700619
620
621 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700622 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700623
624 @param message String message to log into syslog
625 @param tag String tag prefix for syslog
626
627 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700628 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700629
630
631 def get_autodir(self):
632 """Return the directory to install autotest for client side tests."""
633 return '/data/autotest'
634
Kevin Cheng018db352015-09-20 02:22:08 -0700635
Kris Rambishde8f9d12015-12-16 12:42:41 -0800636 def is_device_ready(self):
637 """Return the if the device is ready for ADB commands."""
638 dev_state = self.adb_run('get-state').stdout.strip()
639 logging.debug('Current device state: %s', dev_state)
640 return dev_state == 'device'
641
642
Kevin Chengd19e6c62015-10-28 16:39:39 -0700643 def verify_connectivity(self):
644 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800645 if not self.is_device_ready():
646 raise error.AutoservHostError('device state is not in the '
647 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700648
649
Simran Basid3ba3fb2015-09-11 14:35:07 -0700650 def verify_software(self):
651 """Verify working software on an adb_host.
652
Simran Basi38f7ddf2015-09-18 12:25:03 -0700653 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700654 """
Dan Shiab999722015-12-04 14:27:08 -0800655 # Check if adb and fastboot are present.
656 self.teststation.run('which adb')
657 self.teststation.run('which fastboot')
658 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700659
Kevin Cheng018db352015-09-20 02:22:08 -0700660
Simran Basid3ba3fb2015-09-11 14:35:07 -0700661 def verify_job_repo_url(self, tag=''):
662 """Make sure job_repo_url of this host is valid.
663
Simran Basi38f7ddf2015-09-18 12:25:03 -0700664 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700665
666 @param tag: The tag from the server job, in the format
667 <job_id>-<user>/<hostname>, or <hostless> for a server job.
668 """
669 return
Kevin Cheng018db352015-09-20 02:22:08 -0700670
671
Simran Basibeb2bb22016-02-03 15:25:48 -0800672 def repair(self):
673 """Attempt to get the DUT to pass `self.verify()`."""
674 try:
675 self.ensure_adb_mode(timeout=30)
676 return
677 except error.AutoservError as e:
678 logging.error(e)
679 logging.debug('Verifying the device is accessible via fastboot.')
680 self.ensure_bootloader_mode()
681 if not self.job.run_test(
682 'provision_AndroidUpdate', host=self, value=None,
683 force=True, repair=True):
684 raise error.AutoservRepairTotalFailure(
685 'Unable to repair the device.')
686
687
Simran Basi1b023762015-09-25 12:12:20 -0700688 def send_file(self, source, dest, delete_dest=False,
689 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700690 """Copy files from the drone to the device.
691
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400692 Just a note, there is the possibility the test station is localhost
693 which makes some of these steps redundant (e.g. creating tmp dir) but
694 that scenario will undoubtedly be a development scenario (test station
695 is also the moblab) and not the typical live test running scenario so
696 the redundancy I think is harmless.
697
Kevin Cheng018db352015-09-20 02:22:08 -0700698 @param source: The file/directory on the drone to send to the device.
699 @param dest: The destination path on the device to copy to.
700 @param delete_dest: A flag set to choose whether or not to delete
701 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700702 @param preserve_symlinks: Controls if symlinks on the source will be
703 copied as such on the destination or
704 transformed into the referenced
705 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700706 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700707 # If we need to preserve symlinks, let's check if the source is a
708 # symlink itself and if so, just create it on the device.
709 if preserve_symlinks:
710 symlink_target = None
711 try:
712 symlink_target = os.readlink(source)
713 except OSError:
714 # Guess it's not a symlink.
715 pass
716
717 if symlink_target is not None:
718 # Once we create the symlink, let's get out of here.
719 self.run('ln -s %s %s' % (symlink_target, dest))
720 return
721
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400722 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700723 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400724 src_path = os.path.join(tmp_dir, os.path.basename(dest))
725 # Now copy the file over to the test station so you can reference the
726 # file in the push command.
727 self.teststation.send_file(source, src_path,
728 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700729
730 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400731 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700732
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700733 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700734
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400735 # Cleanup the test station.
736 try:
737 self.teststation.run('rm -rf %s' % tmp_dir)
738 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
739 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700740
741
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700742 def _get_file_info(self, dest):
743 """Get permission and possible symlink info about file on the device.
744
745 These files are on the device so we only have shell commands (via adb)
746 to get the info we want. We'll use 'ls' to get it all.
747
748 @param dest: File to get info about.
749
750 @returns a dict of the file permissions and symlink.
751 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800752 # Grab file info.
753 file_info = self.run_output('ls -l %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700754 symlink = None
755 perms = 0
756 match = re.match(FILE_INFO_REGEX, file_info)
757 if match:
758 # Check if it's a symlink and grab the linked dest if it is.
759 if match.group('TYPE') == 'l':
760 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
761 if symlink_match:
762 symlink = symlink_match.group('SYMLINK')
763
764 # Set the perms.
765 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
766 if perm != '-':
767 perms |= perm_flag
768
769 return {'perms': perms,
770 'symlink': symlink}
771
772
Simran Basi1b023762015-09-25 12:12:20 -0700773 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
774 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700775 """Copy files from the device to the drone.
776
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400777 Just a note, there is the possibility the test station is localhost
778 which makes some of these steps redundant (e.g. creating tmp dir) but
779 that scenario will undoubtedly be a development scenario (test station
780 is also the moblab) and not the typical live test running scenario so
781 the redundancy I think is harmless.
782
Kevin Cheng018db352015-09-20 02:22:08 -0700783 @param source: The file/directory on the device to copy back to the
784 drone.
785 @param dest: The destination path on the drone to copy to.
786 @param delete_dest: A flag set to choose whether or not to delete
787 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700788 @param preserve_perm: Tells get_file() to try to preserve the sources
789 permissions on files and dirs.
790 @param preserve_symlinks: Try to preserve symlinks instead of
791 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -0700792 """
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400793 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700794 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400795 dest_path = os.path.join(tmp_dir, os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -0700796
797 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400798 self.teststation.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700799
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700800 source_info = {}
801 if preserve_symlinks or preserve_perm:
802 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -0700803
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700804 # If we want to preserve symlinks, just create it here, otherwise pull
805 # the file off the device.
806 if preserve_symlinks and source_info['symlink']:
807 os.symlink(source_info['symlink'], dest)
808 else:
Roshan Pius95567142015-11-03 09:56:08 -0800809 self.adb_run('pull %s %s' % (source, dest_path))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700810
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400811 # Copy over the file from the test station and clean up.
812 self.teststation.get_file(dest_path, dest)
813 try:
814 self.teststation.run('rm -rf %s' % tmp_dir)
815 except (error.AutoservRunError, error.AutoservSSHTimeout) as e:
816 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700817
818 if preserve_perm:
819 os.chmod(dest, source_info['perms'])
Kevin Cheng018db352015-09-20 02:22:08 -0700820
821
822 def get_release_version(self):
823 """Get the release version from the RELEASE_FILE on the device.
824
825 @returns The release string in the RELEASE_FILE.
826
827 """
828 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -0700829
830
831 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700832 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700833
Kevin Chengd19e6c62015-10-28 16:39:39 -0700834 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700835
836 @param parent: Parent directory of the returned tmp dir.
837
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700838 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700839 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700840 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
841 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -0700842 if not parent.startswith(TMP_DIR):
843 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -0700844 self.run('mkdir -p %s' % parent)
845 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
846 self.tmp_dirs.append(tmp_dir)
847 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -0700848
849
850 def get_platform(self):
851 """Determine the correct platform label for this host.
852
853 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -0700854 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -0700855
856 @returns a string representing this host's platform.
857 """
858 return 'adb'
859
860
Gilad Arnolda76bef02015-09-29 13:55:15 -0700861 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -0800862 """Get the OS type of the DUT, e.g., android or brillo.
863 """
864 if not self._os_type:
865 if self.run_output('getprop ro.product.brand') == 'Brillo':
866 self._os_type = OS_TYPE_BRILLO
867 else:
868 self._os_type = OS_TYPE_ANDROID
869
870 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700871
872
873 def _forward(self, reverse, args):
874 """Execute a forwarding command.
875
876 @param reverse: Whether this is reverse forwarding (Boolean).
877 @param args: List of command arguments.
878 """
879 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700880 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -0700881
882
883 def add_forwarding(self, src, dst, reverse=False, rebind=True):
884 """Forward a port between the ADB host and device.
885
886 Port specifications are any strings accepted as such by ADB, for
887 example 'tcp:8080'.
888
889 @param src: Port specification to forward from.
890 @param dst: Port specification to forward to.
891 @param reverse: Do reverse forwarding from device to host (Boolean).
892 @param rebind: Allow rebinding an already bound port (Boolean).
893 """
894 args = []
895 if not rebind:
896 args.append('--no-rebind')
897 args += [src, dst]
898 self._forward(reverse, args)
899
900
901 def remove_forwarding(self, src=None, reverse=False):
902 """Removes forwarding on port.
903
904 @param src: Port specification, or None to remove all forwarding.
905 @param reverse: Whether this is reverse forwarding (Boolean).
906 """
907 args = []
908 if src is None:
909 args.append('--remove-all')
910 else:
911 args += ['--remove', src]
912 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700913
914
xixuan6cf6d2f2016-01-29 15:29:00 -0800915 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700916 """
917 Forwards a port securely through a tunnel process from the server
918 to the DUT for RPC server connection.
919 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
920 to the DUT.
921
922 @param port: remote port on the DUT.
923 @param local_port: local forwarding port.
924
925 @return: the tunnel process.
926 """
927 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800928 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -0700929
930
xixuan6cf6d2f2016-01-29 15:29:00 -0800931 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -0700932 """
933 Disconnects a previously forwarded port from the server to the DUT for
934 RPC server connection.
935 Remove the previously added 'ADB forward' rule to forward the RPC
936 packets from the AdbHost to the DUT.
937
938 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -0800939 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -0700940 @param port: remote port on the DUT.
941
942 """
943 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -0800944 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700945
946
947 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700948 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700949
950 @raise: error.AutoservError if the device failed to reboot into
951 bootloader mode.
952 """
953 if self.is_up(command=FASTBOOT_CMD):
954 return
955 self.adb_run('reboot bootloader')
956 if not self.wait_up(command=FASTBOOT_CMD):
957 raise error.AutoservError(
958 'The device failed to reboot into bootloader mode.')
959
960
Dan Shie4e807b2015-12-10 09:04:03 -0800961 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700962 """Ensure the device is up and can be accessed by adb command.
963
Dan Shie4e807b2015-12-10 09:04:03 -0800964 @param timeout: Time limit in seconds before returning even if the host
965 is not up.
966
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700967 @raise: error.AutoservError if the device failed to reboot into
968 adb mode.
969 """
970 if self.is_up():
971 return
Dan Shi04980372016-03-22 10:57:47 -0700972 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
973 # check if the device is in adb mode.
974 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -0800975 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700976 raise error.AutoservError(
977 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800978 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -0700979
980
981 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -0800982 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -0700983 """Get the Android build information from the build url.
984
985 @param build_url: The url to use for downloading Android artifacts.
986 pattern: http://$devserver:###/static/branch/target/build_id
987
Dan Shi6450e142016-03-11 11:52:20 -0800988 @return: A dictionary of build information, including keys:
989 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -0800990 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -0700991 """
Dan Shiab999722015-12-04 14:27:08 -0800992 if not build_url:
993 raise AndroidInstallError('Need build_url to download image files.')
994
995 try:
996 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -0800997 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -0800998 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -0800999 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001000 match.group('BUILD_TYPE'))),
1001 'build_id': match.group('BUILD_ID')}
1002 except (AttributeError, IndexError, ValueError) as e:
1003 raise AndroidInstallError(
1004 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001005
1006
Dan Shia2872172015-10-31 01:16:51 -07001007 @retry.retry(error.AutoservRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001008 def download_file(self, build_url, file, dest_dir, unzip=False,
1009 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001010 """Download the given file from the build url.
1011
1012 @param build_url: The url to use for downloading Android artifacts.
1013 pattern: http://$devserver:###/static/branch/target/build_id
1014 @param file: Name of the file to be downloaded, e.g., boot.img.
1015 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001016 @param unzip: If True, unzip the downloaded file.
1017 @param unzip_dest: Location to unzip the downloaded file to. If not
1018 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001019 """
Dan Shidb0366c2016-02-19 10:36:18 -08001020 # Append the file name to the url if build_url is linked to the folder
1021 # containing the file.
1022 if not build_url.endswith('/%s' % file):
1023 src_url = os.path.join(build_url, file)
1024 else:
1025 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001026 dest_file = os.path.join(dest_dir, file)
1027 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001028 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001029 if unzip:
1030 unzip_dest = unzip_dest or dest_dir
1031 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1032 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001033 except:
1034 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001035 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001036 raise
1037
1038
Dan Shiab999722015-12-04 14:27:08 -08001039 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001040 """Download required image files from the given build_url to a local
1041 directory in the machine runs fastboot command.
1042
1043 @param build_url: The url to use for downloading Android artifacts.
1044 pattern: http://$devserver:###/static/branch/target/build_id
1045
1046 @return: Path to the directory contains image files.
1047 """
Dan Shi08ff1282016-02-18 19:51:16 -08001048 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001049
1050 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001051 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001052
1053 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001054 self.download_file(build_url, zipped_image_file, image_dir,
1055 unzip=True)
1056 for image_file in ANDROID_STANDALONE_IMAGES:
Dan Shidb0366c2016-02-19 10:36:18 -08001057 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001058
Dan Shia2872172015-10-31 01:16:51 -07001059 return image_dir
1060 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001061 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001062 raise
1063
1064
Dan Shiab999722015-12-04 14:27:08 -08001065 def stage_brillo_image_files(self, build_url):
1066 """Download required brillo image files from the given build_url to a
1067 local directory in the machine runs fastboot command.
1068
1069 @param build_url: The url to use for downloading Android artifacts.
1070 pattern: http://$devserver:###/static/branch/target/build_id
1071
1072 @return: Path to the directory contains image files.
1073 """
Dan Shi08ff1282016-02-18 19:51:16 -08001074 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001075
1076 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1077 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1078 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001079
1080 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001081 self.download_file(build_url, zipped_image_file, image_dir,
1082 unzip=True)
1083 self.download_file(build_url, vendor_partitions_file, image_dir,
1084 unzip=True,
1085 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001086 return image_dir
1087 except:
1088 self.teststation.run('rm -rf %s' % image_dir)
1089 raise
1090
1091
Simran Basibeb2bb22016-02-03 15:25:48 -08001092 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001093 """Stage a build on a devserver and return the build_url and devserver.
1094
1095 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001096
Dan Shi225b9042015-11-18 10:25:21 -08001097 @returns a tuple with an update URL like:
1098 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1099 and the devserver instance.
1100 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001101 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001102 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001103 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1104 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001105 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001106 branch, target, build_id = utils.parse_launch_control_build(build_name)
Simran Basibeb2bb22016-02-03 15:25:48 -08001107 is_brillo = os_type == OS_TYPE_BRILLO
Dan Shi08ff1282016-02-18 19:51:16 -08001108 devserver.trigger_download(target, build_id, branch,
1109 is_brillo=is_brillo, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001110 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001111
1112
Dan Shie4e807b2015-12-10 09:04:03 -08001113 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001114 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001115 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001116
1117 Following are the steps used here to provision an android device:
1118 1. If build_local_path is not set, download the image zip file, e.g.,
1119 shamu-img-2284311.zip, unzip it.
1120 2. Run fastboot to install following artifacts:
1121 bootloader, radio, boot, system, vendor(only if exists)
1122
1123 Repair is not supported for Android devices yet.
1124
1125 @param build_url: The url to use for downloading Android artifacts.
1126 pattern: http://$devserver:###/static/$build
1127 @param build_local_path: The path to a local folder that contains the
1128 image files needed to provision the device. Note that the folder
1129 is in the machine running adb command, rather than the drone.
1130 @param wipe: If true, userdata will be wiped before flashing.
1131 @param flash_all: If True, all img files found in img_path will be
1132 flashed. Otherwise, only boot and system are flashed.
1133
1134 @raises AndroidInstallError if any error occurs.
1135 """
Dan Shia2872172015-10-31 01:16:51 -07001136 # If the build is not staged in local server yet, clean up the temp
1137 # folder used to store image files after the provision is completed.
1138 delete_build_folder = bool(not build_local_path)
1139
1140 try:
1141 # Download image files needed for provision to a local directory.
1142 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001143 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001144
1145 # Device needs to be in bootloader mode for flashing.
1146 self.ensure_bootloader_mode()
1147
1148 if wipe:
Dan Shie4e807b2015-12-10 09:04:03 -08001149 self.fastboot_run('-w')
Dan Shia2872172015-10-31 01:16:51 -07001150
1151 # Get all *.img file in the build_local_path.
1152 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001153 image_files = self.teststation.run(
1154 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001155 images = dict([(os.path.basename(f), f) for f in image_files])
1156 for image, image_file in images.items():
1157 if image not in ANDROID_IMAGES:
1158 continue
1159 logging.info('Flashing %s...', image_file)
Dan Shi70c30192016-03-22 23:14:12 -07001160 self.fastboot_run('-S 256M flash %s %s' %
Dan Shie9913d32016-03-09 14:17:26 -08001161 (image[:-4], image_file))
Dan Shia2872172015-10-31 01:16:51 -07001162 if image == ANDROID_BOOTLOADER:
1163 self.fastboot_run('reboot-bootloader')
1164 self.wait_up(command=FASTBOOT_CMD)
1165 except Exception as e:
1166 logging.error('Install Android build failed with error: %s', e)
1167 # Re-raise the exception with type of AndroidInstallError.
1168 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1169 finally:
1170 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001171 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001172 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1173 DEFAULT_WAIT_UP_TIME_SECONDS)
1174 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001175 logging.info('Successfully installed Android build staged at %s.',
1176 build_url)
1177
1178
Dan Shiab999722015-12-04 14:27:08 -08001179 def install_brillo(self, build_url, build_local_path=None):
1180 """Install the Brillo DUT.
1181
1182 Following are the steps used here to provision an android device:
1183 1. If build_local_path is not set, download the image zip file, e.g.,
1184 dragonboard-img-123456.zip, unzip it. And download the vendor
1185 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1186 unzip it to vendor folder.
1187 2. Run provision_device script to install OS images and vendor
1188 partitions.
1189
1190 @param build_url: The url to use for downloading Android artifacts.
1191 pattern: http://$devserver:###/static/$build
1192 @param build_local_path: The path to a local folder that contains the
1193 image files needed to provision the device. Note that the folder
1194 is in the machine running adb command, rather than the drone.
1195
1196 @raises AndroidInstallError if any error occurs.
1197 """
1198 # If the build is not staged in local server yet, clean up the temp
1199 # folder used to store image files after the provision is completed.
1200 delete_build_folder = bool(not build_local_path)
1201
Dan Shiab999722015-12-04 14:27:08 -08001202 try:
1203 # Download image files needed for provision to a local directory.
1204 if not build_local_path:
1205 build_local_path = self.stage_brillo_image_files(build_url)
1206
1207 # Device needs to be in bootloader mode for flashing.
1208 self.ensure_bootloader_mode()
1209
1210 # Run provision_device command to install image files and vendor
1211 # partitions.
1212 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1213 cmd = (BRILLO_PROVISION_CMD %
1214 {'os_image_dir': build_local_path,
1215 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001216 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001217 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001218 self.teststation.run(cmd)
1219 except Exception as e:
1220 logging.error('Install Brillo build failed with error: %s', e)
1221 # Re-raise the exception with type of AndroidInstallError.
1222 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1223 finally:
1224 if delete_build_folder:
1225 self.teststation.run('rm -rf %s' % build_local_path)
1226 self.ensure_adb_mode()
1227 logging.info('Successfully installed Android build staged at %s.',
1228 build_url)
1229
1230
Dan Shibe3636a2016-02-14 22:48:01 -08001231 @property
1232 def job_repo_url_attribute(self):
1233 """Get the host attribute name for job_repo_url, which should append the
1234 adb serial.
1235 """
1236 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1237
1238
Dan Shie4e807b2015-12-10 09:04:03 -08001239 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001240 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001241 """Install the DUT.
1242
1243 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001244 pattern: http://$devserver:###/static/$build. If build_url is
1245 set to None, the code may try _parser.options.image to do the
1246 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001247 @param build_local_path: The path to a local directory that contains the
1248 image files needed to provision the device.
1249 @param wipe: If true, userdata will be wiped before flashing.
1250 @param flash_all: If True, all img files found in img_path will be
1251 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001252
Dan Shibe3636a2016-02-14 22:48:01 -08001253 @returns A tuple of (image_name, host_attributes).
1254 image_name is the name of image installed, e.g.,
1255 git_mnc-release/shamu-userdebug/1234
1256 host_attributes is a dictionary of (attribute, value), which
1257 can be saved to afe_host_attributes table in database. This
1258 method returns a dictionary with a single entry of
1259 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1260 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001261 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001262 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001263 if not build_url and self._parser.options.image:
1264 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001265 self._parser.options.image, os_type=os_type)
1266 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001267 self.install_android(
1268 build_url=build_url, build_local_path=build_local_path,
1269 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001270 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001271 self.install_brillo(
1272 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001273 else:
1274 raise error.InstallError(
1275 'Installation of os type %s is not supported.' %
1276 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001277 return (build_url.split('static/')[-1],
1278 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001279
1280
1281 def list_files_glob(self, path_glob):
1282 """Get a list of files on the device given glob pattern path.
1283
1284 @param path_glob: The path glob that we want to return the list of
1285 files that match the glob. Relative paths will not work as
1286 expected. Supply an absolute path to get the list of files
1287 you're hoping for.
1288
1289 @returns List of files that match the path_glob.
1290 """
1291 # This is just in case path_glob has no path separator.
1292 base_path = os.path.dirname(path_glob) or '.'
1293 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001294 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001295 if result.exit_status != 0:
1296 return []
1297 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001298
1299
Dan Shidb0366c2016-02-19 10:36:18 -08001300 def install_apk(self, apk, force_reinstall=False):
Kevin Cheng31355942016-01-05 14:23:35 -08001301 """Install the specified apk.
1302
1303 This will install the apk and override it if it's already installed and
1304 will also allow for downgraded apks.
1305
1306 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001307 @param force_reinstall: True to reinstall the apk even if it's already
1308 installed. Default is set to False.
1309
1310 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001311 """
Dan Shidb0366c2016-02-19 10:36:18 -08001312 return self.adb_run('install %s -d %s' %
1313 ('-r' if force_reinstall else '', apk))
1314
1315
1316 @retry.retry(error.AutoservRunError, timeout_min=0.2)
1317 def _confirm_apk_installed(self, package_name):
1318 """Confirm if apk is already installed with the given name.
1319
1320 `pm list packages` command is not reliable some time. The retry helps to
1321 reduce the chance of false negative.
1322
1323 @param package_name: Name of the package, e.g., com.android.phone.
1324
1325 @raise AutoservRunError: If the package is not found or pm list command
1326 failed for any reason.
1327 """
1328 name = 'package:%s' % package_name
1329 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1330
1331
1332 def is_apk_installed(self, package_name):
1333 """Check if apk is already installed with the given name.
1334
1335 @param package_name: Name of the package, e.g., com.android.phone.
1336
1337 @return: True if package is installed. False otherwise.
1338 """
1339 try:
1340 self._confirm_apk_installed(package_name)
1341 return True
1342 except:
1343 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001344
1345
1346 def get_attributes_to_clear_before_provision(self):
1347 """Get a list of attributes to be cleared before machine_install starts.
1348 """
1349 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001350
1351
1352 def get_labels(self):
1353 """Return a list of the labels gathered from the devices connected.
1354
1355 @return: A list of strings that denote the labels from all the devices
1356 connected.
1357 """
1358 return self.labels.get_labels(self)
1359
1360
1361 def update_labels(self):
1362 """Update the labels for this testbed."""
1363 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001364
1365
1366 def stage_server_side_package(self, image=None):
1367 """Stage autotest server-side package on devserver.
1368
1369 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1370
1371 @return: A url to the autotest server-side package. Return None if
1372 server-side package is not supported.
1373 @raise: error.AutoservError if fail to locate the build to test with.
1374 """
1375 if image:
1376 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1377 else:
1378 job_repo_url = afe_utils.get_host_attribute(
1379 self, self.job_repo_url_attribute)
1380 if job_repo_url:
1381 devserver_url, image = (
1382 tools.get_devserver_build_from_package_url(
1383 job_repo_url, True))
1384 ds = dev_server.AndroidBuildServer(devserver_url)
1385 else:
1386 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1387 if not labels:
1388 raise error.AutoservError(
1389 'Failed to stage server-side package. The host has '
1390 'no job_report_url attribute or version label.')
1391 image = labels[0].name[len(self.VERSION_PREFIX)+1:]
1392 ds = dev_server.AndroidBuildServer.resolve(image, self.hostname)
1393
1394 branch, target, build_id = utils.parse_launch_control_build(image)
1395 build_target, _ = utils.parse_launch_control_target(target)
1396
1397 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1398 # packaging is not supported.
1399 try:
1400 if int(build_id) < self.MIN_VERSION_SUPPORT_SSP:
1401 logging.warn('Build %s is older than %s. Server side packaging '
1402 'is disabled.', image,
1403 self.MIN_VERSION_SUPPORT_SSP)
1404 return None
1405 except ValueError:
1406 logging.warn('Failed to compare build id in %s with the minimum '
1407 'version that supports server side packaging. Server '
1408 'side packaging is disabled.', image)
1409 return None
1410
1411 ds.stage_artifacts(target, build_id, branch,
1412 artifacts=['autotest_server_package'])
1413 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1414 {'build_target': build_target,
1415 'build_id': build_id})
1416 return '%s/static/%s/%s' % (ds.url(), image,
1417 autotest_server_package_name)