blob: 31e89e9549bf40f94e6bda3571734977a607f0f0 [file] [log] [blame]
Ang Li93420002016-05-10 19:11:44 -07001#!/usr/bin/env python3.4
2#
3# Copyright 2016 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17from builtins import str
18from builtins import open
19
Ang Li7f0e1c72016-06-14 11:23:49 -070020import logging
Ang Li93420002016-05-10 19:11:44 -070021import os
22import time
23import traceback
Sahil Jain06dd6a22016-06-24 13:47:37 -070024import threading
25import socket
Ang Li93420002016-05-10 19:11:44 -070026
Keun Soo Yime34754e2016-08-15 11:25:15 -070027from vts.runners.host import keys
Ang Li93420002016-05-10 19:11:44 -070028from vts.runners.host import logger as vts_logger
29from vts.runners.host import signals
30from vts.runners.host import utils
Ang Li7f0e1c72016-06-14 11:23:49 -070031from vts.utils.python.controllers import adb
32from vts.utils.python.controllers import event_dispatcher
33from vts.utils.python.controllers import fastboot
Ang Li6c303fc2016-09-22 13:19:33 -070034from vts.utils.python.controllers import sl4a_client
Sahil Jain06dd6a22016-06-24 13:47:37 -070035from vts.runners.host.tcp_client import vts_tcp_client
Ang Li7f0e1c72016-06-14 11:23:49 -070036from vts.utils.python.mirror import hal_mirror
Keun Soo Yim63d67512016-07-01 17:13:47 -070037from vts.utils.python.mirror import shell_mirror
Keun Soo Yim39bc0b92016-07-06 18:27:15 -070038from vts.utils.python.mirror import lib_mirror
Sahil Jain06dd6a22016-06-24 13:47:37 -070039from vts.runners.host import errors
40import subprocess
Ang Li93420002016-05-10 19:11:44 -070041
42VTS_CONTROLLER_CONFIG_NAME = "AndroidDevice"
43VTS_CONTROLLER_REFERENCE_NAME = "android_devices"
44
45ANDROID_DEVICE_PICK_ALL_TOKEN = "*"
46# Key name for adb logcat extra params in config file.
47ANDROID_DEVICE_ADB_LOGCAT_PARAM_KEY = "adb_logcat_param"
48ANDROID_DEVICE_EMPTY_CONFIG_MSG = "Configuration is empty, abort!"
49ANDROID_DEVICE_NOT_LIST_CONFIG_MSG = "Configuration should be a list, abort!"
50
Keun Soo Yime34754e2016-08-15 11:25:15 -070051ANDROID_PRODUCT_TYPE_UNKNOWN = "unknown"
52
Sahil Jain06dd6a22016-06-24 13:47:37 -070053# Target-side directory where the VTS binaries are uploaded
54DEFAULT_AGENT_BASE_DIR = "/data/local/tmp"
55# Time for which the current is put on sleep when the client is unable to
56# make a connection.
57THREAD_SLEEP_TIME = 1
58# Max number of attempts that the client can make to connect to the agent
59MAX_AGENT_CONNECT_RETRIES = 10
60
Ang Li93420002016-05-10 19:11:44 -070061class AndroidDeviceError(signals.ControllerError):
62 pass
63
Ang Lie2139f12016-05-12 17:39:06 -070064
Tri Vo7ed0d642017-01-18 09:56:48 -080065def create(configs, start_services=True):
Ang Li53bb72b2016-07-19 18:29:37 -070066 """Creates AndroidDevice controller objects.
67
68 Args:
69 configs: A list of dicts, each representing a configuration for an
70 Android device.
Tri Vo7ed0d642017-01-18 09:56:48 -080071 start_services: boolean, controls whether services will be started.
Ang Li53bb72b2016-07-19 18:29:37 -070072
73 Returns:
74 A list of AndroidDevice objects.
75 """
Ang Li93420002016-05-10 19:11:44 -070076 if not configs:
77 raise AndroidDeviceError(ANDROID_DEVICE_EMPTY_CONFIG_MSG)
78 elif configs == ANDROID_DEVICE_PICK_ALL_TOKEN:
Ang Li7f0e1c72016-06-14 11:23:49 -070079 ads = get_all_instances()
Ang Li93420002016-05-10 19:11:44 -070080 elif not isinstance(configs, list):
81 raise AndroidDeviceError(ANDROID_DEVICE_NOT_LIST_CONFIG_MSG)
82 elif isinstance(configs[0], str):
83 # Configs is a list of serials.
Ang Li7f0e1c72016-06-14 11:23:49 -070084 ads = get_instances(configs)
Ang Li93420002016-05-10 19:11:44 -070085 else:
86 # Configs is a list of dicts.
Ang Li7f0e1c72016-06-14 11:23:49 -070087 ads = get_instances_with_configs(configs)
Ang Li93420002016-05-10 19:11:44 -070088 connected_ads = list_adb_devices()
89 for ad in ads:
90 if ad.serial not in connected_ads:
Ang Li53bb72b2016-07-19 18:29:37 -070091 raise DoesNotExistError(("Android device %s is specified in config"
92 " but is not attached.") % ad.serial)
Tri Vo7ed0d642017-01-18 09:56:48 -080093 if start_services:
94 _startServicesOnAds(ads)
Ang Li93420002016-05-10 19:11:44 -070095 return ads
96
Ang Lie2139f12016-05-12 17:39:06 -070097
Ang Li93420002016-05-10 19:11:44 -070098def destroy(ads):
Ang Li53bb72b2016-07-19 18:29:37 -070099 """Cleans up AndroidDevice objects.
100
101 Args:
102 ads: A list of AndroidDevice objects.
103 """
Ang Li93420002016-05-10 19:11:44 -0700104 for ad in ads:
Ang Li53bb72b2016-07-19 18:29:37 -0700105 try:
106 ad.cleanUp()
107 except:
108 ad.log.exception("Failed to clean up properly.")
109
110
Ang Li6c303fc2016-09-22 13:19:33 -0700111def _startServicesOnAds(ads):
Ang Li53bb72b2016-07-19 18:29:37 -0700112 """Starts long running services on multiple AndroidDevice objects.
113
114 If any one AndroidDevice object fails to start services, cleans up all
115 existing AndroidDevice objects and their services.
116
117 Args:
118 ads: A list of AndroidDevice objects whose services to start.
119 """
120 running_ads = []
121 for ad in ads:
122 running_ads.append(ad)
123 try:
Ang Li6c303fc2016-09-22 13:19:33 -0700124 ad.startServices()
Ang Li53bb72b2016-07-19 18:29:37 -0700125 except:
126 ad.log.exception("Failed to start some services, abort!")
127 destroy(running_ads)
128 raise
Ang Li93420002016-05-10 19:11:44 -0700129
Ang Lie2139f12016-05-12 17:39:06 -0700130
Ang Li93420002016-05-10 19:11:44 -0700131def _parse_device_list(device_list_str, key):
132 """Parses a byte string representing a list of devices. The string is
133 generated by calling either adb or fastboot.
134
135 Args:
136 device_list_str: Output of adb or fastboot.
137 key: The token that signifies a device in device_list_str.
138
139 Returns:
140 A list of android device serial numbers.
141 """
142 clean_lines = str(device_list_str, 'utf-8').strip().split('\n')
143 results = []
144 for line in clean_lines:
145 tokens = line.strip().split('\t')
146 if len(tokens) == 2 and tokens[1] == key:
147 results.append(tokens[0])
148 return results
149
Ang Lie2139f12016-05-12 17:39:06 -0700150
Ang Li93420002016-05-10 19:11:44 -0700151def list_adb_devices():
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700152 """List all target devices connected to the host and detected by adb.
Ang Li93420002016-05-10 19:11:44 -0700153
154 Returns:
155 A list of android device serials. Empty if there's none.
156 """
157 out = adb.AdbProxy().devices()
158 return _parse_device_list(out, "device")
159
Ang Lie2139f12016-05-12 17:39:06 -0700160
Ang Li93420002016-05-10 19:11:44 -0700161def list_fastboot_devices():
162 """List all android devices connected to the computer that are in in
163 fastboot mode. These are detected by fastboot.
164
165 Returns:
166 A list of android device serials. Empty if there's none.
167 """
168 out = fastboot.FastbootProxy().devices()
169 return _parse_device_list(out, "fastboot")
170
Ang Lie2139f12016-05-12 17:39:06 -0700171
Ang Li7f0e1c72016-06-14 11:23:49 -0700172def get_instances(serials):
Ang Li93420002016-05-10 19:11:44 -0700173 """Create AndroidDevice instances from a list of serials.
174
175 Args:
176 serials: A list of android device serials.
Ang Li93420002016-05-10 19:11:44 -0700177
178 Returns:
179 A list of AndroidDevice objects.
180 """
181 results = []
182 for s in serials:
Ang Li7f0e1c72016-06-14 11:23:49 -0700183 results.append(AndroidDevice(s))
Ang Li93420002016-05-10 19:11:44 -0700184 return results
185
Ang Lie2139f12016-05-12 17:39:06 -0700186
Ang Li7f0e1c72016-06-14 11:23:49 -0700187def get_instances_with_configs(configs):
Ang Li93420002016-05-10 19:11:44 -0700188 """Create AndroidDevice instances from a list of json configs.
189
190 Each config should have the required key-value pair "serial".
191
192 Args:
193 configs: A list of dicts each representing the configuration of one
194 android device.
Ang Li93420002016-05-10 19:11:44 -0700195
196 Returns:
197 A list of AndroidDevice objects.
198 """
199 results = []
200 for c in configs:
201 try:
Keun Soo Yime34754e2016-08-15 11:25:15 -0700202 serial = c.pop(keys.ConfigKeys.IKEY_SERIAL)
Ang Li93420002016-05-10 19:11:44 -0700203 except KeyError:
Keun Soo Yime34754e2016-08-15 11:25:15 -0700204 raise AndroidDeviceError(
205 ('Required value %s is missing in '
206 'AndroidDevice config %s.') % (keys.ConfigKeys.IKEY_SERIAL,
207 c))
208 try:
209 product_type = c.pop(keys.ConfigKeys.IKEY_PRODUCT_TYPE)
210 except KeyError:
211 logging.error(
212 'Required value %s is missing in '
213 'AndroidDevice config %s.',
214 keys.ConfigKeys.IKEY_PRODUCT_TYPE, c)
215 product_type = ANDROID_PRODUCT_TYPE_UNKNOWN
216
217 ad = AndroidDevice(serial, product_type)
Ang Li93420002016-05-10 19:11:44 -0700218 ad.loadConfig(c)
219 results.append(ad)
220 return results
221
Ang Lie2139f12016-05-12 17:39:06 -0700222
Ang Li7f0e1c72016-06-14 11:23:49 -0700223def get_all_instances(include_fastboot=False):
Ang Li93420002016-05-10 19:11:44 -0700224 """Create AndroidDevice instances for all attached android devices.
225
226 Args:
227 include_fastboot: Whether to include devices in bootloader mode or not.
Ang Li93420002016-05-10 19:11:44 -0700228
229 Returns:
230 A list of AndroidDevice objects each representing an android device
231 attached to the computer.
232 """
233 if include_fastboot:
234 serial_list = list_adb_devices() + list_fastboot_devices()
Ang Li7f0e1c72016-06-14 11:23:49 -0700235 return get_instances(serial_list)
236 return get_instances(list_adb_devices())
Ang Li93420002016-05-10 19:11:44 -0700237
Ang Lie2139f12016-05-12 17:39:06 -0700238
Ang Li93420002016-05-10 19:11:44 -0700239def filter_devices(ads, func):
240 """Finds the AndroidDevice instances from a list that match certain
241 conditions.
242
243 Args:
244 ads: A list of AndroidDevice instances.
245 func: A function that takes an AndroidDevice object and returns True
246 if the device satisfies the filter condition.
247
248 Returns:
249 A list of AndroidDevice instances that satisfy the filter condition.
250 """
251 results = []
252 for ad in ads:
253 if func(ad):
254 results.append(ad)
255 return results
256
Ang Lie2139f12016-05-12 17:39:06 -0700257
Ang Li93420002016-05-10 19:11:44 -0700258def get_device(ads, **kwargs):
259 """Finds a unique AndroidDevice instance from a list that has specific
260 attributes of certain values.
261
262 Example:
263 get_device(android_devices, label="foo", phone_number="1234567890")
264 get_device(android_devices, model="angler")
265
266 Args:
267 ads: A list of AndroidDevice instances.
268 kwargs: keyword arguments used to filter AndroidDevice instances.
269
270 Returns:
271 The target AndroidDevice instance.
272
273 Raises:
274 AndroidDeviceError is raised if none or more than one device is
275 matched.
276 """
Ang Lie2139f12016-05-12 17:39:06 -0700277
Ang Li93420002016-05-10 19:11:44 -0700278 def _get_device_filter(ad):
279 for k, v in kwargs.items():
280 if not hasattr(ad, k):
281 return False
282 elif getattr(ad, k) != v:
283 return False
284 return True
Ang Lie2139f12016-05-12 17:39:06 -0700285
Ang Li93420002016-05-10 19:11:44 -0700286 filtered = filter_devices(ads, _get_device_filter)
287 if not filtered:
288 raise AndroidDeviceError(("Could not find a target device that matches"
289 " condition: %s.") % kwargs)
290 elif len(filtered) == 1:
291 return filtered[0]
292 else:
293 serials = [ad.serial for ad in filtered]
294 raise AndroidDeviceError("More than one device matched: %s" % serials)
295
Ang Lie2139f12016-05-12 17:39:06 -0700296
Ang Li93420002016-05-10 19:11:44 -0700297def takeBugReports(ads, test_name, begin_time):
298 """Takes bug reports on a list of android devices.
299
300 If you want to take a bug report, call this function with a list of
301 android_device objects in on_fail. But reports will be taken on all the
302 devices in the list concurrently. Bug report takes a relative long
303 time to take, so use this cautiously.
304
305 Args:
306 ads: A list of AndroidDevice instances.
307 test_name: Name of the test case that triggered this bug report.
308 begin_time: Logline format timestamp taken when the test started.
309 """
310 begin_time = vts_logger.normalizeLogLineTimestamp(begin_time)
Ang Lie2139f12016-05-12 17:39:06 -0700311
Ang Li93420002016-05-10 19:11:44 -0700312 def take_br(test_name, begin_time, ad):
313 ad.takeBugReport(test_name, begin_time)
Ang Lie2139f12016-05-12 17:39:06 -0700314
Ang Li93420002016-05-10 19:11:44 -0700315 args = [(test_name, begin_time, ad) for ad in ads]
316 utils.concurrent_exec(take_br, args)
317
Ang Lie2139f12016-05-12 17:39:06 -0700318
Ang Li7f0e1c72016-06-14 11:23:49 -0700319class AndroidDevice(object):
Ang Li93420002016-05-10 19:11:44 -0700320 """Class representing an android device.
321
Ang Li53bb72b2016-07-19 18:29:37 -0700322 Each object of this class represents one Android device. The object holds
323 handles to adb, fastboot, and various RPC clients.
Ang Li93420002016-05-10 19:11:44 -0700324
325 Attributes:
Keun Soo Yime34754e2016-08-15 11:25:15 -0700326 serial: A string that's the serial number of the Android device.
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700327 device_command_port: int, the port number used on the Android device
328 for adb port forwarding (for command-response sessions).
329 device_callback_port: int, the port number used on the Android device
330 for adb port reverse forwarding (for callback sessions).
Ang Lie014a8b2016-06-28 18:24:52 -0700331 log: A logger project with a device-specific prefix for each line -
332 [AndroidDevice|<serial>]
Ang Li93420002016-05-10 19:11:44 -0700333 log_path: A string that is the path where all logs collected on this
334 android device should be stored.
335 adb_logcat_process: A process that collects the adb logcat.
336 adb_logcat_file_path: A string that's the full path to the adb logcat
337 file collected, if any.
Ang Lie014a8b2016-06-28 18:24:52 -0700338 vts_agent_process: A process that runs the HAL agent.
Ang Li93420002016-05-10 19:11:44 -0700339 adb: An AdbProxy object used for interacting with the device via adb.
340 fastboot: A FastbootProxy object used for interacting with the device
341 via fastboot.
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700342 host_command_port: the host-side port for runner to agent sessions
343 (to send commands and receive responses).
344 host_callback_port: the host-side port for agent to runner sessions
345 (to get callbacks from agent).
Ang Li53bb72b2016-07-19 18:29:37 -0700346 hal: HalMirror, in charge of all communications with the HAL layer.
347 lib: LibMirror, in charge of all communications with static and shared
348 native libs.
349 shell: ShellMirror, in charge of all communications with shell.
Keun Soo Yime34754e2016-08-15 11:25:15 -0700350 _product_type: A string, the device product type (e.g., bullhead) if
351 known, ANDROID_PRODUCT_TYPE_UNKNOWN otherwise.
Ang Li93420002016-05-10 19:11:44 -0700352 """
353
Keun Soo Yime34754e2016-08-15 11:25:15 -0700354 def __init__(self, serial="", product_type=ANDROID_PRODUCT_TYPE_UNKNOWN,
355 device_callback_port=5010):
Ang Li93420002016-05-10 19:11:44 -0700356 self.serial = serial
Keun Soo Yime34754e2016-08-15 11:25:15 -0700357 self._product_type = product_type
Keun Soo Yimf5d0bca2016-07-30 23:59:26 -0700358 self.device_command_port = None
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700359 self.device_callback_port = device_callback_port
Ang Lie014a8b2016-06-28 18:24:52 -0700360 self.log = AndroidDeviceLoggerAdapter(logging.getLogger(),
361 {"serial": self.serial})
362 base_log_path = getattr(logging, "log_path", "/tmp/logs/")
Ang Li7f0e1c72016-06-14 11:23:49 -0700363 self.log_path = os.path.join(base_log_path, "AndroidDevice%s" % serial)
Ang Li93420002016-05-10 19:11:44 -0700364 self.adb_logcat_process = None
365 self.adb_logcat_file_path = None
Ang Lie014a8b2016-06-28 18:24:52 -0700366 self.vts_agent_process = None
Ang Li93420002016-05-10 19:11:44 -0700367 self.adb = adb.AdbProxy(serial)
368 self.fastboot = fastboot.FastbootProxy(serial)
369 if not self.isBootloaderMode:
370 self.rootAdb()
Ang Li6c303fc2016-09-22 13:19:33 -0700371 self.host_command_port = None
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700372 self.host_callback_port = adb.get_available_host_port()
Ang Lie014a8b2016-06-28 18:24:52 -0700373 self.adb.reverse_tcp_forward(self.device_callback_port,
374 self.host_callback_port)
Ang Li53bb72b2016-07-19 18:29:37 -0700375 self.hal = None
Keun Soo Yimf5d0bca2016-07-30 23:59:26 -0700376 self.lib = None
377 self.shell = None
Ang Li6c303fc2016-09-22 13:19:33 -0700378 self.sl4a_host_port = None
379 # TODO: figure out a good way to detect which port is available
380 # on the target side, instead of hard coding a port number.
381 self.sl4a_target_port = 8082
Ang Li93420002016-05-10 19:11:44 -0700382
383 def __del__(self):
Ang Li53bb72b2016-07-19 18:29:37 -0700384 self.cleanUp()
385
386 def cleanUp(self):
387 """Cleans up the AndroidDevice object and releases any resources it
388 claimed.
389 """
390 self.stopServices()
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700391 if self.host_command_port:
392 self.adb.forward("--remove tcp:%s" % self.host_command_port)
Ang Li6c303fc2016-09-22 13:19:33 -0700393 self.host_command_port = None
394 if self.sl4a_host_port:
395 self.adb.forward("--remove tcp:%s" % self.sl4a_host_port)
396 self.sl4a_host_port = None
Ang Li93420002016-05-10 19:11:44 -0700397
398 @property
399 def isBootloaderMode(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700400 """True if the device is in bootloader mode."""
Ang Li93420002016-05-10 19:11:44 -0700401 return self.serial in list_fastboot_devices()
402
403 @property
404 def isAdbRoot(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700405 """True if adb is running as root for this device."""
406 id_str = self.adb.shell("id -u").decode("utf-8")
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700407 return "root" in id_str
Ang Li93420002016-05-10 19:11:44 -0700408
409 @property
Tri Voe1a5a852016-10-20 19:59:45 -0700410 def verityEnabled(self):
411 """True if verity is enabled for this device."""
412 try:
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800413 verified = self.adb.shell('getprop partition.system.verified').decode("utf-8")
414 if not verified:
415 return False
Tri Voe1a5a852016-10-20 19:59:45 -0700416 except adb.AdbError:
417 # If verity is disabled, there is no property 'partition.system.verified'
418 return False
419 return True
420
421 @property
Ang Li93420002016-05-10 19:11:44 -0700422 def model(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700423 """The Android code name for the device."""
Ang Li93420002016-05-10 19:11:44 -0700424 # If device is in bootloader mode, get mode name from fastboot.
425 if self.isBootloaderMode:
426 out = self.fastboot.getvar("product").strip()
427 # "out" is never empty because of the "total time" message fastboot
428 # writes to stderr.
429 lines = out.decode("utf-8").split('\n', 1)
430 if lines:
431 tokens = lines[0].split(' ')
432 if len(tokens) > 1:
433 return tokens[1].lower()
434 return None
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800435 out = self.adb.shell('getprop ro.build.product')
436 model = out.decode("utf-8").strip().lower()
Ang Li93420002016-05-10 19:11:44 -0700437 if model == "sprout":
438 return model
439 else:
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800440 out = self.adb.shell('getprop ro.product.name')
441 model = out.decode("utf-8").strip().lower()
Ang Li93420002016-05-10 19:11:44 -0700442 return model
443
444 @property
Tri Vo921bfa02016-09-20 10:25:23 -0700445 def cpu_abi(self):
446 """CPU ABI (Application Binary Interface) of the device."""
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800447 out = self.adb.shell('getprop ro.product.cpu.abi')
Tri Vo921bfa02016-09-20 10:25:23 -0700448 if not out:
449 return "unknown"
450
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800451 cpu_abi = out.decode("utf-8").strip().lower()
Tri Vo921bfa02016-09-20 10:25:23 -0700452 return cpu_abi
453
454 @property
Tri Vof07f1292016-09-21 17:27:46 -0700455 def is64Bit(self):
456 """True if device is 64 bit."""
457 out = self.adb.shell('uname -m')
458 return "64" in out
459
460 @property
Hsin-Yi Chen8a863ec2016-12-29 18:46:14 +0800461 def libPaths(self):
462 """List of strings representing the paths to the native library directories."""
463 paths_32 = ["/system/lib", "/vendor/lib"]
464 if self.is64Bit:
465 paths_64 = ["/system/lib64", "/vendor/lib64"]
466 paths_64.extend(paths_32)
467 return paths_64
468 return paths_32
469
470 @property
Ang Li93420002016-05-10 19:11:44 -0700471 def isAdbLogcatOn(self):
472 """Whether there is an ongoing adb logcat collection.
473 """
474 if self.adb_logcat_process:
475 return True
476 return False
477
478 def loadConfig(self, config):
479 """Add attributes to the AndroidDevice object based on json config.
480
481 Args:
482 config: A dictionary representing the configs.
483
484 Raises:
485 AndroidDeviceError is raised if the config is trying to overwrite
486 an existing attribute.
487 """
488 for k, v in config.items():
489 if hasattr(self, k):
Ang Li7f0e1c72016-06-14 11:23:49 -0700490 raise AndroidDeviceError(
491 "Attempting to set existing attribute %s on %s" %
492 (k, self.serial))
Ang Li93420002016-05-10 19:11:44 -0700493 setattr(self, k, v)
494
495 def rootAdb(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700496 """Changes adb to root mode for this device."""
Ang Li93420002016-05-10 19:11:44 -0700497 if not self.isAdbRoot:
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700498 try:
499 self.adb.root()
Keun Soo Yima5a0dc22016-07-16 17:56:19 -0700500 self.adb.wait_for_device()
501 self.adb.remount()
Keun Soo Yim731e9172016-07-16 17:48:39 -0700502 self.adb.wait_for_device()
503 except adb.AdbError as e:
504 # adb wait-for-device is not always possible in the lab
Keun Soo Yima5a0dc22016-07-16 17:56:19 -0700505 # continue with an assumption it's done by the harness.
Keun Soo Yim731e9172016-07-16 17:48:39 -0700506 logging.exception(e)
Ang Li93420002016-05-10 19:11:44 -0700507
Ang Li93420002016-05-10 19:11:44 -0700508 def startAdbLogcat(self):
509 """Starts a standing adb logcat collection in separate subprocesses and
510 save the logcat in a file.
511 """
512 if self.isAdbLogcatOn:
Ang Li7f0e1c72016-06-14 11:23:49 -0700513 raise AndroidDeviceError(("Android device %s already has an adb "
Ang Lie2139f12016-05-12 17:39:06 -0700514 "logcat thread going on. Cannot start "
Ang Li7f0e1c72016-06-14 11:23:49 -0700515 "another one.") % self.serial)
Ang Li7f0e1c72016-06-14 11:23:49 -0700516 f_name = "adblog,%s,%s.txt" % (self.model, self.serial)
Ang Li93420002016-05-10 19:11:44 -0700517 utils.create_dir(self.log_path)
518 logcat_file_path = os.path.join(self.log_path, f_name)
519 try:
520 extra_params = self.adb_logcat_param
521 except AttributeError:
522 extra_params = "-b all"
Ang Li7f0e1c72016-06-14 11:23:49 -0700523 cmd = "adb -s %s logcat -v threadtime %s >> %s" % (
Ang Li93420002016-05-10 19:11:44 -0700524 self.serial, extra_params, logcat_file_path)
525 self.adb_logcat_process = utils.start_standing_subprocess(cmd)
526 self.adb_logcat_file_path = logcat_file_path
527
528 def stopAdbLogcat(self):
529 """Stops the adb logcat collection subprocess.
530 """
531 if not self.isAdbLogcatOn:
Ang Li7f0e1c72016-06-14 11:23:49 -0700532 raise AndroidDeviceError(
533 "Android device %s does not have an ongoing adb logcat collection."
534 % self.serial)
Ang Li93420002016-05-10 19:11:44 -0700535 utils.stop_standing_subprocess(self.adb_logcat_process)
536 self.adb_logcat_process = None
537
538 def takeBugReport(self, test_name, begin_time):
539 """Takes a bug report on the device and stores it in a file.
540
541 Args:
542 test_name: Name of the test case that triggered this bug report.
543 begin_time: Logline format timestamp taken when the test started.
544 """
545 br_path = os.path.join(self.log_path, "BugReports")
546 utils.create_dir(br_path)
Ang Li7f0e1c72016-06-14 11:23:49 -0700547 base_name = ",%s,%s.txt" % (begin_time, self.serial)
Ang Li93420002016-05-10 19:11:44 -0700548 test_name_len = utils.MAX_FILENAME_LEN - len(base_name)
549 out_name = test_name[:test_name_len] + base_name
550 full_out_path = os.path.join(br_path, out_name.replace(' ', '\ '))
551 self.log.info("Taking bugreport for %s on %s", test_name, self.serial)
Ang Li7f0e1c72016-06-14 11:23:49 -0700552 self.adb.bugreport(" > %s" % full_out_path)
Ang Li93420002016-05-10 19:11:44 -0700553 self.log.info("Bugreport for %s taken at %s", test_name, full_out_path)
554
Ang Li93420002016-05-10 19:11:44 -0700555 @utils.timeout(15 * 60)
556 def waitForBootCompletion(self):
557 """Waits for Android framework to broadcast ACTION_BOOT_COMPLETED.
558
559 This function times out after 15 minutes.
560 """
Keun Soo Yim731e9172016-07-16 17:48:39 -0700561 try:
562 self.adb.wait_for_device()
563 except adb.AdbError as e:
564 # adb wait-for-device is not always possible in the lab
565 logging.exception(e)
Tri Vo175de122016-10-28 13:36:57 -0700566 while not self.hasBooted():
Ang Li93420002016-05-10 19:11:44 -0700567 time.sleep(5)
568
Tri Vo175de122016-10-28 13:36:57 -0700569 def hasBooted(self):
570 """Checks whether the device has booted.
571
572 Returns:
573 True if booted, False otherwise.
574 """
575 try:
576 out = self.adb.shell("getprop sys.boot_completed")
577 completed = out.decode('utf-8').strip()
578 if completed == '1':
579 return True
580 except adb.AdbError:
581 # adb shell calls may fail during certain period of booting
582 # process, which is normal. Ignoring these errors.
583 return False
584
Tri Vo091b4ac2016-12-06 15:49:38 -0800585 def stop(self):
586 """Stops Android runtime."""
587 self.adb.shell("stop")
588 self.adb.shell("setprop sys.boot_completed 0")
589
590 def start(self):
591 """Starts Android runtime and waits for ACTION_BOOT_COMPLETED."""
592 self.adb.shell("start")
593 self.waitForBootCompletion()
594
Tri Vo7ed0d642017-01-18 09:56:48 -0800595 def reboot(self, restart_services=True):
Ang Li7f0e1c72016-06-14 11:23:49 -0700596 """Reboots the device and wait for device to complete booting.
Ang Li93420002016-05-10 19:11:44 -0700597
598 This is probably going to print some error messages in console. Only
599 use if there's no other option.
600
Ang Li93420002016-05-10 19:11:44 -0700601 Raises:
602 AndroidDeviceError is raised if waiting for completion timed
603 out.
604 """
605 if self.isBootloaderMode:
606 self.fastboot.reboot()
607 return
Tri Vo7ed0d642017-01-18 09:56:48 -0800608
609 if restart_services:
610 has_adb_log = self.isAdbLogcatOn
611 has_vts_agent = True if self.vts_agent_process else False
612 if has_adb_log:
613 self.stopAdbLogcat()
614 if has_vts_agent:
615 self.stopVtsAgent()
616
Ang Li93420002016-05-10 19:11:44 -0700617 self.adb.reboot()
618 self.waitForBootCompletion()
619 self.rootAdb()
Tri Vo7ed0d642017-01-18 09:56:48 -0800620
621 if restart_services:
622 if has_adb_log:
623 self.startAdbLogcat()
624 if has_vts_agent:
625 self.startVtsAgent()
Sahil Jain06dd6a22016-06-24 13:47:37 -0700626
Ang Li6c303fc2016-09-22 13:19:33 -0700627 def startServices(self):
Ang Li53bb72b2016-07-19 18:29:37 -0700628 """Starts long running services on the android device.
629
630 1. Start adb logcat capture.
Ang Li6c303fc2016-09-22 13:19:33 -0700631 2. Start VtsAgent and create HalMirror unless disabled in config.
632 3. If enabled in config, start sl4a service and create sl4a clients.
Ang Li53bb72b2016-07-19 18:29:37 -0700633 """
Ang Li6c303fc2016-09-22 13:19:33 -0700634 enable_vts_agent = getattr(self, "enable_vts_agent", True)
635 enable_sl4a = getattr(self, "enable_sl4a", False)
Ang Li53bb72b2016-07-19 18:29:37 -0700636 try:
637 self.startAdbLogcat()
638 except:
639 self.log.exception("Failed to start adb logcat!")
640 raise
Ang Li6c303fc2016-09-22 13:19:33 -0700641 if enable_vts_agent:
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700642 self.startVtsAgent()
643 self.device_command_port = int(
644 self.adb.shell("cat /data/local/tmp/vts_tcp_server_port"))
645 logging.info("device_command_port: %s", self.device_command_port)
Ang Li6c303fc2016-09-22 13:19:33 -0700646 if not self.host_command_port:
647 self.host_command_port = adb.get_available_host_port()
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700648 self.adb.tcp_forward(self.host_command_port, self.device_command_port)
649 self.hal = hal_mirror.HalMirror(self.host_command_port,
650 self.host_callback_port)
651 self.lib = lib_mirror.LibMirror(self.host_command_port)
652 self.shell = shell_mirror.ShellMirror(self.host_command_port)
Ang Li6c303fc2016-09-22 13:19:33 -0700653 if enable_sl4a:
654 self.startSl4aClient()
Ang Li53bb72b2016-07-19 18:29:37 -0700655
656 def stopServices(self):
657 """Stops long running services on the android device.
658 """
659 if self.adb_logcat_process:
660 self.stopAdbLogcat()
661 self.stopVtsAgent()
662 if self.hal:
663 self.hal.CleanUp()
664
Ang Lie014a8b2016-06-28 18:24:52 -0700665 def startVtsAgent(self):
666 """Start HAL agent on the AndroidDevice.
Sahil Jain06dd6a22016-06-24 13:47:37 -0700667
668 This function starts the target side native agent and is persisted
Ang Lie014a8b2016-06-28 18:24:52 -0700669 throughout the test run.
Sahil Jain06dd6a22016-06-24 13:47:37 -0700670 """
Ang Li6c303fc2016-09-22 13:19:33 -0700671 self.log.info("Starting VTS agent")
Ang Lie014a8b2016-06-28 18:24:52 -0700672 if self.vts_agent_process:
673 raise AndroidDeviceError("HAL agent is already running on %s." %
674 self.serial)
Keun Soo Yima066dd52016-07-01 15:18:28 -0700675
676 cleanup_commands = [
Keun Soo Yim02da0272016-07-19 07:56:38 -0700677 "rm -f /data/local/tmp/vts_driver_*",
Ang Li53bb72b2016-07-19 18:29:37 -0700678 "rm -f /data/local/tmp/vts_agent_callback*"
679 ]
Keun Soo Yim2eecdfa2016-07-29 11:48:37 -0700680 kill_commands = ["killall vts_hal_agent32", "killall vts_hal_agent64",
681 "killall fuzzer32", "killall fuzzer64",
682 "killall vts_shell_driver32",
Yuexi Ma674e59d2016-07-19 15:39:54 -0700683 "killall vts_shell_driver64"]
Keun Soo Yima066dd52016-07-01 15:18:28 -0700684 cleanup_commands.extend(kill_commands)
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -0700685 chmod_commands = [
Keun Soo Yim2eecdfa2016-07-29 11:48:37 -0700686 "chmod 755 %s/32/vts_hal_agent32" % DEFAULT_AGENT_BASE_DIR,
687 "chmod 755 %s/64/vts_hal_agent64" % DEFAULT_AGENT_BASE_DIR,
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -0700688 "chmod 755 %s/32/fuzzer32" % DEFAULT_AGENT_BASE_DIR,
Keun Soo Yim02da0272016-07-19 07:56:38 -0700689 "chmod 755 %s/64/fuzzer64" % DEFAULT_AGENT_BASE_DIR,
690 "chmod 755 %s/32/vts_shell_driver32" % DEFAULT_AGENT_BASE_DIR,
Ang Li53bb72b2016-07-19 18:29:37 -0700691 "chmod 755 %s/64/vts_shell_driver64" % DEFAULT_AGENT_BASE_DIR
692 ]
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -0700693 cleanup_commands.extend(chmod_commands)
Keun Soo Yima066dd52016-07-01 15:18:28 -0700694 for cmd in cleanup_commands:
Sahil Jain06dd6a22016-06-24 13:47:37 -0700695 try:
696 self.adb.shell(cmd)
Keun Soo Yimab7fb062016-07-13 14:47:19 -0700697 except adb.AdbError as e:
698 self.log.warning(
Ang Li53bb72b2016-07-19 18:29:37 -0700699 "A command to setup the env to start the VTS Agent failed %s",
700 e)
Tri Vo843b57f2016-09-24 14:51:38 -0700701
702 bits = ['64', '32'] if self.is64Bit else ['32']
703 for bitness in bits:
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800704 vts_agent_log_path = os.path.join(self.log_path,
705 "vts_agent_" + bitness + ".log")
Keun Soo Yimd2aa5b82016-07-30 20:12:19 -0700706 cmd = (
707 'adb -s {s} shell LD_LIBRARY_PATH={path}/{bitness} '
708 '{path}/{bitness}/vts_hal_agent{bitness}'
709 ' {path}/32/fuzzer32 {path}/64/fuzzer64 {path}/spec'
710 ' {path}/32/vts_shell_driver32 {path}/64/vts_shell_driver64 >> {log}'
711 ).format(s=self.serial,
712 bitness=bitness,
713 path=DEFAULT_AGENT_BASE_DIR,
714 log=vts_agent_log_path)
715 try:
716 self.vts_agent_process = utils.start_standing_subprocess(
717 cmd, check_health_delay=1)
718 except utils.VTSUtilsError as e:
719 logging.exception(e)
720 with open(vts_agent_log_path, 'r') as log_file:
721 logging.error("VTS agent output:\n")
722 logging.error(log_file.read())
723 # one common cause is that 64-bit executable is not supported
724 # in low API level devices.
725 if bitness == '32':
726 raise
727 else:
728 logging.error('retrying using a 32-bit binary.')
Sahil Jain06dd6a22016-06-24 13:47:37 -0700729
Ang Lie014a8b2016-06-28 18:24:52 -0700730 def stopVtsAgent(self):
731 """Stop the HAL agent running on the AndroidDevice.
Sahil Jain06dd6a22016-06-24 13:47:37 -0700732 """
Ang Lie014a8b2016-06-28 18:24:52 -0700733 if self.vts_agent_process:
734 utils.stop_standing_subprocess(self.vts_agent_process)
735 self.vts_agent_process = None
Sahil Jain06dd6a22016-06-24 13:47:37 -0700736
Keun Soo Yime34754e2016-08-15 11:25:15 -0700737 @property
738 def product_type(self):
739 """Gets the product type name."""
740 return self._product_type
741
Ang Li6c303fc2016-09-22 13:19:33 -0700742 # Code for using SL4A client
743 def startSl4aClient(self, handle_event=True):
744 """Create an sl4a connection to the device.
745
746 Return the connection handler 'droid'. By default, another connection
747 on the same session is made for EventDispatcher, and the dispatcher is
748 returned to the caller as well.
749 If sl4a server is not started on the device, try to start it.
750
751 Args:
752 handle_event: True if this droid session will need to handle
753 events.
754 """
755 self._sl4a_sessions = {}
756 self._sl4a_event_dispatchers = {}
757 if not self.sl4a_host_port or not adb.is_port_available(self.sl4a_host_port):
758 self.sl4a_host_port = adb.get_available_host_port()
759 self.adb.tcp_forward(self.sl4a_host_port, self.sl4a_target_port)
760 try:
761 droid = self._createNewSl4aSession()
762 except sl4a_client.Error:
763 sl4a_client.start_sl4a(self.adb)
764 droid = self._createNewSl4aSession()
765 self.sl4a = droid
766 if handle_event:
767 ed = self._getSl4aEventDispatcher(droid)
768 self.sl4a_event = ed
769
770 def _getSl4aEventDispatcher(self, droid):
771 """Return an EventDispatcher for an sl4a session
772
773 Args:
774 droid: Session to create EventDispatcher for.
775
776 Returns:
777 ed: An EventDispatcher for specified session.
778 """
779 # TODO (angli): Move service-specific start/stop functions out of
780 # android_device, including VTS Agent, SL4A, and any other
781 # target-side services.
782 ed_key = self.serial + str(droid.uid)
783 if ed_key in self._sl4a_event_dispatchers:
784 if self._sl4a_event_dispatchers[ed_key] is None:
785 raise AndroidDeviceError("EventDispatcher Key Empty")
786 self.log.debug("Returning existing key %s for event dispatcher!",
787 ed_key)
788 return self._sl4a_event_dispatchers[ed_key]
789 event_droid = self._addNewConnectionToSl4aSession(droid.uid)
790 ed = event_dispatcher.EventDispatcher(event_droid)
791 self._sl4a_event_dispatchers[ed_key] = ed
792 return ed
793
794 def _createNewSl4aSession(self):
795 """Start a new session in sl4a.
796
797 Also caches the droid in a dict with its uid being the key.
798
799 Returns:
800 An Android object used to communicate with sl4a on the android
801 device.
802
803 Raises:
804 sl4a_client.Error: Something is wrong with sl4a and it returned an
805 existing uid to a new session.
806 """
807 droid = sl4a_client.Sl4aClient(port=self.sl4a_host_port)
808 droid.open()
809 if droid.uid in self._sl4a_sessions:
810 raise sl4a_client.Error(
811 "SL4A returned an existing uid for a new session. Abort.")
812 self._sl4a_sessions[droid.uid] = [droid]
813 return droid
814
815 def _addNewConnectionToSl4aSession(self, session_id):
816 """Create a new connection to an existing sl4a session.
817
818 Args:
819 session_id: UID of the sl4a session to add connection to.
820
821 Returns:
822 An Android object used to communicate with sl4a on the android
823 device.
824
825 Raises:
826 DoesNotExistError: Raised if the session it's trying to connect to
827 does not exist.
828 """
829 if session_id not in self._sl4a_sessions:
830 raise DoesNotExistError("Session %d doesn't exist." % session_id)
831 droid = sl4a_client.Sl4aClient(port=self.sl4a_host_port, uid=session_id)
832 droid.open(cmd=sl4a_client.Sl4aCommand.CONTINUE)
833 return droid
834
835 def _terminateSl4aSession(self, session_id):
836 """Terminate a session in sl4a.
837
838 Send terminate signal to sl4a server; stop dispatcher associated with
839 the session. Clear corresponding droids and dispatchers from cache.
840
841 Args:
842 session_id: UID of the sl4a session to terminate.
843 """
844 if self._sl4a_sessions and (session_id in self._sl4a_sessions):
845 for droid in self._sl4a_sessions[session_id]:
846 droid.closeSl4aSession()
847 droid.close()
848 del self._sl4a_sessions[session_id]
849 ed_key = self.serial + str(session_id)
850 if ed_key in self._sl4a_event_dispatchers:
851 self._sl4a_event_dispatchers[ed_key].clean_up()
852 del self._sl4a_event_dispatchers[ed_key]
853
854 def _terminateAllSl4aSessions(self):
855 """Terminate all sl4a sessions on the AndroidDevice instance.
856
857 Terminate all sessions and clear caches.
858 """
859 if self._sl4a_sessions:
860 session_ids = list(self._sl4a_sessions.keys())
861 for session_id in session_ids:
862 try:
863 self._terminateSl4aSession(session_id)
864 except:
865 self.log.exception("Failed to terminate session %d.",
866 session_id)
867 if self.sl4a_host_port:
868 self.adb.forward("--remove tcp:%d" % self.sl4a_host_port)
869 self.sl4a_host_port = None
870
Sahil Jain06dd6a22016-06-24 13:47:37 -0700871
Ang Lie014a8b2016-06-28 18:24:52 -0700872class AndroidDeviceLoggerAdapter(logging.LoggerAdapter):
873 """A wrapper class that attaches a prefix to all log lines from an
874 AndroidDevice object.
875 """
876
877 def process(self, msg, kwargs):
878 """Process every log message written via the wrapped logger object.
879
880 We are adding the prefix "[AndroidDevice|<serial>]" to all log lines.
881
882 Args:
883 msg: string, the original log message.
884 kwargs: dict, the key value pairs that can be used to modify the
885 original log message.
886 """
887 msg = "[AndroidDevice|%s] %s" % (self.extra["serial"], msg)
888 return (msg, kwargs)