blob: 0b79188e40ff34c85e0e0f034df8573c176447a0 [file] [log] [blame]
Simran Basi431010f2013-09-04 10:42:41 -07001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -07004
5import datetime
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07006import errno
Kevin Cheng3a4a57a2015-09-30 12:09:50 -07007import functools
Simran Basi431010f2013-09-04 10:42:41 -07008import logging
Kevin Cheng018db352015-09-20 02:22:08 -07009import os
Simran Basi431010f2013-09-04 10:42:41 -070010import re
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070011import stat
Dan Shia2872172015-10-31 01:16:51 -070012import sys
Simran Basi431010f2013-09-04 10:42:41 -070013import time
14
15import common
16
Simran Basi9c5d3982016-04-01 18:49:44 -070017from autotest_lib.client.bin import utils as client_utils
Dan Shi49d451f2016-04-19 09:25:01 -070018from autotest_lib.client.common_lib import android_utils
Simran Basi431010f2013-09-04 10:42:41 -070019from autotest_lib.client.common_lib import error
Dan Shi6450e142016-03-11 11:52:20 -080020from autotest_lib.client.common_lib import global_config
Dan Shi225b9042015-11-18 10:25:21 -080021from autotest_lib.client.common_lib.cros import dev_server
Simran Basi431010f2013-09-04 10:42:41 -070022from autotest_lib.client.common_lib.cros import retry
Dan Shi6450e142016-03-11 11:52:20 -080023from autotest_lib.server import afe_utils
Dan Shi225b9042015-11-18 10:25:21 -080024from autotest_lib.server import autoserv_parser
Dan Shia2872172015-10-31 01:16:51 -070025from autotest_lib.server import constants as server_constants
Dan Shi225b9042015-11-18 10:25:21 -080026from autotest_lib.server import utils
Simran Basi5ace6f22016-01-06 17:30:44 -080027from autotest_lib.server.cros import provision
Dan Shi6450e142016-03-11 11:52:20 -080028from autotest_lib.server.cros.dynamic_suite import tools
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070029from autotest_lib.server.cros.dynamic_suite import constants
Simran Basi724b8a52013-09-30 11:19:31 -070030from autotest_lib.server.hosts import abstract_ssh
Kevin Chengc6a645a2015-12-18 11:15:10 -080031from autotest_lib.server.hosts import adb_label
32from autotest_lib.server.hosts import base_label
Kevin Cheng85e864a2015-11-30 11:49:34 -080033from autotest_lib.server.hosts import teststation_host
Simran Basi431010f2013-09-04 10:42:41 -070034
35
Dan Shi6450e142016-03-11 11:52:20 -080036CONFIG = global_config.global_config
37
Dan Shi6ea3e1c2015-10-28 15:19:04 -070038ADB_CMD = 'adb'
39FASTBOOT_CMD = 'fastboot'
Simran Basi431010f2013-09-04 10:42:41 -070040SHELL_CMD = 'shell'
Filipe Brandenburger34363392015-08-13 14:57:45 -070041# Some devices have no serial, then `adb serial` has output such as:
42# (no serial number) device
43# ?????????? device
44DEVICE_NO_SERIAL_MSG = '(no serial number)'
45DEVICE_NO_SERIAL_TAG = '<NO_SERIAL>'
Simran Basi431010f2013-09-04 10:42:41 -070046# Regex to find an adb device. Examples:
47# 0146B5580B01801B device
48# 018e0ecb20c97a62 device
49# 172.22.75.141:5555 device
Kevin Cheng224415e2016-04-22 11:32:10 -070050# localhost:22 device
Alexandru Branciogea380fb2016-04-01 16:01:34 +030051DEVICE_FINDER_REGEX = (r'^(?P<SERIAL>([\w-]+)|((tcp:)?' +
52 '\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}([:]5555)?)|' +
Kevin Cheng224415e2016-04-22 11:32:10 -070053 '((tcp:)?localhost([:]22)?)|' +
Filipe Brandenburger34363392015-08-13 14:57:45 -070054 re.escape(DEVICE_NO_SERIAL_MSG) +
Alexandru Branciogea380fb2016-04-01 16:01:34 +030055 r')[ \t]+(?:device|fastboot)')
Simran Basi431010f2013-09-04 10:42:41 -070056CMD_OUTPUT_PREFIX = 'ADB_CMD_OUTPUT'
57CMD_OUTPUT_REGEX = ('(?P<OUTPUT>[\s\S]*)%s:(?P<EXIT_CODE>\d{1,3})' %
58 CMD_OUTPUT_PREFIX)
Kevin Cheng018db352015-09-20 02:22:08 -070059RELEASE_FILE = 'ro.build.version.release'
Kevin Cheng3a4a57a2015-09-30 12:09:50 -070060BOARD_FILE = 'ro.product.device'
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -070061SDK_FILE = 'ro.build.version.sdk'
Simran Basi242f8de2016-06-08 14:23:43 -070062LOGCAT_FILE_FMT = 'logcat_%s.log'
Simran Basi38f7ddf2015-09-18 12:25:03 -070063TMP_DIR = '/data/local/tmp'
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070064# Regex to pull out file type, perms and symlink. Example:
Kevin Chengaaabd0c2015-11-10 16:05:04 -080065# lrwxrwx--- 1 6 root system 2015-09-12 19:21 blah_link -> ./blah
Kevin Cheng92fe6ae2015-10-21 11:45:34 -070066FILE_INFO_REGEX = '^(?P<TYPE>[dl-])(?P<PERMS>[rwx-]{9})'
67FILE_SYMLINK_REGEX = '^.*-> (?P<SYMLINK>.+)'
68# List of the perm stats indexed by the order they are listed in the example
69# supplied above.
70FILE_PERMS_FLAGS = [stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
71 stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
72 stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
Simran Basi431010f2013-09-04 10:42:41 -070073
Dan Shi6ea3e1c2015-10-28 15:19:04 -070074# Default maximum number of seconds to wait for a device to be down.
75DEFAULT_WAIT_DOWN_TIME_SECONDS = 10
76# Default maximum number of seconds to wait for a device to be up.
Dan Shie4e807b2015-12-10 09:04:03 -080077DEFAULT_WAIT_UP_TIME_SECONDS = 300
78# Maximum number of seconds to wait for a device to be up after it's wiped.
Dan Shi50a412a2016-01-05 10:52:40 -080079WAIT_UP_AFTER_WIPE_TIME_SECONDS = 1200
Simran Basi431010f2013-09-04 10:42:41 -070080
Dan Shi7075f552016-04-21 15:42:41 -070081# Default timeout for retrying adb/fastboot command.
Dan Shi1cbf3812016-07-18 23:06:38 +000082DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS = 10
Dan Shi7075f552016-04-21 15:42:41 -070083
Dan Shia2872172015-10-31 01:16:51 -070084OS_TYPE_ANDROID = 'android'
85OS_TYPE_BRILLO = 'brillo'
86
Dan Shie234dea2016-01-20 17:15:17 -080087# Regex to parse build name to get the detailed build information.
Dan Shi6450e142016-03-11 11:52:20 -080088BUILD_REGEX = ('(?P<BRANCH>([^/]+))/(?P<BUILD_TARGET>([^/]+))-'
Dan Shie234dea2016-01-20 17:15:17 -080089 '(?P<BUILD_TYPE>([^/]+))/(?P<BUILD_ID>([^/]+))')
Dan Shia2872172015-10-31 01:16:51 -070090# Regex to parse devserver url to get the detailed build information. Sample
91# url: http://$devserver:8080/static/branch/target/build_id
Dan Shie234dea2016-01-20 17:15:17 -080092DEVSERVER_URL_REGEX = '.*/%s/*' % BUILD_REGEX
Dan Shia2872172015-10-31 01:16:51 -070093
Dan Shi6450e142016-03-11 11:52:20 -080094ANDROID_IMAGE_FILE_FMT = '%(build_target)s-img-%(build_id)s.zip'
Dan Shi49d451f2016-04-19 09:25:01 -070095
Dan Shiab999722015-12-04 14:27:08 -080096BRILLO_VENDOR_PARTITIONS_FILE_FMT = (
Dan Shi6450e142016-03-11 11:52:20 -080097 '%(build_target)s-vendor_partitions-%(build_id)s.zip')
98AUTOTEST_SERVER_PACKAGE_FILE_FMT = (
99 '%(build_target)s-autotest_server_package-%(build_id)s.tar.bz2')
Simran Basi9228a6f2016-03-29 12:03:37 -0700100ADB_DEVICE_PREFIXES = ['product:', 'model:', 'device:']
Dan Shia2872172015-10-31 01:16:51 -0700101
Simran Basi9c5d3982016-04-01 18:49:44 -0700102# Map of product names to build target name.
103PRODUCT_TARGET_MAP = {'dragon' : 'ryu',
104 'flo' : 'razor',
105 'flo_lte' : 'razorg',
106 'gm4g_sprout' : 'seed_l8150',
107 'flounder' : 'volantis',
108 'flounder_lte' : 'volantisg'}
109
Dan Shiab999722015-12-04 14:27:08 -0800110# Command to provision a Brillo device.
111# os_image_dir: The full path of the directory that contains all the Android image
112# files (from the image zip file).
113# vendor_partition_dir: The full path of the directory that contains all the
114# Brillo vendor partitions, and provision-device script.
115BRILLO_PROVISION_CMD = (
Simran Basi7e52c622016-01-05 15:43:51 -0800116 'sudo ANDROID_PROVISION_OS_PARTITIONS=%(os_image_dir)s '
Dan Shiab999722015-12-04 14:27:08 -0800117 'ANDROID_PROVISION_VENDOR_PARTITIONS=%(vendor_partition_dir)s '
118 '%(vendor_partition_dir)s/provision-device')
Dan Shia2872172015-10-31 01:16:51 -0700119
Dan Shi12a4f662016-05-10 14:49:42 -0700120# Default timeout in minutes for fastboot commands.
121DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN = 10
122
David Purselle01548b2016-05-11 10:00:42 -0700123# Default permissions for files/dirs copied from the device.
124_DEFAULT_FILE_PERMS = 0o600
125_DEFAULT_DIR_PERMS = 0o700
126
Dan Shi626d5412016-05-16 16:05:13 -0700127# Constants for getprop return value for a given property.
128PROPERTY_VALUE_TRUE = '1'
129
Dan Shic716ac62016-05-24 16:47:57 -0700130# Timeout used for retrying installing apk. After reinstall apk failed, we try
131# to reboot the device and try again.
132APK_INSTALL_TIMEOUT_MIN = 5
133
Bryan Lewandowski68646b62016-07-12 10:24:57 -0700134# Directory where (non-Brillo) Android stores tombstone crash logs.
135ANDROID_TOMBSTONE_CRASH_LOG_DIR = '/data/tombstones'
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -0700136# Directory where Brillo stores crash logs for native (non-Java) crashes.
137BRILLO_NATIVE_CRASH_LOG_DIR = '/data/misc/crash_reporter/crash'
138
Dan Shi35a39be2016-07-25 00:20:31 -0700139# A specific string value to return when a timeout has occurred.
140TIMEOUT_MSG = 'TIMEOUT_OCCURRED'
141
Dan Shia2872172015-10-31 01:16:51 -0700142class AndroidInstallError(error.InstallError):
143 """Generic error for Android installation related exceptions."""
144
145
Simran Basi724b8a52013-09-30 11:19:31 -0700146class ADBHost(abstract_ssh.AbstractSSHHost):
Simran Basi431010f2013-09-04 10:42:41 -0700147 """This class represents a host running an ADB server."""
148
Simran Basi5ace6f22016-01-06 17:30:44 -0800149 VERSION_PREFIX = provision.ANDROID_BUILD_VERSION_PREFIX
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700150 _LABEL_FUNCTIONS = []
151 _DETECTABLE_LABELS = []
152 label_decorator = functools.partial(utils.add_label_detector,
153 _LABEL_FUNCTIONS,
154 _DETECTABLE_LABELS)
155
Dan Shi225b9042015-11-18 10:25:21 -0800156 _parser = autoserv_parser.autoserv_parser
Simran Basi431010f2013-09-04 10:42:41 -0700157
Dan Shi6450e142016-03-11 11:52:20 -0800158 # Minimum build id that supports server side packaging. Older builds may
159 # not have server side package built or with Autotest code change to support
160 # server-side packaging.
161 MIN_VERSION_SUPPORT_SSP = CONFIG.get_config_value(
162 'AUTOSERV', 'min_launch_control_build_id_support_ssp', type=int)
163
beeps46dadc92013-11-07 14:07:10 -0800164 @staticmethod
165 def check_host(host, timeout=10):
166 """
167 Check if the given host is an adb host.
168
Simran Basi14622bb2015-11-25 13:23:40 -0800169 If SSH connectivity can't be established, check_host will try to use
170 user 'adb' as well. If SSH connectivity still can't be established
171 then the original SSH user is restored.
172
beeps46dadc92013-11-07 14:07:10 -0800173 @param host: An ssh host representing a device.
174 @param timeout: The timeout for the run command.
175
176
177 @return: True if the host device has adb.
178
179 @raises AutoservRunError: If the command failed.
180 @raises AutoservSSHTimeout: Ssh connection has timed out.
181 """
Dan Shi64e130f2015-12-16 14:45:44 -0800182 # host object may not have user attribute if it's a LocalHost object.
183 current_user = host.user if hasattr(host, 'user') else None
beeps46dadc92013-11-07 14:07:10 -0800184 try:
Simran Basi14622bb2015-11-25 13:23:40 -0800185 if not (host.hostname == 'localhost' or
186 host.verify_ssh_user_access()):
Simran Basi1621c632015-10-14 12:22:23 -0700187 host.user = 'adb'
Simran Basi933c8af2015-04-29 14:05:07 -0700188 result = host.run(
Dan Shia2872172015-10-31 01:16:51 -0700189 'test -f %s' % server_constants.ANDROID_TESTER_FILEFLAG,
Simran Basi933c8af2015-04-29 14:05:07 -0700190 timeout=timeout)
Justin Giorgi6ee64532016-08-10 11:32:04 -0700191 except (error.GenericHostRunError, error.AutoservSSHTimeout):
Dan Shi64e130f2015-12-16 14:45:44 -0800192 if current_user is not None:
193 host.user = current_user
beeps46dadc92013-11-07 14:07:10 -0800194 return False
195 return result.exit_status == 0
196
197
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700198 # TODO(garnold) Remove the 'serials' argument once all clients are made to
199 # not use it.
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700200 def _initialize(self, hostname='localhost', serials=None,
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700201 adb_serial=None, fastboot_serial=None,
Simran Basi9228a6f2016-03-29 12:03:37 -0700202 teststation=None, *args, **dargs):
Simran Basi431010f2013-09-04 10:42:41 -0700203 """Initialize an ADB Host.
204
205 This will create an ADB Host. Hostname should always refer to the
Kevin Chengd19e6c62015-10-28 16:39:39 -0700206 test station connected to an Android DUT. This will be the DUT
207 to test with. If there are multiple, serial must be specified or an
Simran Basi9228a6f2016-03-29 12:03:37 -0700208 exception will be raised.
Simran Basi431010f2013-09-04 10:42:41 -0700209
210 @param hostname: Hostname of the machine running ADB.
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700211 @param serials: DEPRECATED (to be removed)
212 @param adb_serial: An ADB device serial. If None, assume a single
213 device is attached (and fail otherwise).
214 @param fastboot_serial: A fastboot device serial. If None, defaults to
215 the ADB serial (or assumes a single device if
216 the latter is None).
Kevin Cheng549beb42015-11-18 11:42:25 -0800217 @param teststation: The teststation object ADBHost should use.
Simran Basi431010f2013-09-04 10:42:41 -0700218 """
Simran Basi1bf60eb2015-12-01 16:39:29 -0800219 # Sets up the is_client_install_supported field.
220 super(ADBHost, self)._initialize(hostname=hostname,
221 is_client_install_supported=False,
222 *args, **dargs)
Kevin Cheng85e864a2015-11-30 11:49:34 -0800223
Kevin Chengd19e6c62015-10-28 16:39:39 -0700224 self.tmp_dirs = []
Kevin Chengc6a645a2015-12-18 11:15:10 -0800225 self.labels = base_label.LabelRetriever(adb_label.ADB_LABELS)
Kevin Cheng05ae2a42016-06-06 10:12:48 -0700226 adb_serial = adb_serial or self._afe_host.attributes.get('serials')
227 fastboot_serial = (fastboot_serial or
228 self._afe_host.attributes.get('fastboot_serial'))
229
Dan Shi50a412a2016-01-05 10:52:40 -0800230 self.adb_serial = adb_serial
Dan Shi3a011ed2016-04-26 12:26:53 -0700231 if adb_serial:
232 adb_prefix = any(adb_serial.startswith(p)
233 for p in ADB_DEVICE_PREFIXES)
234 self.fastboot_serial = (fastboot_serial or
235 ('tcp:%s' % adb_serial.split(':')[0] if
236 ':' in adb_serial and not adb_prefix else adb_serial))
237 self._use_tcpip = ':' in adb_serial and not adb_prefix
238 else:
239 self.fastboot_serial = fastboot_serial or adb_serial
240 self._use_tcpip = False
Kevin Cheng85e864a2015-11-30 11:49:34 -0800241 self.teststation = (teststation if teststation
Justin Giorgi5208eaa2016-07-02 20:12:12 -0700242 else teststation_host.create_teststationhost(
243 hostname=hostname,
244 user=self.user,
245 password=self.password,
246 port=self.port
247 ))
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700248
249 msg ='Initializing ADB device on host: %s' % hostname
Dan Shi50a412a2016-01-05 10:52:40 -0800250 if self.adb_serial:
251 msg += ', ADB serial: %s' % self.adb_serial
252 if self.fastboot_serial:
253 msg += ', fastboot serial: %s' % self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700254 logging.debug(msg)
255
Dan Shiab999722015-12-04 14:27:08 -0800256 self._os_type = None
257
Simran Basi431010f2013-09-04 10:42:41 -0700258
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700259 def _connect_over_tcpip_as_needed(self):
260 """Connect to the ADB device over TCP/IP if so configured."""
Simran Basi9228a6f2016-03-29 12:03:37 -0700261 if not self._use_tcpip:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700262 return
263 logging.debug('Connecting to device over TCP/IP')
Simran Basi9228a6f2016-03-29 12:03:37 -0700264 self.adb_run('connect %s' % self.adb_serial)
Simran Basi431010f2013-09-04 10:42:41 -0700265
266
Roshan Pius4d7540c2015-12-16 13:30:32 -0800267 def _restart_adbd_with_root_permissions(self):
268 """Restarts the adb daemon with root permissions."""
Justin Giorgi6ee64532016-08-10 11:32:04 -0700269 @retry.retry(error.GenericHostRunError, timeout_min=20/60.0,
270 delay_sec=1)
Dan Shi922de302016-04-22 15:19:18 -0700271 def run_adb_root():
272 """Run command `adb root`."""
273 self.adb_run('root')
274
275 # adb command may flake with error "device not found". Retry the root
276 # command to reduce the chance of flake.
277 run_adb_root()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800278 # TODO(ralphnathan): Remove this sleep once b/19749057 is resolved.
279 time.sleep(1)
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300280 self._connect_over_tcpip_as_needed()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800281 self.adb_run('wait-for-device')
282
283
Simran Basi9228a6f2016-03-29 12:03:37 -0700284 def _set_tcp_port(self):
285 """Ensure the device remains in tcp/ip mode after a reboot."""
286 if not self._use_tcpip:
287 return
288 port = self.adb_serial.split(':')[-1]
289 self.run('setprop persist.adb.tcp.port %s' % port)
290
291
Roshan Pius4d7540c2015-12-16 13:30:32 -0800292 def _reset_adbd_connection(self):
293 """Resets adbd connection to the device after a reboot/initialization"""
Roshan Pius4d7540c2015-12-16 13:30:32 -0800294 self._connect_over_tcpip_as_needed()
Simran Basi9228a6f2016-03-29 12:03:37 -0700295 self._restart_adbd_with_root_permissions()
296 self._set_tcp_port()
Roshan Pius4d7540c2015-12-16 13:30:32 -0800297
298
Kevin Cheng85e864a2015-11-30 11:49:34 -0800299 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800300 def adb_run(self, command, **kwargs):
Simran Basi431010f2013-09-04 10:42:41 -0700301 """Runs an adb command.
302
Kevin Chengd19e6c62015-10-28 16:39:39 -0700303 This command will launch on the test station.
Simran Basi431010f2013-09-04 10:42:41 -0700304
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700305 Refer to _device_run method for docstring for parameters.
306 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800307 return self._device_run(ADB_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700308
309
Kevin Cheng85e864a2015-11-30 11:49:34 -0800310 # pylint: disable=missing-docstring
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800311 def fastboot_run(self, command, **kwargs):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700312 """Runs an fastboot command.
313
Kevin Chengd19e6c62015-10-28 16:39:39 -0700314 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700315
316 Refer to _device_run method for docstring for parameters.
317 """
Gilad Arnoldf17f6fd2015-11-12 14:44:07 -0800318 return self._device_run(FASTBOOT_CMD, command, **kwargs)
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700319
320
Dan Shi12a4f662016-05-10 14:49:42 -0700321 # pylint: disable=missing-docstring
Justin Giorgi6ee64532016-08-10 11:32:04 -0700322 @retry.retry(error.GenericHostRunError,
Dan Shi12a4f662016-05-10 14:49:42 -0700323 timeout_min=DEFAULT_FASTBOOT_RETRY_TIMEOUT_MIN)
324 def _fastboot_run_with_retry(self, command, **kwargs):
325 """Runs an fastboot command with retry.
326
327 This command will launch on the test station.
328
329 Refer to _device_run method for docstring for parameters.
330 """
331 return self.fastboot_run(command, **kwargs)
332
333
Simran Basie6c4f142016-06-23 17:10:04 -0700334 def _log_adb_pid(self):
335 """Log the pid of adb server.
336
337 adb's server is known to have bugs and randomly restart. BY logging
338 the server's pid it will allow us to better debug random adb failures.
339 """
340 adb_pid = self.teststation.run('pgrep -f "adb.*server"')
341 logging.debug('ADB Server PID: %s', adb_pid.stdout)
342
343
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700344 def _device_run(self, function, command, shell=False,
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700345 timeout=3600, ignore_status=False, ignore_timeout=False,
346 stdout=utils.TEE_TO_LOGS, stderr=utils.TEE_TO_LOGS,
347 connect_timeout=30, options='', stdin=None, verbose=True,
348 require_sudo=False, args=()):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700349 """Runs a command named `function` on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700350
Kevin Chengd19e6c62015-10-28 16:39:39 -0700351 This command will launch on the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700352
Simran Basi431010f2013-09-04 10:42:41 -0700353 @param command: Command to run.
354 @param shell: If true the command runs in the adb shell otherwise if
355 False it will be passed directly to adb. For example
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700356 reboot with shell=False will call 'adb reboot'. This
357 option only applies to function adb.
Simran Basi431010f2013-09-04 10:42:41 -0700358 @param timeout: Time limit in seconds before attempting to
359 kill the running process. The run() function
360 will take a few seconds longer than 'timeout'
361 to complete if it has to kill the process.
362 @param ignore_status: Do not raise an exception, no matter
363 what the exit code of the command is.
364 @param ignore_timeout: Bool True if command timeouts should be
365 ignored. Will return None on command timeout.
366 @param stdout: Redirect stdout.
367 @param stderr: Redirect stderr.
368 @param connect_timeout: Connection timeout (in seconds)
369 @param options: String with additional ssh command options
370 @param stdin: Stdin to pass (a string) to the executed command
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700371 @param require_sudo: True to require sudo to run the command. Default is
372 False.
Simran Basi431010f2013-09-04 10:42:41 -0700373 @param args: Sequence of strings to pass as arguments to command by
374 quoting them in " and escaping their contents if
375 necessary.
376
377 @returns a CMDResult object.
Simran Basi431010f2013-09-04 10:42:41 -0700378 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700379 if function == ADB_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800380 serial = self.adb_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700381 elif function == FASTBOOT_CMD:
Dan Shi50a412a2016-01-05 10:52:40 -0800382 serial = self.fastboot_serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700383 else:
384 raise NotImplementedError('Mode %s is not supported' % function)
385
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700386 if function != ADB_CMD and shell:
387 raise error.CmdError('shell option is only applicable to `adb`.')
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700388
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700389 cmd = '%s%s ' % ('sudo -n ' if require_sudo else '', function)
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700390
391 if serial:
392 cmd += '-s %s ' % serial
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700393
Simran Basi431010f2013-09-04 10:42:41 -0700394 if shell:
395 cmd += '%s ' % SHELL_CMD
396 cmd += command
397
Simran Basie6c4f142016-06-23 17:10:04 -0700398 self._log_adb_pid()
399
Roshan Pius58e5dd32015-10-16 15:16:42 -0700400 if verbose:
401 logging.debug('Command: %s', cmd)
Simran Basi431010f2013-09-04 10:42:41 -0700402
Kevin Cheng85e864a2015-11-30 11:49:34 -0800403 return self.teststation.run(cmd, timeout=timeout,
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400404 ignore_status=ignore_status,
405 ignore_timeout=ignore_timeout, stdout_tee=stdout,
406 stderr_tee=stderr, options=options, stdin=stdin,
407 connect_timeout=connect_timeout, args=args)
Simran Basi431010f2013-09-04 10:42:41 -0700408
409
Dan Shi8c51bda2016-05-26 12:21:02 -0700410 def _run_output_with_retry(self, cmd):
411 """Call run_output method for the given command with retry.
412
Dan Shi68094122016-06-10 14:29:06 -0700413 adb command can be flaky some time, and the command may fail or return
414 empty string. It may take several retries until a value can be returned.
Dan Shi8c51bda2016-05-26 12:21:02 -0700415
416 @param cmd: The command to run.
417
418 @return: Return value from the command after retry.
419 """
420 try:
421 return client_utils.poll_for_condition(
Dan Shi68094122016-06-10 14:29:06 -0700422 lambda: self.run_output(cmd, ignore_status=True),
Dan Shi8c51bda2016-05-26 12:21:02 -0700423 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS,
424 sleep_interval=0.5,
425 desc='Get return value for command `%s`' % cmd)
426 except client_utils.TimeoutError:
427 return ''
428
429
Dan Shie234dea2016-01-20 17:15:17 -0800430 def get_board_name(self):
431 """Get the name of the board, e.g., shamu, dragonboard etc.
432 """
Simran Basi9c5d3982016-04-01 18:49:44 -0700433 product = self.run_output('getprop %s' % BOARD_FILE)
434 return PRODUCT_TARGET_MAP.get(product, product)
Dan Shie234dea2016-01-20 17:15:17 -0800435
436
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700437 @label_decorator()
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700438 def get_board(self):
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700439 """Determine the correct board label for the device.
440
441 @returns a string representing this device's board.
442 """
Dan Shie234dea2016-01-20 17:15:17 -0800443 board = self.get_board_name()
Kevin Cheng3a4a57a2015-09-30 12:09:50 -0700444 board_os = self.get_os_type()
Kevin Cheng49f7b812015-12-15 15:24:23 -0800445 return constants.BOARD_PREFIX + '-'.join([board_os, board])
Christopher Wiley8e6b08e2013-10-11 12:34:26 -0700446
447
Christopher Wiley08849d52013-11-22 08:57:58 -0800448 def job_start(self):
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700449 """Overload of parent which intentionally doesn't log certain files.
Dan Shi2d279cf2016-05-27 22:06:10 +0000450
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700451 The parent implementation attempts to log certain Linux files, such as
452 /var/log, which do not exist on Android, thus there is no call to the
453 parent's job_start(). The sync call is made so that logcat logs can be
454 approximately matched to server logs.
Dan Shi2d279cf2016-05-27 22:06:10 +0000455 """
Justin Giorgidd05a942016-07-05 20:53:12 -0700456 # Try resetting the ADB daemon on the device, however if we are
457 # creating the host to do a repair job, the device maybe inaccesible
458 # via ADB.
459 try:
460 self._reset_adbd_connection()
Justin Giorgi6ee64532016-08-10 11:32:04 -0700461 except error.GenericHostRunError as e:
Justin Giorgidd05a942016-07-05 20:53:12 -0700462 logging.error('Unable to reset the device adb daemon connection: '
463 '%s.', e)
464
Simran Basid6b49792016-06-07 17:22:03 -0700465 if self.is_up():
466 self._sync_time()
Bryan Lewandowski8c96bb22016-07-19 12:56:03 -0700467 self._enable_native_crash_logging()
Christopher Wiley08849d52013-11-22 08:57:58 -0800468
469
Simran Basi431010f2013-09-04 10:42:41 -0700470 def run(self, command, timeout=3600, ignore_status=False,
471 ignore_timeout=False, stdout_tee=utils.TEE_TO_LOGS,
472 stderr_tee=utils.TEE_TO_LOGS, connect_timeout=30, options='',
Roshan Pius58e5dd32015-10-16 15:16:42 -0700473 stdin=None, verbose=True, args=()):
Simran Basi431010f2013-09-04 10:42:41 -0700474 """Run a command on the adb device.
475
476 The command given will be ran directly on the adb device; for example
477 'ls' will be ran as: 'abd shell ls'
478
479 @param command: The command line string.
480 @param timeout: Time limit in seconds before attempting to
481 kill the running process. The run() function
482 will take a few seconds longer than 'timeout'
483 to complete if it has to kill the process.
484 @param ignore_status: Do not raise an exception, no matter
485 what the exit code of the command is.
486 @param ignore_timeout: Bool True if command timeouts should be
487 ignored. Will return None on command timeout.
488 @param stdout_tee: Redirect stdout.
489 @param stderr_tee: Redirect stderr.
490 @param connect_timeout: Connection timeout (in seconds).
491 @param options: String with additional ssh command options.
492 @param stdin: Stdin to pass (a string) to the executed command
493 @param args: Sequence of strings to pass as arguments to command by
494 quoting them in " and escaping their contents if
495 necessary.
496
497 @returns A CMDResult object or None if the call timed out and
498 ignore_timeout is True.
499
500 @raises AutoservRunError: If the command failed.
501 @raises AutoservSSHTimeout: Ssh connection has timed out.
Simran Basi431010f2013-09-04 10:42:41 -0700502 """
Filipe Brandenburger68a80072015-07-14 10:39:33 -0700503 command = ('"%s; echo %s:\$?"' %
Dan Shi35a39be2016-07-25 00:20:31 -0700504 (utils.sh_escape(command), CMD_OUTPUT_PREFIX))
Simran Basi431010f2013-09-04 10:42:41 -0700505
Dan Shi35a39be2016-07-25 00:20:31 -0700506 def _run():
507 """Run the command and try to parse the exit code.
508 """
509 result = self.adb_run(
510 command, shell=True, timeout=timeout,
511 ignore_status=ignore_status, ignore_timeout=ignore_timeout,
512 stdout=stdout_tee, stderr=stderr_tee,
513 connect_timeout=connect_timeout, options=options,
514 stdin=stdin, verbose=verbose, args=args)
515 if not result:
516 # In case of timeouts. Set the return to a specific string
517 # value. That way the caller of poll_for_condition knows
518 # a timeout occurs and should return None. Return None here will
519 # lead to the command to be retried.
520 return TIMEOUT_MSG
521 parse_output = re.match(CMD_OUTPUT_REGEX, result.stdout)
522 if not parse_output and not ignore_status:
523 logging.error('Failed to parse the exit code for command: `%s`.'
524 ' result: `%s`', command, result.stdout)
525 return None
526 elif parse_output:
527 result.stdout = parse_output.group('OUTPUT')
528 result.exit_status = int(parse_output.group('EXIT_CODE'))
529 if result.exit_status != 0 and not ignore_status:
530 raise error.AutoservRunError(command, result)
531 return result
532
533 result = client_utils.poll_for_condition(
534 lambda: _run(),
535 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS,
536 sleep_interval=0.5,
537 desc='Run command `%s`' % command)
538 return None if result == TIMEOUT_MSG else result
Simran Basi431010f2013-09-04 10:42:41 -0700539
540
Dan Shicf7d2562016-06-16 14:08:23 -0700541 def check_boot_to_adb_complete(self, exception_type=error.TimeoutException):
542 """Check if the device has finished booting and accessible by adb.
543
544 @param exception_type: Type of exception to raise. Default is set to
545 error.TimeoutException for retry.
546
547 @raise exception_type: If the device has not finished booting yet, raise
548 an exception of type `exception_type`.
549 """
550 bootcomplete = self._run_output_with_retry('getprop dev.bootcomplete')
551 if bootcomplete != PROPERTY_VALUE_TRUE:
552 raise exception_type('dev.bootcomplete is %s.' % bootcomplete)
553 if self.get_os_type() == OS_TYPE_ANDROID:
554 boot_completed = self._run_output_with_retry(
555 'getprop sys.boot_completed')
556 if boot_completed != PROPERTY_VALUE_TRUE:
557 raise exception_type('sys.boot_completed is %s.' %
558 boot_completed)
559
560
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700561 def wait_up(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS, command=ADB_CMD):
562 """Wait until the remote host is up or the timeout expires.
Simran Basi431010f2013-09-04 10:42:41 -0700563
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700564 Overrides wait_down from AbstractSSHHost.
Simran Basi431010f2013-09-04 10:42:41 -0700565
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700566 @param timeout: Time limit in seconds before returning even if the host
567 is not up.
568 @param command: The command used to test if a device is up, i.e.,
569 accessible by the given command. Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700570
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700571 @returns True if the host was found to be up before the timeout expires,
572 False otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700573 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700574 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
575 delay_sec=1)
576 def _wait_up():
577 if not self.is_up(command=command):
578 raise error.TimeoutException('Device is still down.')
Dan Shicf7d2562016-06-16 14:08:23 -0700579 if command == ADB_CMD:
580 self.check_boot_to_adb_complete()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700581 return True
582
583 try:
584 _wait_up()
585 logging.debug('Host %s is now up, and can be accessed by %s.',
586 self.hostname, command)
587 return True
588 except error.TimeoutException:
589 logging.debug('Host %s is still down after waiting %d seconds',
590 self.hostname, timeout)
591 return False
Simran Basi431010f2013-09-04 10:42:41 -0700592
593
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700594 def wait_down(self, timeout=DEFAULT_WAIT_DOWN_TIME_SECONDS,
Justin Giorgiea3de262016-08-08 15:28:57 -0700595 warning_timer=None, old_boot_id=None, command=ADB_CMD,
596 boot_id=None):
597 """Wait till the host goes down.
598
599 Return when the host is down (not accessible via the command) OR when
600 the device's boot_id changes (if a boot_id was provided).
Simran Basi431010f2013-09-04 10:42:41 -0700601
602 Overrides wait_down from AbstractSSHHost.
603
604 @param timeout: Time in seconds to wait for the host to go down.
605 @param warning_timer: Time limit in seconds that will generate
606 a warning if the host is not down yet.
607 Currently ignored.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700608 @param old_boot_id: Not applicable for adb_host.
609 @param command: `adb`, test if the device can be accessed by adb
610 command, or `fastboot`, test if the device can be accessed by
611 fastboot command. Default is set to `adb`.
Justin Giorgiea3de262016-08-08 15:28:57 -0700612 @param boot_id: UUID of previous boot (consider the device down when the
613 boot_id changes from this value). Ignored if None.
Simran Basi431010f2013-09-04 10:42:41 -0700614
615 @returns True if the device goes down before the timeout, False
616 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700617 """
618 @retry.retry(error.TimeoutException, timeout_min=timeout/60.0,
619 delay_sec=1)
620 def _wait_down():
Justin Giorgiea3de262016-08-08 15:28:57 -0700621 up = self.is_up(command=command)
622 if not up:
623 return True
624 if boot_id:
625 try:
626 new_boot_id = self.get_boot_id()
627 if new_boot_id != boot_id:
628 return True
Justin Giorgif6ffe0c2016-08-16 10:12:47 -0700629 except error.GenericHostRunError:
Justin Giorgiea3de262016-08-08 15:28:57 -0700630 pass
631 raise error.TimeoutException('Device is still up.')
Simran Basi431010f2013-09-04 10:42:41 -0700632
633 try:
634 _wait_down()
635 logging.debug('Host %s is now down', self.hostname)
636 return True
637 except error.TimeoutException:
638 logging.debug('Host %s is still up after waiting %d seconds',
639 self.hostname, timeout)
640 return False
641
642
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700643 def reboot(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700644 """Reboot the android device via adb.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700645
646 @raises AutoservRebootError if reboot failed.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700647 """
648 # Not calling super.reboot() as we want to reboot the ADB device not
Kevin Chengd19e6c62015-10-28 16:39:39 -0700649 # the test station we are running ADB on.
Justin Giorgiea3de262016-08-08 15:28:57 -0700650 boot_id = self.get_boot_id()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700651 self.adb_run('reboot', timeout=10, ignore_timeout=True)
Justin Giorgiea3de262016-08-08 15:28:57 -0700652 if not self.wait_down(boot_id=boot_id):
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700653 raise error.AutoservRebootError(
654 'ADB Device is still up after reboot')
655 if not self.wait_up():
656 raise error.AutoservRebootError(
657 'ADB Device failed to return from reboot.')
Roshan Pius4d7540c2015-12-16 13:30:32 -0800658 self._reset_adbd_connection()
Roshan Pius50c1f9c2015-11-30 11:37:49 -0800659
660
Alexandru Branciog969ff7c2016-03-30 14:07:15 +0300661 def fastboot_reboot(self):
662 """Do a fastboot reboot to go back to adb.
663
664 @raises AutoservRebootError if reboot failed.
665 """
666 self.fastboot_run('reboot')
667 if not self.wait_down(command=FASTBOOT_CMD):
668 raise error.AutoservRebootError(
669 'Device is still in fastboot mode after reboot')
670 if not self.wait_up():
671 raise error.AutoservRebootError(
672 'Device failed to boot to adb after fastboot reboot.')
673 self._reset_adbd_connection()
674
675
Ralph Nathanb45eb672015-11-18 20:04:39 -0800676 def remount(self):
677 """Remounts paritions on the device read-write.
678
679 Specifically, the /system, /vendor (if present) and /oem (if present)
680 partitions on the device are remounted read-write.
681 """
Ralph Nathanb45eb672015-11-18 20:04:39 -0800682 self.adb_run('remount')
683
684
Kevin Cheng549beb42015-11-18 11:42:25 -0800685 @staticmethod
686 def parse_device_serials(devices_output):
687 """Return a list of parsed serials from the output.
688
689 @param devices_output: Output from either an adb or fastboot command.
690
691 @returns List of device serials
692 """
693 devices = []
694 for line in devices_output.splitlines():
695 match = re.search(DEVICE_FINDER_REGEX, line)
696 if match:
697 serial = match.group('SERIAL')
698 if serial == DEVICE_NO_SERIAL_MSG or re.match(r'^\?+$', serial):
699 serial = DEVICE_NO_SERIAL_TAG
700 logging.debug('Found Device: %s', serial)
701 devices.append(serial)
702 return devices
703
704
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700705 def _get_devices(self, use_adb):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700706 """Get a list of devices currently attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700707
708 @params use_adb: True to get adb accessible devices. Set to False to
709 get fastboot accessible devices.
710
Kevin Chengd19e6c62015-10-28 16:39:39 -0700711 @returns a list of devices attached to the test station.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700712 """
713 if use_adb:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300714 result = self.adb_run('devices').stdout
715 if self.adb_serial and self.adb_serial not in result:
716 self._connect_over_tcpip_as_needed()
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700717 else:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300718 result = self.fastboot_run('devices').stdout
719 if (self.fastboot_serial and
720 self.fastboot_serial not in result):
721 # fastboot devices won't list the devices using TCP
722 try:
723 if 'product' in self.fastboot_run('getvar product',
724 timeout=2).stderr:
725 result += '\n%s\tfastboot' % self.fastboot_serial
Kevin Chengcfcb2cf2016-04-13 10:04:36 -0700726 # The main reason we do a general Exception catch here instead
727 # of setting ignore_timeout/status to True is because even when
728 # the fastboot process has been nuked, it still stays around and
729 # so bgjob wants to warn us of this and tries to read the
730 # /proc/<pid>/stack file which then promptly returns an
731 # 'Operation not permitted' error since we're running as moblab
732 # and we don't have permission to read those files.
733 except Exception:
Alexandru Branciogea380fb2016-04-01 16:01:34 +0300734 pass
735 return self.parse_device_serials(result)
Simran Basi431010f2013-09-04 10:42:41 -0700736
737
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700738 def adb_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700739 """Get a list of devices currently attached to the test station and
740 accessible with the adb command."""
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700741 devices = self._get_devices(use_adb=True)
Dan Shi50a412a2016-01-05 10:52:40 -0800742 if self.adb_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700743 raise error.AutoservError(
744 'Not given ADB serial but multiple devices detected')
745 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700746
747
748 def fastboot_devices(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700749 """Get a list of devices currently attached to the test station and
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700750 accessible by fastboot command.
751 """
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700752 devices = self._get_devices(use_adb=False)
Dan Shi50a412a2016-01-05 10:52:40 -0800753 if self.fastboot_serial is None and len(devices) > 1:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700754 raise error.AutoservError(
755 'Not given fastboot serial but multiple devices detected')
756 return devices
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700757
758
759 def is_up(self, timeout=0, command=ADB_CMD):
760 """Determine if the specified adb device is up with expected mode.
Simran Basi431010f2013-09-04 10:42:41 -0700761
762 @param timeout: Not currently used.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700763 @param command: `adb`, the device can be accessed by adb command,
764 or `fastboot`, the device can be accessed by fastboot command.
765 Default is set to `adb`.
Simran Basi431010f2013-09-04 10:42:41 -0700766
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700767 @returns True if the device is detectable by given command, False
768 otherwise.
Simran Basi431010f2013-09-04 10:42:41 -0700769
770 """
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700771 if command == ADB_CMD:
772 devices = self.adb_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800773 serial = self.adb_serial
Kris Rambishde8f9d12015-12-16 12:42:41 -0800774 # ADB has a device state, if the device is not online, no
775 # subsequent ADB command will complete.
Dan Shi6450e142016-03-11 11:52:20 -0800776 # DUT with single device connected may not have adb_serial set.
777 # Therefore, skip checking if serial is in the list of adb devices
778 # if self.adb_serial is not set.
779 if (serial and serial not in devices) or not self.is_device_ready():
Kris Rambishde8f9d12015-12-16 12:42:41 -0800780 logging.debug('Waiting for device to enter the ready state.')
781 return False
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700782 elif command == FASTBOOT_CMD:
783 devices = self.fastboot_devices()
Dan Shi50a412a2016-01-05 10:52:40 -0800784 serial = self.fastboot_serial
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700785 else:
Gilad Arnold2cfa5522015-10-30 13:58:02 -0700786 raise NotImplementedError('Mode %s is not supported' % command)
787
788 return bool(devices and (not serial or serial in devices))
Simran Basi431010f2013-09-04 10:42:41 -0700789
790
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700791 def stop_loggers(self):
792 """Inherited stop_loggers function.
793
794 Calls parent function and captures logcat, since the end of the run
795 is logically the end/stop of the logcat log.
796 """
797 super(ADBHost, self).stop_loggers()
798 # Record logcat log to a temporary file on the teststation.
799 tmp_dir = self.teststation.get_tmp_dir()
Simran Basi242f8de2016-06-08 14:23:43 -0700800 logcat_filename = LOGCAT_FILE_FMT % self.adb_serial
801 teststation_filename = os.path.join(tmp_dir, logcat_filename)
Bryan Lewandowskiea4a06d2016-06-03 11:25:54 -0700802 try:
803 self.adb_run('logcat -v time -d > "%s"' % (teststation_filename),
804 timeout=20)
Justin Giorgi6ee64532016-08-10 11:32:04 -0700805 except (error.GenericHostRunError, error.AutoservSSHTimeout,
806 error.CmdTimeoutError):
Bryan Lewandowskiea4a06d2016-06-03 11:25:54 -0700807 return
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700808 # Copy-back the log to the drone's results directory.
Simran Basi242f8de2016-06-08 14:23:43 -0700809 results_logcat_filename = os.path.join(self.job.resultdir,
810 logcat_filename)
811 self.teststation.get_file(teststation_filename,
812 results_logcat_filename)
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700813 try:
814 self.teststation.run('rm -rf %s' % tmp_dir)
Justin Giorgi6ee64532016-08-10 11:32:04 -0700815 except (error.GenericHostRunError, error.AutoservSSHTimeout) as e:
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700816 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
817
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -0700818 self._collect_crash_logs()
819
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -0700820
Simran Basi431010f2013-09-04 10:42:41 -0700821 def close(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700822 """Close the ADBHost object.
Simran Basi431010f2013-09-04 10:42:41 -0700823
824 Called as the test ends. Will return the device to USB mode and kill
825 the ADB server.
Simran Basi431010f2013-09-04 10:42:41 -0700826 """
Christopher Wiley08849d52013-11-22 08:57:58 -0800827 # TODO(sbasi) Originally, we would kill the server after each test to
828 # reduce the opportunity for bad server state to hang around.
829 # Unfortunately, there is a period of time after each kill during which
830 # the Android device becomes unusable, and if we start the next test
831 # too quickly, we'll get an error complaining about no ADB device
832 # attached.
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700833 #self.adb_run('kill-server')
Roshan Pius39942602015-12-17 13:42:07 -0800834 # |close| the associated teststation as well.
835 self.teststation.close()
Simran Basi431010f2013-09-04 10:42:41 -0700836 return super(ADBHost, self).close()
Kris Rambish60461dc2014-03-11 11:10:18 -0700837
838
839 def syslog(self, message, tag='autotest'):
Kevin Chengd19e6c62015-10-28 16:39:39 -0700840 """Logs a message to syslog on the device.
Kris Rambish60461dc2014-03-11 11:10:18 -0700841
842 @param message String message to log into syslog
843 @param tag String tag prefix for syslog
844
845 """
Kevin Chengd19e6c62015-10-28 16:39:39 -0700846 self.run('log -t "%s" "%s"' % (tag, message))
Simran Basid3ba3fb2015-09-11 14:35:07 -0700847
848
849 def get_autodir(self):
850 """Return the directory to install autotest for client side tests."""
851 return '/data/autotest'
852
Kevin Cheng018db352015-09-20 02:22:08 -0700853
Kris Rambishde8f9d12015-12-16 12:42:41 -0800854 def is_device_ready(self):
855 """Return the if the device is ready for ADB commands."""
Dan Shi7075f552016-04-21 15:42:41 -0700856 try:
857 # Retry to avoid possible flakes.
858 is_ready = client_utils.poll_for_condition(
859 lambda: self.adb_run('get-state').stdout.strip() == 'device',
860 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS, sleep_interval=1,
861 desc='Waiting for device state to be `device`')
862 except client_utils.TimeoutError:
863 is_ready = False
864
865 logging.debug('Device state is %sready', '' if is_ready else 'NOT ')
866 return is_ready
Kris Rambishde8f9d12015-12-16 12:42:41 -0800867
868
Kevin Chengd19e6c62015-10-28 16:39:39 -0700869 def verify_connectivity(self):
870 """Verify we can connect to the device."""
Kris Rambishde8f9d12015-12-16 12:42:41 -0800871 if not self.is_device_ready():
872 raise error.AutoservHostError('device state is not in the '
873 '\'device\' state.')
Kevin Chengd19e6c62015-10-28 16:39:39 -0700874
875
Simran Basid3ba3fb2015-09-11 14:35:07 -0700876 def verify_software(self):
877 """Verify working software on an adb_host.
878
Simran Basi38f7ddf2015-09-18 12:25:03 -0700879 TODO (crbug.com/532222): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700880 """
Dan Shiab999722015-12-04 14:27:08 -0800881 # Check if adb and fastboot are present.
882 self.teststation.run('which adb')
883 self.teststation.run('which fastboot')
884 self.teststation.run('which unzip')
Simran Basid3ba3fb2015-09-11 14:35:07 -0700885
Dan Shi626d5412016-05-16 16:05:13 -0700886 # Apply checks only for Android device.
Dan Shi1e2a98a2016-05-18 12:08:08 -0700887 if self.get_os_type() == OS_TYPE_ANDROID:
Dan Shi626d5412016-05-16 16:05:13 -0700888 # Make sure ro.boot.hardware and ro.build.product match.
Dan Shi8c51bda2016-05-26 12:21:02 -0700889 hardware = self._run_output_with_retry('getprop ro.boot.hardware')
890 product = self._run_output_with_retry('getprop ro.build.product')
Dan Shi1e2a98a2016-05-18 12:08:08 -0700891 if hardware != product:
892 raise error.AutoservHostError('ro.boot.hardware: %s does not '
893 'match to ro.build.product: %s' %
894 (hardware, product))
895
Kevin Cheng018db352015-09-20 02:22:08 -0700896
Simran Basid3ba3fb2015-09-11 14:35:07 -0700897 def verify_job_repo_url(self, tag=''):
898 """Make sure job_repo_url of this host is valid.
899
Simran Basi38f7ddf2015-09-18 12:25:03 -0700900 TODO (crbug.com/532223): Actually implement this method.
Simran Basid3ba3fb2015-09-11 14:35:07 -0700901
902 @param tag: The tag from the server job, in the format
903 <job_id>-<user>/<hostname>, or <hostless> for a server job.
904 """
905 return
Kevin Cheng018db352015-09-20 02:22:08 -0700906
907
Simran Basibeb2bb22016-02-03 15:25:48 -0800908 def repair(self):
909 """Attempt to get the DUT to pass `self.verify()`."""
910 try:
911 self.ensure_adb_mode(timeout=30)
912 return
913 except error.AutoservError as e:
914 logging.error(e)
915 logging.debug('Verifying the device is accessible via fastboot.')
916 self.ensure_bootloader_mode()
917 if not self.job.run_test(
918 'provision_AndroidUpdate', host=self, value=None,
919 force=True, repair=True):
920 raise error.AutoservRepairTotalFailure(
921 'Unable to repair the device.')
922
923
Simran Basi1b023762015-09-25 12:12:20 -0700924 def send_file(self, source, dest, delete_dest=False,
925 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -0700926 """Copy files from the drone to the device.
927
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400928 Just a note, there is the possibility the test station is localhost
929 which makes some of these steps redundant (e.g. creating tmp dir) but
930 that scenario will undoubtedly be a development scenario (test station
931 is also the moblab) and not the typical live test running scenario so
932 the redundancy I think is harmless.
933
Kevin Cheng018db352015-09-20 02:22:08 -0700934 @param source: The file/directory on the drone to send to the device.
935 @param dest: The destination path on the device to copy to.
936 @param delete_dest: A flag set to choose whether or not to delete
937 dest on the device if it exists.
Simran Basi1b023762015-09-25 12:12:20 -0700938 @param preserve_symlinks: Controls if symlinks on the source will be
939 copied as such on the destination or
940 transformed into the referenced
941 file/directory.
Kevin Cheng018db352015-09-20 02:22:08 -0700942 """
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700943 # If we need to preserve symlinks, let's check if the source is a
944 # symlink itself and if so, just create it on the device.
945 if preserve_symlinks:
946 symlink_target = None
947 try:
948 symlink_target = os.readlink(source)
949 except OSError:
950 # Guess it's not a symlink.
951 pass
952
953 if symlink_target is not None:
954 # Once we create the symlink, let's get out of here.
955 self.run('ln -s %s %s' % (symlink_target, dest))
956 return
957
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400958 # Stage the files on the test station.
Kevin Chengd19e6c62015-10-28 16:39:39 -0700959 tmp_dir = self.teststation.get_tmp_dir()
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400960 src_path = os.path.join(tmp_dir, os.path.basename(dest))
961 # Now copy the file over to the test station so you can reference the
962 # file in the push command.
963 self.teststation.send_file(source, src_path,
964 preserve_symlinks=preserve_symlinks)
Kevin Cheng018db352015-09-20 02:22:08 -0700965
966 if delete_dest:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400967 self.run('rm -rf %s' % dest)
Kevin Cheng018db352015-09-20 02:22:08 -0700968
Dan Shi6ea3e1c2015-10-28 15:19:04 -0700969 self.adb_run('push %s %s' % (src_path, dest))
Kevin Cheng018db352015-09-20 02:22:08 -0700970
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400971 # Cleanup the test station.
972 try:
973 self.teststation.run('rm -rf %s' % tmp_dir)
Justin Giorgi6ee64532016-08-10 11:32:04 -0700974 except (error.GenericHostRunError, error.AutoservSSHTimeout) as e:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -0400975 logging.warn('failed to remove dir %s: %s', tmp_dir, e)
Kevin Cheng018db352015-09-20 02:22:08 -0700976
977
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700978 def _get_file_info(self, dest):
979 """Get permission and possible symlink info about file on the device.
980
981 These files are on the device so we only have shell commands (via adb)
982 to get the info we want. We'll use 'ls' to get it all.
983
984 @param dest: File to get info about.
985
986 @returns a dict of the file permissions and symlink.
987 """
Kevin Chengaaabd0c2015-11-10 16:05:04 -0800988 # Grab file info.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -0700989 file_info = self.run_output('ls -ld %s' % dest)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -0700990 symlink = None
991 perms = 0
992 match = re.match(FILE_INFO_REGEX, file_info)
993 if match:
994 # Check if it's a symlink and grab the linked dest if it is.
995 if match.group('TYPE') == 'l':
996 symlink_match = re.match(FILE_SYMLINK_REGEX, file_info)
997 if symlink_match:
998 symlink = symlink_match.group('SYMLINK')
999
1000 # Set the perms.
1001 for perm, perm_flag in zip(match.group('PERMS'), FILE_PERMS_FLAGS):
1002 if perm != '-':
1003 perms |= perm_flag
1004
1005 return {'perms': perms,
1006 'symlink': symlink}
1007
1008
Simran Basi1b023762015-09-25 12:12:20 -07001009 def get_file(self, source, dest, delete_dest=False, preserve_perm=True,
1010 preserve_symlinks=False):
Kevin Cheng018db352015-09-20 02:22:08 -07001011 """Copy files from the device to the drone.
1012
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001013 Just a note, there is the possibility the test station is localhost
1014 which makes some of these steps redundant (e.g. creating tmp dir) but
1015 that scenario will undoubtedly be a development scenario (test station
1016 is also the moblab) and not the typical live test running scenario so
1017 the redundancy I think is harmless.
1018
Kevin Cheng018db352015-09-20 02:22:08 -07001019 @param source: The file/directory on the device to copy back to the
1020 drone.
1021 @param dest: The destination path on the drone to copy to.
1022 @param delete_dest: A flag set to choose whether or not to delete
1023 dest on the drone if it exists.
Simran Basi1b023762015-09-25 12:12:20 -07001024 @param preserve_perm: Tells get_file() to try to preserve the sources
1025 permissions on files and dirs.
1026 @param preserve_symlinks: Try to preserve symlinks instead of
1027 transforming them into files/dirs on copy.
Kevin Cheng018db352015-09-20 02:22:08 -07001028 """
David Purselle01548b2016-05-11 10:00:42 -07001029 # Stage the files on the test station under teststation_temp_dir.
1030 teststation_temp_dir = self.teststation.get_tmp_dir()
1031 teststation_dest = os.path.join(teststation_temp_dir,
1032 os.path.basename(source))
Kevin Cheng018db352015-09-20 02:22:08 -07001033
Kevin Cheng92fe6ae2015-10-21 11:45:34 -07001034 source_info = {}
1035 if preserve_symlinks or preserve_perm:
1036 source_info = self._get_file_info(source)
Kevin Cheng018db352015-09-20 02:22:08 -07001037
Kevin Cheng92fe6ae2015-10-21 11:45:34 -07001038 # If we want to preserve symlinks, just create it here, otherwise pull
1039 # the file off the device.
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -07001040 #
1041 # TODO(sadmac): Directories containing symlinks won't behave as
1042 # expected.
Kevin Cheng92fe6ae2015-10-21 11:45:34 -07001043 if preserve_symlinks and source_info['symlink']:
1044 os.symlink(source_info['symlink'], dest)
1045 else:
David Purselle01548b2016-05-11 10:00:42 -07001046 self.adb_run('pull %s %s' % (source, teststation_temp_dir))
Kevin Cheng92fe6ae2015-10-21 11:45:34 -07001047
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001048 # Copy over the file from the test station and clean up.
David Purselle01548b2016-05-11 10:00:42 -07001049 self.teststation.get_file(teststation_dest, dest,
1050 delete_dest=delete_dest)
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001051 try:
David Purselle01548b2016-05-11 10:00:42 -07001052 self.teststation.run('rm -rf %s' % teststation_temp_dir)
Justin Giorgi6ee64532016-08-10 11:32:04 -07001053 except (error.GenericHostRunError, error.AutoservSSHTimeout) as e:
David Purselle01548b2016-05-11 10:00:42 -07001054 logging.warn('failed to remove dir %s: %s',
1055 teststation_temp_dir, e)
Kevin Cheng92fe6ae2015-10-21 11:45:34 -07001056
David Pursell788b1b52016-05-19 09:03:31 -07001057 # Source will be copied under dest if either:
1058 # 1. Source is a directory and doesn't end with /.
1059 # 2. Source is a file and dest is a directory.
Bindu Mahadev594a80e2016-06-01 10:39:49 -07001060 command = '[ -d %s ]' % source
1061 source_is_dir = self.run(command,
David Pursell788b1b52016-05-19 09:03:31 -07001062 ignore_status=True).exit_status == 0
David Pursell2e283932016-08-12 10:48:40 -07001063 logging.debug('%s on the device %s a directory', source,
1064 'is' if source_is_dir else 'is not')
Bindu Mahadev594a80e2016-06-01 10:39:49 -07001065
David Pursell788b1b52016-05-19 09:03:31 -07001066 if ((source_is_dir and not source.endswith(os.sep)) or
1067 (not source_is_dir and os.path.isdir(dest))):
1068 receive_path = os.path.join(dest, os.path.basename(source))
1069 else:
1070 receive_path = dest
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -07001071
David Pursell2e283932016-08-12 10:48:40 -07001072 if not os.path.exists(receive_path):
1073 logging.warning('Expected file %s does not exist; skipping'
1074 ' permissions copy', receive_path)
1075 return
1076
David Pursell788b1b52016-05-19 09:03:31 -07001077 # Set the permissions of the received file/dirs.
1078 if os.path.isdir(receive_path):
1079 for root, _dirs, files in os.walk(receive_path):
1080 def process(rel_path, default_perm):
1081 info = self._get_file_info(os.path.join(source,
1082 rel_path))
1083 if info['perms'] != 0:
1084 target = os.path.join(receive_path, rel_path)
1085 if preserve_perm:
1086 os.chmod(target, info['perms'])
1087 else:
1088 os.chmod(target, default_perm)
Casey Dahlinf6bc8ed2016-04-13 14:33:48 -07001089
David Pursell788b1b52016-05-19 09:03:31 -07001090 rel_root = os.path.relpath(root, receive_path)
1091 process(rel_root, _DEFAULT_DIR_PERMS)
1092 for f in files:
1093 process(os.path.join(rel_root, f), _DEFAULT_FILE_PERMS)
1094 elif preserve_perm:
1095 os.chmod(receive_path, source_info['perms'])
1096 else:
1097 os.chmod(receive_path, _DEFAULT_FILE_PERMS)
Kevin Cheng018db352015-09-20 02:22:08 -07001098
1099
1100 def get_release_version(self):
1101 """Get the release version from the RELEASE_FILE on the device.
1102
1103 @returns The release string in the RELEASE_FILE.
1104
1105 """
1106 return self.run_output('getprop %s' % RELEASE_FILE)
Simran Basi38f7ddf2015-09-18 12:25:03 -07001107
1108
1109 def get_tmp_dir(self, parent=''):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001110 """Return a suitable temporary directory on the device.
Simran Basi38f7ddf2015-09-18 12:25:03 -07001111
Kevin Chengd19e6c62015-10-28 16:39:39 -07001112 We ensure this is a subdirectory of /data/local/tmp.
Simran Basi38f7ddf2015-09-18 12:25:03 -07001113
1114 @param parent: Parent directory of the returned tmp dir.
1115
Kevin Cheng3a4a57a2015-09-30 12:09:50 -07001116 @returns a path to the temp directory on the host.
Simran Basi38f7ddf2015-09-18 12:25:03 -07001117 """
Kevin Chengd19e6c62015-10-28 16:39:39 -07001118 # TODO(kevcheng): Refactor the cleanup of tmp dir to be inherited
1119 # from the parent.
Simran Basi38f7ddf2015-09-18 12:25:03 -07001120 if not parent.startswith(TMP_DIR):
1121 parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep))
Kevin Chengd19e6c62015-10-28 16:39:39 -07001122 self.run('mkdir -p %s' % parent)
1123 tmp_dir = self.run_output('mktemp -d -p %s' % parent)
1124 self.tmp_dirs.append(tmp_dir)
1125 return tmp_dir
Simran Basi1b023762015-09-25 12:12:20 -07001126
1127
1128 def get_platform(self):
1129 """Determine the correct platform label for this host.
1130
1131 TODO (crbug.com/536250): Figure out what we want to do for adb_host's
Kevin Chengd19e6c62015-10-28 16:39:39 -07001132 get_platform.
Simran Basi1b023762015-09-25 12:12:20 -07001133
1134 @returns a string representing this host's platform.
1135 """
1136 return 'adb'
1137
1138
Gilad Arnolda76bef02015-09-29 13:55:15 -07001139 def get_os_type(self):
Dan Shiab999722015-12-04 14:27:08 -08001140 """Get the OS type of the DUT, e.g., android or brillo.
1141 """
1142 if not self._os_type:
1143 if self.run_output('getprop ro.product.brand') == 'Brillo':
1144 self._os_type = OS_TYPE_BRILLO
1145 else:
1146 self._os_type = OS_TYPE_ANDROID
1147
1148 return self._os_type
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001149
1150
1151 def _forward(self, reverse, args):
1152 """Execute a forwarding command.
1153
1154 @param reverse: Whether this is reverse forwarding (Boolean).
1155 @param args: List of command arguments.
1156 """
1157 cmd = '%s %s' % ('reverse' if reverse else 'forward', ' '.join(args))
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001158 self.adb_run(cmd)
Gilad Arnolde452b1f2015-10-06 08:48:34 -07001159
1160
1161 def add_forwarding(self, src, dst, reverse=False, rebind=True):
1162 """Forward a port between the ADB host and device.
1163
1164 Port specifications are any strings accepted as such by ADB, for
1165 example 'tcp:8080'.
1166
1167 @param src: Port specification to forward from.
1168 @param dst: Port specification to forward to.
1169 @param reverse: Do reverse forwarding from device to host (Boolean).
1170 @param rebind: Allow rebinding an already bound port (Boolean).
1171 """
1172 args = []
1173 if not rebind:
1174 args.append('--no-rebind')
1175 args += [src, dst]
1176 self._forward(reverse, args)
1177
1178
1179 def remove_forwarding(self, src=None, reverse=False):
1180 """Removes forwarding on port.
1181
1182 @param src: Port specification, or None to remove all forwarding.
1183 @param reverse: Whether this is reverse forwarding (Boolean).
1184 """
1185 args = []
1186 if src is None:
1187 args.append('--remove-all')
1188 else:
1189 args += ['--remove', src]
1190 self._forward(reverse, args)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001191
1192
xixuan6cf6d2f2016-01-29 15:29:00 -08001193 def create_ssh_tunnel(self, port, local_port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001194 """
1195 Forwards a port securely through a tunnel process from the server
1196 to the DUT for RPC server connection.
1197 Add a 'ADB forward' rule to forward the RPC packets from the AdbHost
1198 to the DUT.
1199
1200 @param port: remote port on the DUT.
1201 @param local_port: local forwarding port.
1202
1203 @return: the tunnel process.
1204 """
1205 self.add_forwarding('tcp:%s' % port, 'tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001206 return super(ADBHost, self).create_ssh_tunnel(port, local_port)
Roshan Pius58e5dd32015-10-16 15:16:42 -07001207
1208
xixuan6cf6d2f2016-01-29 15:29:00 -08001209 def disconnect_ssh_tunnel(self, tunnel_proc, port):
Roshan Pius58e5dd32015-10-16 15:16:42 -07001210 """
1211 Disconnects a previously forwarded port from the server to the DUT for
1212 RPC server connection.
1213 Remove the previously added 'ADB forward' rule to forward the RPC
1214 packets from the AdbHost to the DUT.
1215
1216 @param tunnel_proc: the original tunnel process returned from
xixuan6cf6d2f2016-01-29 15:29:00 -08001217 |create_ssh_tunnel|.
Roshan Pius58e5dd32015-10-16 15:16:42 -07001218 @param port: remote port on the DUT.
1219
1220 """
1221 self.remove_forwarding('tcp:%s' % port)
xixuan6cf6d2f2016-01-29 15:29:00 -08001222 super(ADBHost, self).disconnect_ssh_tunnel(tunnel_proc, port)
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001223
1224
1225 def ensure_bootloader_mode(self):
Kevin Chengd19e6c62015-10-28 16:39:39 -07001226 """Ensure the device is in bootloader mode.
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001227
1228 @raise: error.AutoservError if the device failed to reboot into
1229 bootloader mode.
1230 """
1231 if self.is_up(command=FASTBOOT_CMD):
1232 return
1233 self.adb_run('reboot bootloader')
1234 if not self.wait_up(command=FASTBOOT_CMD):
1235 raise error.AutoservError(
1236 'The device failed to reboot into bootloader mode.')
1237
1238
Dan Shie4e807b2015-12-10 09:04:03 -08001239 def ensure_adb_mode(self, timeout=DEFAULT_WAIT_UP_TIME_SECONDS):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001240 """Ensure the device is up and can be accessed by adb command.
1241
Dan Shie4e807b2015-12-10 09:04:03 -08001242 @param timeout: Time limit in seconds before returning even if the host
1243 is not up.
1244
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001245 @raise: error.AutoservError if the device failed to reboot into
1246 adb mode.
1247 """
1248 if self.is_up():
1249 return
Dan Shi04980372016-03-22 10:57:47 -07001250 # Ignore timeout error to allow `fastboot reboot` to fail quietly and
1251 # check if the device is in adb mode.
1252 self.fastboot_run('reboot', timeout=timeout, ignore_timeout=True)
Dan Shie4e807b2015-12-10 09:04:03 -08001253 if not self.wait_up(timeout=timeout):
Dan Shi6ea3e1c2015-10-28 15:19:04 -07001254 raise error.AutoservError(
1255 'The device failed to reboot into adb mode.')
Roshan Pius4d7540c2015-12-16 13:30:32 -08001256 self._reset_adbd_connection()
Dan Shia2872172015-10-31 01:16:51 -07001257
1258
1259 @classmethod
Dan Shi08ff1282016-02-18 19:51:16 -08001260 def get_build_info_from_build_url(cls, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001261 """Get the Android build information from the build url.
1262
1263 @param build_url: The url to use for downloading Android artifacts.
1264 pattern: http://$devserver:###/static/branch/target/build_id
1265
Dan Shi6450e142016-03-11 11:52:20 -08001266 @return: A dictionary of build information, including keys:
1267 build_target, branch, target, build_id.
Dan Shiab999722015-12-04 14:27:08 -08001268 @raise AndroidInstallError: If failed to parse build_url.
Dan Shia2872172015-10-31 01:16:51 -07001269 """
Dan Shiab999722015-12-04 14:27:08 -08001270 if not build_url:
1271 raise AndroidInstallError('Need build_url to download image files.')
1272
1273 try:
1274 match = re.match(DEVSERVER_URL_REGEX, build_url)
Dan Shi6450e142016-03-11 11:52:20 -08001275 return {'build_target': match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001276 'branch': match.group('BRANCH'),
Dan Shi6450e142016-03-11 11:52:20 -08001277 'target': ('%s-%s' % (match.group('BUILD_TARGET'),
Dan Shiab999722015-12-04 14:27:08 -08001278 match.group('BUILD_TYPE'))),
1279 'build_id': match.group('BUILD_ID')}
1280 except (AttributeError, IndexError, ValueError) as e:
1281 raise AndroidInstallError(
1282 'Failed to parse build url: %s\nError: %s' % (build_url, e))
Dan Shia2872172015-10-31 01:16:51 -07001283
1284
Justin Giorgi6ee64532016-08-10 11:32:04 -07001285 @retry.retry(error.GenericHostRunError, timeout_min=10)
Simran Basi7756a0b2016-03-16 13:10:07 -07001286 def download_file(self, build_url, file, dest_dir, unzip=False,
1287 unzip_dest=None):
Dan Shia2872172015-10-31 01:16:51 -07001288 """Download the given file from the build url.
1289
1290 @param build_url: The url to use for downloading Android artifacts.
1291 pattern: http://$devserver:###/static/branch/target/build_id
1292 @param file: Name of the file to be downloaded, e.g., boot.img.
1293 @param dest_dir: Destination folder for the file to be downloaded to.
Simran Basi7756a0b2016-03-16 13:10:07 -07001294 @param unzip: If True, unzip the downloaded file.
1295 @param unzip_dest: Location to unzip the downloaded file to. If not
1296 provided, dest_dir is used.
Dan Shia2872172015-10-31 01:16:51 -07001297 """
Dan Shidb0366c2016-02-19 10:36:18 -08001298 # Append the file name to the url if build_url is linked to the folder
1299 # containing the file.
1300 if not build_url.endswith('/%s' % file):
1301 src_url = os.path.join(build_url, file)
1302 else:
1303 src_url = build_url
Dan Shia2872172015-10-31 01:16:51 -07001304 dest_file = os.path.join(dest_dir, file)
1305 try:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001306 self.teststation.run('wget -q -O "%s" "%s"' % (dest_file, src_url))
Simran Basi7756a0b2016-03-16 13:10:07 -07001307 if unzip:
1308 unzip_dest = unzip_dest or dest_dir
1309 self.teststation.run('unzip "%s/%s" -x -d "%s"' %
1310 (dest_dir, file, unzip_dest))
Dan Shia2872172015-10-31 01:16:51 -07001311 except:
1312 # Delete the destination file if download failed.
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001313 self.teststation.run('rm -f "%s"' % dest_file)
Dan Shia2872172015-10-31 01:16:51 -07001314 raise
1315
1316
Dan Shiab999722015-12-04 14:27:08 -08001317 def stage_android_image_files(self, build_url):
Dan Shia2872172015-10-31 01:16:51 -07001318 """Download required image files from the given build_url to a local
1319 directory in the machine runs fastboot command.
1320
1321 @param build_url: The url to use for downloading Android artifacts.
1322 pattern: http://$devserver:###/static/branch/target/build_id
1323
1324 @return: Path to the directory contains image files.
1325 """
Dan Shi08ff1282016-02-18 19:51:16 -08001326 build_info = self.get_build_info_from_build_url(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001327
1328 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
Kevin Cheng85e864a2015-11-30 11:49:34 -08001329 image_dir = self.teststation.get_tmp_dir()
Dan Shia2872172015-10-31 01:16:51 -07001330
1331 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001332 self.download_file(build_url, zipped_image_file, image_dir,
1333 unzip=True)
Dan Shi49d451f2016-04-19 09:25:01 -07001334 images = android_utils.AndroidImageFiles.get_standalone_images(
1335 build_info['build_target'])
1336 for image_file in images:
Dan Shidb0366c2016-02-19 10:36:18 -08001337 self.download_file(build_url, image_file, image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001338
Dan Shia2872172015-10-31 01:16:51 -07001339 return image_dir
1340 except:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001341 self.teststation.run('rm -rf %s' % image_dir)
Dan Shia2872172015-10-31 01:16:51 -07001342 raise
1343
1344
Dan Shiab999722015-12-04 14:27:08 -08001345 def stage_brillo_image_files(self, build_url):
1346 """Download required brillo image files from the given build_url to a
1347 local directory in the machine runs fastboot command.
1348
1349 @param build_url: The url to use for downloading Android artifacts.
1350 pattern: http://$devserver:###/static/branch/target/build_id
1351
1352 @return: Path to the directory contains image files.
1353 """
Dan Shi08ff1282016-02-18 19:51:16 -08001354 build_info = self.get_build_info_from_build_url(build_url)
Dan Shiab999722015-12-04 14:27:08 -08001355
1356 zipped_image_file = ANDROID_IMAGE_FILE_FMT % build_info
1357 vendor_partitions_file = BRILLO_VENDOR_PARTITIONS_FILE_FMT % build_info
1358 image_dir = self.teststation.get_tmp_dir()
Dan Shiab999722015-12-04 14:27:08 -08001359
1360 try:
Simran Basi7756a0b2016-03-16 13:10:07 -07001361 self.download_file(build_url, zipped_image_file, image_dir,
1362 unzip=True)
1363 self.download_file(build_url, vendor_partitions_file, image_dir,
1364 unzip=True,
1365 unzip_dest=os.path.join(image_dir, 'vendor'))
Dan Shiab999722015-12-04 14:27:08 -08001366 return image_dir
1367 except:
1368 self.teststation.run('rm -rf %s' % image_dir)
1369 raise
1370
1371
Simran Basibeb2bb22016-02-03 15:25:48 -08001372 def stage_build_for_install(self, build_name, os_type=None):
Dan Shi225b9042015-11-18 10:25:21 -08001373 """Stage a build on a devserver and return the build_url and devserver.
1374
1375 @param build_name: a name like git-master/shamu-userdebug/2040953
Dan Shiab999722015-12-04 14:27:08 -08001376
Dan Shi225b9042015-11-18 10:25:21 -08001377 @returns a tuple with an update URL like:
1378 http://172.22.50.122:8080/git-master/shamu-userdebug/2040953
1379 and the devserver instance.
1380 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001381 os_type = os_type or self.get_os_type()
Dan Shi225b9042015-11-18 10:25:21 -08001382 logging.info('Staging build for installation: %s', build_name)
Dan Shi216389c2015-12-22 11:03:06 -08001383 devserver = dev_server.AndroidBuildServer.resolve(build_name,
1384 self.hostname)
Dan Shiba943532015-12-03 08:58:00 -08001385 build_name = devserver.translate(build_name)
Dan Shi6450e142016-03-11 11:52:20 -08001386 branch, target, build_id = utils.parse_launch_control_build(build_name)
Dan Shi08ff1282016-02-18 19:51:16 -08001387 devserver.trigger_download(target, build_id, branch,
Justin Giorgidd05a942016-07-05 20:53:12 -07001388 os=os_type, synchronous=False)
Dan Shif2fd0762015-12-01 10:09:32 -08001389 return '%s/static/%s' % (devserver.url(), build_name), devserver
Dan Shi225b9042015-11-18 10:25:21 -08001390
1391
Dan Shie4e807b2015-12-10 09:04:03 -08001392 def install_android(self, build_url, build_local_path=None, wipe=True,
Dan Shia2872172015-10-31 01:16:51 -07001393 flash_all=False):
Dan Shiab999722015-12-04 14:27:08 -08001394 """Install the Android DUT.
Dan Shia2872172015-10-31 01:16:51 -07001395
1396 Following are the steps used here to provision an android device:
1397 1. If build_local_path is not set, download the image zip file, e.g.,
1398 shamu-img-2284311.zip, unzip it.
1399 2. Run fastboot to install following artifacts:
1400 bootloader, radio, boot, system, vendor(only if exists)
1401
1402 Repair is not supported for Android devices yet.
1403
1404 @param build_url: The url to use for downloading Android artifacts.
1405 pattern: http://$devserver:###/static/$build
1406 @param build_local_path: The path to a local folder that contains the
1407 image files needed to provision the device. Note that the folder
1408 is in the machine running adb command, rather than the drone.
1409 @param wipe: If true, userdata will be wiped before flashing.
1410 @param flash_all: If True, all img files found in img_path will be
1411 flashed. Otherwise, only boot and system are flashed.
1412
1413 @raises AndroidInstallError if any error occurs.
1414 """
Dan Shia2872172015-10-31 01:16:51 -07001415 # If the build is not staged in local server yet, clean up the temp
1416 # folder used to store image files after the provision is completed.
1417 delete_build_folder = bool(not build_local_path)
1418
1419 try:
1420 # Download image files needed for provision to a local directory.
1421 if not build_local_path:
Dan Shiab999722015-12-04 14:27:08 -08001422 build_local_path = self.stage_android_image_files(build_url)
Dan Shia2872172015-10-31 01:16:51 -07001423
1424 # Device needs to be in bootloader mode for flashing.
1425 self.ensure_bootloader_mode()
1426
1427 if wipe:
Dan Shi12a4f662016-05-10 14:49:42 -07001428 self._fastboot_run_with_retry('-w')
Dan Shia2872172015-10-31 01:16:51 -07001429
1430 # Get all *.img file in the build_local_path.
1431 list_file_cmd = 'ls -d %s' % os.path.join(build_local_path, '*.img')
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001432 image_files = self.teststation.run(
1433 list_file_cmd).stdout.strip().split()
Dan Shia2872172015-10-31 01:16:51 -07001434 images = dict([(os.path.basename(f), f) for f in image_files])
Dan Shi49d451f2016-04-19 09:25:01 -07001435 build_info = self.get_build_info_from_build_url(build_url)
1436 board = build_info['build_target']
1437 all_images = (
1438 android_utils.AndroidImageFiles.get_standalone_images(board)
1439 + android_utils.AndroidImageFiles.get_zipped_images(board))
1440
1441 # Sort images to be flashed, bootloader needs to be the first one.
1442 bootloader = android_utils.AndroidImageFiles.BOOTLOADER
1443 sorted_images = sorted(
1444 images.items(),
1445 key=lambda pair: 0 if pair[0] == bootloader else 1)
1446 for image, image_file in sorted_images:
1447 if image not in all_images:
Dan Shia2872172015-10-31 01:16:51 -07001448 continue
1449 logging.info('Flashing %s...', image_file)
Dan Shi12a4f662016-05-10 14:49:42 -07001450 self._fastboot_run_with_retry('-S 256M flash %s %s' %
1451 (image[:-4], image_file))
Dan Shi49d451f2016-04-19 09:25:01 -07001452 if image == android_utils.AndroidImageFiles.BOOTLOADER:
Dan Shia2872172015-10-31 01:16:51 -07001453 self.fastboot_run('reboot-bootloader')
1454 self.wait_up(command=FASTBOOT_CMD)
1455 except Exception as e:
1456 logging.error('Install Android build failed with error: %s', e)
1457 # Re-raise the exception with type of AndroidInstallError.
1458 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1459 finally:
1460 if delete_build_folder:
Kevin Cheng5f6ed6a2015-10-28 16:18:12 -04001461 self.teststation.run('rm -rf %s' % build_local_path)
Dan Shie4e807b2015-12-10 09:04:03 -08001462 timeout = (WAIT_UP_AFTER_WIPE_TIME_SECONDS if wipe else
1463 DEFAULT_WAIT_UP_TIME_SECONDS)
1464 self.ensure_adb_mode(timeout=timeout)
Dan Shia2872172015-10-31 01:16:51 -07001465 logging.info('Successfully installed Android build staged at %s.',
1466 build_url)
1467
1468
Dan Shiab999722015-12-04 14:27:08 -08001469 def install_brillo(self, build_url, build_local_path=None):
1470 """Install the Brillo DUT.
1471
1472 Following are the steps used here to provision an android device:
1473 1. If build_local_path is not set, download the image zip file, e.g.,
1474 dragonboard-img-123456.zip, unzip it. And download the vendor
1475 partition zip file, e.g., dragonboard-vendor_partitions-123456.zip,
1476 unzip it to vendor folder.
1477 2. Run provision_device script to install OS images and vendor
1478 partitions.
1479
1480 @param build_url: The url to use for downloading Android artifacts.
1481 pattern: http://$devserver:###/static/$build
1482 @param build_local_path: The path to a local folder that contains the
1483 image files needed to provision the device. Note that the folder
1484 is in the machine running adb command, rather than the drone.
1485
1486 @raises AndroidInstallError if any error occurs.
1487 """
1488 # If the build is not staged in local server yet, clean up the temp
1489 # folder used to store image files after the provision is completed.
1490 delete_build_folder = bool(not build_local_path)
1491
Dan Shiab999722015-12-04 14:27:08 -08001492 try:
1493 # Download image files needed for provision to a local directory.
1494 if not build_local_path:
1495 build_local_path = self.stage_brillo_image_files(build_url)
1496
1497 # Device needs to be in bootloader mode for flashing.
1498 self.ensure_bootloader_mode()
1499
1500 # Run provision_device command to install image files and vendor
1501 # partitions.
1502 vendor_partition_dir = os.path.join(build_local_path, 'vendor')
1503 cmd = (BRILLO_PROVISION_CMD %
1504 {'os_image_dir': build_local_path,
1505 'vendor_partition_dir': vendor_partition_dir})
Dan Shi86bd8c02016-03-10 09:21:51 -08001506 if self.fastboot_serial:
Dan Shi91b42352016-03-10 22:12:22 -08001507 cmd += ' -s %s ' % self.fastboot_serial
Dan Shiab999722015-12-04 14:27:08 -08001508 self.teststation.run(cmd)
1509 except Exception as e:
1510 logging.error('Install Brillo build failed with error: %s', e)
1511 # Re-raise the exception with type of AndroidInstallError.
1512 raise AndroidInstallError, sys.exc_info()[1], sys.exc_info()[2]
1513 finally:
1514 if delete_build_folder:
1515 self.teststation.run('rm -rf %s' % build_local_path)
1516 self.ensure_adb_mode()
1517 logging.info('Successfully installed Android build staged at %s.',
1518 build_url)
1519
1520
Dan Shibe3636a2016-02-14 22:48:01 -08001521 @property
1522 def job_repo_url_attribute(self):
1523 """Get the host attribute name for job_repo_url, which should append the
1524 adb serial.
1525 """
1526 return '%s_%s' % (constants.JOB_REPO_URL, self.adb_serial)
1527
1528
Dan Shie4e807b2015-12-10 09:04:03 -08001529 def machine_install(self, build_url=None, build_local_path=None, wipe=True,
Simran Basibeb2bb22016-02-03 15:25:48 -08001530 flash_all=False, os_type=None):
Dan Shia2872172015-10-31 01:16:51 -07001531 """Install the DUT.
1532
1533 @param build_url: The url to use for downloading Android artifacts.
Dan Shi225b9042015-11-18 10:25:21 -08001534 pattern: http://$devserver:###/static/$build. If build_url is
1535 set to None, the code may try _parser.options.image to do the
1536 installation. If none of them is set, machine_install will fail.
Dan Shia2872172015-10-31 01:16:51 -07001537 @param build_local_path: The path to a local directory that contains the
1538 image files needed to provision the device.
1539 @param wipe: If true, userdata will be wiped before flashing.
1540 @param flash_all: If True, all img files found in img_path will be
1541 flashed. Otherwise, only boot and system are flashed.
Simran Basi5ace6f22016-01-06 17:30:44 -08001542
Dan Shibe3636a2016-02-14 22:48:01 -08001543 @returns A tuple of (image_name, host_attributes).
1544 image_name is the name of image installed, e.g.,
1545 git_mnc-release/shamu-userdebug/1234
1546 host_attributes is a dictionary of (attribute, value), which
1547 can be saved to afe_host_attributes table in database. This
1548 method returns a dictionary with a single entry of
1549 `job_repo_url_[adb_serial]`: devserver_url, where devserver_url
1550 is a url to the build staged on devserver.
Dan Shia2872172015-10-31 01:16:51 -07001551 """
Simran Basibeb2bb22016-02-03 15:25:48 -08001552 os_type = os_type or self.get_os_type()
Simran Basi5ace6f22016-01-06 17:30:44 -08001553 if not build_url and self._parser.options.image:
1554 build_url, _ = self.stage_build_for_install(
Simran Basibeb2bb22016-02-03 15:25:48 -08001555 self._parser.options.image, os_type=os_type)
1556 if os_type == OS_TYPE_ANDROID:
Dan Shia2872172015-10-31 01:16:51 -07001557 self.install_android(
1558 build_url=build_url, build_local_path=build_local_path,
1559 wipe=wipe, flash_all=flash_all)
Simran Basibeb2bb22016-02-03 15:25:48 -08001560 elif os_type == OS_TYPE_BRILLO:
Dan Shiab999722015-12-04 14:27:08 -08001561 self.install_brillo(
1562 build_url=build_url, build_local_path=build_local_path)
Dan Shia2872172015-10-31 01:16:51 -07001563 else:
1564 raise error.InstallError(
1565 'Installation of os type %s is not supported.' %
1566 self.get_os_type())
Dan Shibe3636a2016-02-14 22:48:01 -08001567 return (build_url.split('static/')[-1],
1568 {self.job_repo_url_attribute: build_url})
Kevin Chengd19e6c62015-10-28 16:39:39 -07001569
1570
1571 def list_files_glob(self, path_glob):
1572 """Get a list of files on the device given glob pattern path.
1573
1574 @param path_glob: The path glob that we want to return the list of
1575 files that match the glob. Relative paths will not work as
1576 expected. Supply an absolute path to get the list of files
1577 you're hoping for.
1578
1579 @returns List of files that match the path_glob.
1580 """
1581 # This is just in case path_glob has no path separator.
1582 base_path = os.path.dirname(path_glob) or '.'
1583 result = self.run('find %s -path \'%s\' -print' %
Christopher Wileyd21d66a2016-03-01 10:58:13 -08001584 (base_path, path_glob), ignore_status=True)
Kevin Chengd19e6c62015-10-28 16:39:39 -07001585 if result.exit_status != 0:
1586 return []
1587 return result.stdout.splitlines()
Kevin Cheng31355942016-01-05 14:23:35 -08001588
1589
Justin Giorgi6ee64532016-08-10 11:32:04 -07001590 @retry.retry(error.GenericHostRunError, timeout_min=APK_INSTALL_TIMEOUT_MIN)
Dan Shida995002016-04-25 23:12:58 -07001591 def install_apk(self, apk, force_reinstall=True):
Kevin Cheng31355942016-01-05 14:23:35 -08001592 """Install the specified apk.
1593
1594 This will install the apk and override it if it's already installed and
1595 will also allow for downgraded apks.
1596
1597 @param apk: The path to apk file.
Dan Shidb0366c2016-02-19 10:36:18 -08001598 @param force_reinstall: True to reinstall the apk even if it's already
Dan Shida995002016-04-25 23:12:58 -07001599 installed. Default is set to True.
Dan Shidb0366c2016-02-19 10:36:18 -08001600
1601 @returns a CMDResult object.
Kevin Cheng31355942016-01-05 14:23:35 -08001602 """
Dan Shic716ac62016-05-24 16:47:57 -07001603 try:
1604 client_utils.poll_for_condition(
1605 lambda: self.run('pm list packages',
1606 ignore_status=True).exit_status == 0,
1607 timeout=120)
1608 client_utils.poll_for_condition(
1609 lambda: self.run('service list | grep mount',
1610 ignore_status=True).exit_status == 0,
1611 timeout=120)
1612 return self.adb_run('install %s -d %s' %
1613 ('-r' if force_reinstall else '', apk))
Justin Giorgi6ee64532016-08-10 11:32:04 -07001614 except error.GenericHostRunError:
Dan Shic716ac62016-05-24 16:47:57 -07001615 self.reboot()
1616 raise
Dan Shidb0366c2016-02-19 10:36:18 -08001617
1618
Justin Giorgi38a859f2016-08-15 20:19:32 -07001619 def uninstall_package(self, package):
1620 """Remove the specified package.
1621
1622 @param package: Android package name.
1623
1624 @raises GenericHostRunError: uninstall failed
1625 """
1626 result = self.adb_run('uninstall %s' % package)
1627
1628 if self.is_apk_installed(package):
1629 raise error.GenericHostRunError('Uninstall of "%s" failed.'
1630 % package, result)
1631
1632
Justin Giorgi6ee64532016-08-10 11:32:04 -07001633 @retry.retry(error.GenericHostRunError, timeout_min=0.2)
Dan Shidb0366c2016-02-19 10:36:18 -08001634 def _confirm_apk_installed(self, package_name):
1635 """Confirm if apk is already installed with the given name.
1636
1637 `pm list packages` command is not reliable some time. The retry helps to
1638 reduce the chance of false negative.
1639
1640 @param package_name: Name of the package, e.g., com.android.phone.
1641
1642 @raise AutoservRunError: If the package is not found or pm list command
1643 failed for any reason.
1644 """
1645 name = 'package:%s' % package_name
1646 self.adb_run('shell pm list packages | grep -w "%s"' % name)
1647
1648
1649 def is_apk_installed(self, package_name):
1650 """Check if apk is already installed with the given name.
1651
1652 @param package_name: Name of the package, e.g., com.android.phone.
1653
1654 @return: True if package is installed. False otherwise.
1655 """
1656 try:
1657 self._confirm_apk_installed(package_name)
1658 return True
1659 except:
1660 return False
Dan Shibe3636a2016-02-14 22:48:01 -08001661
1662
1663 def get_attributes_to_clear_before_provision(self):
1664 """Get a list of attributes to be cleared before machine_install starts.
1665 """
1666 return [self.job_repo_url_attribute]
Kevin Chengc6a645a2015-12-18 11:15:10 -08001667
1668
1669 def get_labels(self):
1670 """Return a list of the labels gathered from the devices connected.
1671
1672 @return: A list of strings that denote the labels from all the devices
1673 connected.
1674 """
1675 return self.labels.get_labels(self)
1676
1677
1678 def update_labels(self):
1679 """Update the labels for this testbed."""
1680 self.labels.update_labels(self)
Dan Shi6450e142016-03-11 11:52:20 -08001681
1682
1683 def stage_server_side_package(self, image=None):
1684 """Stage autotest server-side package on devserver.
1685
1686 @param image: A build name, e.g., git_mnc_dev/shamu-eng/123
1687
Dan Shi14de7622016-08-22 11:09:06 -07001688 @return: A url to the autotest server-side package.
1689
1690 @raise: error.AutoservError if fail to locate the build to test with, or
1691 fail to stage server-side package.
Dan Shi6450e142016-03-11 11:52:20 -08001692 """
Dan Shid37736b2016-07-06 15:10:29 -07001693 # If enable_drone_in_restricted_subnet is False, do not set hostname
1694 # in devserver.resolve call, so a devserver in non-restricted subnet
1695 # is picked to stage autotest server package for drone to download.
1696 hostname = self.hostname
1697 if not utils.ENABLE_DRONE_IN_RESTRICTED_SUBNET:
1698 hostname = None
Dan Shi6450e142016-03-11 11:52:20 -08001699 if image:
Dan Shid37736b2016-07-06 15:10:29 -07001700 ds = dev_server.AndroidBuildServer.resolve(image, hostname)
Dan Shi6450e142016-03-11 11:52:20 -08001701 else:
1702 job_repo_url = afe_utils.get_host_attribute(
1703 self, self.job_repo_url_attribute)
1704 if job_repo_url:
1705 devserver_url, image = (
1706 tools.get_devserver_build_from_package_url(
1707 job_repo_url, True))
Dan Shid37736b2016-07-06 15:10:29 -07001708 # If enable_drone_in_restricted_subnet is True, use the
1709 # existing devserver. Otherwise, resolve a new one in
1710 # non-restricted subnet.
1711 if utils.ENABLE_DRONE_IN_RESTRICTED_SUBNET:
1712 ds = dev_server.AndroidBuildServer(devserver_url)
1713 else:
1714 ds = dev_server.AndroidBuildServer.resolve(image)
Dan Shi6450e142016-03-11 11:52:20 -08001715 else:
1716 labels = afe_utils.get_labels(self, self.VERSION_PREFIX)
1717 if not labels:
1718 raise error.AutoservError(
1719 'Failed to stage server-side package. The host has '
1720 'no job_report_url attribute or version label.')
Kevin Cheng84a71ba2016-07-14 11:03:57 -07001721 image = labels[0][len(self.VERSION_PREFIX + ':'):]
Dan Shid37736b2016-07-06 15:10:29 -07001722 ds = dev_server.AndroidBuildServer.resolve(image, hostname)
Dan Shi6450e142016-03-11 11:52:20 -08001723
1724 branch, target, build_id = utils.parse_launch_control_build(image)
1725 build_target, _ = utils.parse_launch_control_target(target)
1726
1727 # For any build older than MIN_VERSION_SUPPORT_SSP, server side
1728 # packaging is not supported.
1729 try:
Dan Shi14de7622016-08-22 11:09:06 -07001730 # Some build ids may have special character before the actual
1731 # number, skip such characters.
1732 actual_build_id = build_id
1733 if build_id.startswith('P'):
1734 actual_build_id = build_id[1:]
1735 if int(actual_build_id) < self.MIN_VERSION_SUPPORT_SSP:
1736 raise error.AutoservError(
1737 'Build %s is older than %s. Server side packaging is '
1738 'disabled.' % (image, self.MIN_VERSION_SUPPORT_SSP))
Dan Shi6450e142016-03-11 11:52:20 -08001739 except ValueError:
Dan Shi14de7622016-08-22 11:09:06 -07001740 raise error.AutoservError(
1741 'Failed to compare build id in %s with the minimum '
1742 'version that supports server side packaging. Server '
1743 'side packaging is disabled.' % image)
Dan Shi6450e142016-03-11 11:52:20 -08001744
1745 ds.stage_artifacts(target, build_id, branch,
1746 artifacts=['autotest_server_package'])
1747 autotest_server_package_name = (AUTOTEST_SERVER_PACKAGE_FILE_FMT %
1748 {'build_target': build_target,
1749 'build_id': build_id})
1750 return '%s/static/%s/%s' % (ds.url(), image,
1751 autotest_server_package_name)
Bryan Lewandowski0f3f0112016-05-27 15:17:19 -07001752
1753
1754 def _sync_time(self):
1755 """Approximate synchronization of time between host and ADB device.
1756
1757 This sets the ADB/Android device's clock to approximately the same
1758 time as the Autotest host for the purposes of comparing Android system
1759 logs such as logcat to logs from the Autotest host system.
1760 """
1761 command = 'date '
1762 sdk_version = int(self.run('getprop %s' % SDK_FILE).stdout)
1763 if sdk_version < 23:
1764 # Android L and earlier use this format: date -s (format).
1765 command += ('-s %s' %
1766 datetime.datetime.now().strftime('%Y%m%d.%H%M%S'))
1767 else:
Alex Deymob244ddb2016-07-20 19:51:30 -07001768 # Android M and later use this format: date -u (format).
1769 command += ('-u %s' %
1770 datetime.datetime.utcnow().strftime('%m%d%H%M%Y.%S'))
Bryan Lewandowskiea4a06d2016-06-03 11:25:54 -07001771 self.run(command, timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS,
1772 ignore_timeout=True)
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001773
1774
1775 def _enable_native_crash_logging(self):
1776 """Enable native (non-Java) crash logging.
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001777 """
Ralph Nathan3b758a32016-08-11 17:48:46 -07001778 # TODO(b/30820403): Enable Brillo native crash logging.
1779 # if self.get_os_type() == OS_TYPE_BRILLO:
1780 # self._enable_brillo_native_crash_logging()
1781 if self.get_os_type() == OS_TYPE_ANDROID:
Bryan Lewandowski68646b62016-07-12 10:24:57 -07001782 self._enable_android_native_crash_logging()
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001783
Bryan Lewandowski68646b62016-07-12 10:24:57 -07001784
1785 def _enable_brillo_native_crash_logging(self):
1786 """Enables native crash logging for a Brillo DUT.
1787 """
Bryan Lewandowski8c96bb22016-07-19 12:56:03 -07001788 try:
1789 self.run('touch /data/misc/metrics/enabled',
1790 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS,
1791 ignore_timeout=True)
1792 # If running, crash_sender will delete crash files every hour.
1793 self.run('stop crash_sender',
1794 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS,
1795 ignore_timeout=True)
Justin Giorgi6ee64532016-08-10 11:32:04 -07001796 except error.GenericHostRunError as e:
Bryan Lewandowski8c96bb22016-07-19 12:56:03 -07001797 logging.warn(e)
1798 logging.warn('Failed to enable Brillo native crash logging.')
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001799
1800
Bryan Lewandowski68646b62016-07-12 10:24:57 -07001801 def _enable_android_native_crash_logging(self):
1802 """Enables native crash logging for an Android DUT.
1803 """
1804 # debuggerd should be enabled by default on Android.
1805 result = self.run('pgrep debuggerd',
1806 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS,
1807 ignore_timeout=True, ignore_status=True)
1808 if not result or result.exit_status != 0:
1809 logging.debug('Unable to confirm that debuggerd is running.')
1810
1811
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001812 def _collect_crash_logs(self):
1813 """Copies crash log files from the DUT to the drone.
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001814 """
Bryan Lewandowski68646b62016-07-12 10:24:57 -07001815 if self.get_os_type() == OS_TYPE_BRILLO:
1816 self._collect_crash_logs_dut(BRILLO_NATIVE_CRASH_LOG_DIR)
1817 elif self.get_os_type() == OS_TYPE_ANDROID:
1818 self._collect_crash_logs_dut(ANDROID_TOMBSTONE_CRASH_LOG_DIR)
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001819
Bryan Lewandowski68646b62016-07-12 10:24:57 -07001820
1821 def _collect_crash_logs_dut(self, log_directory):
1822 """Copies native crash logs from the Android/Brillo DUT to the drone.
1823
1824 @param log_directory: absolute path of the directory on the DUT where
1825 log files are stored.
1826 """
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001827 files = None
1828 try:
Bryan Lewandowski68646b62016-07-12 10:24:57 -07001829 result = self.run('find %s -maxdepth 1 -type f' % log_directory,
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001830 timeout=DEFAULT_COMMAND_RETRY_TIMEOUT_SECONDS)
1831 files = result.stdout.strip().split()
Justin Giorgi6ee64532016-08-10 11:32:04 -07001832 except (error.GenericHostRunError, error.AutoservSSHTimeout,
1833 error.CmdTimeoutError):
Bryan Lewandowski68646b62016-07-12 10:24:57 -07001834 logging.debug('Unable to call find %s, unable to find crash logs',
1835 log_directory)
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001836 if not files:
Bryan Lewandowski68646b62016-07-12 10:24:57 -07001837 logging.debug('There are no crash logs on the DUT.')
Bryan Lewandowski11f8aed2016-06-29 15:44:40 -07001838 return
1839
1840 crash_dir = os.path.join(self.job.resultdir, 'crash')
1841 try:
1842 os.mkdir(crash_dir)
1843 except OSError as e:
1844 if e.errno != errno.EEXIST:
1845 raise e
1846
1847 for f in files:
Bryan Lewandowski68646b62016-07-12 10:24:57 -07001848 logging.debug('DUT native crash file produced: %s', f)
1849 dest = os.path.join(crash_dir, os.path.basename(f))
1850 self.get_file(source=f, dest=dest)