blob: 1b31091681633adc66212d86066b0edaf5302c9c [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
Ang Li6c303fc2016-09-22 13:19:33 -070065def create(configs):
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.
71
72 Returns:
73 A list of AndroidDevice objects.
74 """
Ang Li93420002016-05-10 19:11:44 -070075 if not configs:
76 raise AndroidDeviceError(ANDROID_DEVICE_EMPTY_CONFIG_MSG)
77 elif configs == ANDROID_DEVICE_PICK_ALL_TOKEN:
Ang Li7f0e1c72016-06-14 11:23:49 -070078 ads = get_all_instances()
Ang Li93420002016-05-10 19:11:44 -070079 elif not isinstance(configs, list):
80 raise AndroidDeviceError(ANDROID_DEVICE_NOT_LIST_CONFIG_MSG)
81 elif isinstance(configs[0], str):
82 # Configs is a list of serials.
Ang Li7f0e1c72016-06-14 11:23:49 -070083 ads = get_instances(configs)
Ang Li93420002016-05-10 19:11:44 -070084 else:
85 # Configs is a list of dicts.
Ang Li7f0e1c72016-06-14 11:23:49 -070086 ads = get_instances_with_configs(configs)
Ang Li93420002016-05-10 19:11:44 -070087 connected_ads = list_adb_devices()
88 for ad in ads:
89 if ad.serial not in connected_ads:
Ang Li53bb72b2016-07-19 18:29:37 -070090 raise DoesNotExistError(("Android device %s is specified in config"
91 " but is not attached.") % ad.serial)
Ang Li6c303fc2016-09-22 13:19:33 -070092 _startServicesOnAds(ads)
Ang Li93420002016-05-10 19:11:44 -070093 return ads
94
Ang Lie2139f12016-05-12 17:39:06 -070095
Ang Li93420002016-05-10 19:11:44 -070096def destroy(ads):
Ang Li53bb72b2016-07-19 18:29:37 -070097 """Cleans up AndroidDevice objects.
98
99 Args:
100 ads: A list of AndroidDevice objects.
101 """
Ang Li93420002016-05-10 19:11:44 -0700102 for ad in ads:
Ang Li53bb72b2016-07-19 18:29:37 -0700103 try:
104 ad.cleanUp()
105 except:
106 ad.log.exception("Failed to clean up properly.")
107
108
Ang Li6c303fc2016-09-22 13:19:33 -0700109def _startServicesOnAds(ads):
Ang Li53bb72b2016-07-19 18:29:37 -0700110 """Starts long running services on multiple AndroidDevice objects.
111
112 If any one AndroidDevice object fails to start services, cleans up all
113 existing AndroidDevice objects and their services.
114
115 Args:
116 ads: A list of AndroidDevice objects whose services to start.
117 """
118 running_ads = []
119 for ad in ads:
120 running_ads.append(ad)
121 try:
Ang Li6c303fc2016-09-22 13:19:33 -0700122 ad.startServices()
Ang Li53bb72b2016-07-19 18:29:37 -0700123 except:
124 ad.log.exception("Failed to start some services, abort!")
125 destroy(running_ads)
126 raise
Ang Li93420002016-05-10 19:11:44 -0700127
Ang Lie2139f12016-05-12 17:39:06 -0700128
Ang Li93420002016-05-10 19:11:44 -0700129def _parse_device_list(device_list_str, key):
130 """Parses a byte string representing a list of devices. The string is
131 generated by calling either adb or fastboot.
132
133 Args:
134 device_list_str: Output of adb or fastboot.
135 key: The token that signifies a device in device_list_str.
136
137 Returns:
138 A list of android device serial numbers.
139 """
140 clean_lines = str(device_list_str, 'utf-8').strip().split('\n')
141 results = []
142 for line in clean_lines:
143 tokens = line.strip().split('\t')
144 if len(tokens) == 2 and tokens[1] == key:
145 results.append(tokens[0])
146 return results
147
Ang Lie2139f12016-05-12 17:39:06 -0700148
Ang Li93420002016-05-10 19:11:44 -0700149def list_adb_devices():
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700150 """List all target devices connected to the host and detected by adb.
Ang Li93420002016-05-10 19:11:44 -0700151
152 Returns:
153 A list of android device serials. Empty if there's none.
154 """
155 out = adb.AdbProxy().devices()
156 return _parse_device_list(out, "device")
157
Ang Lie2139f12016-05-12 17:39:06 -0700158
Ang Li93420002016-05-10 19:11:44 -0700159def list_fastboot_devices():
160 """List all android devices connected to the computer that are in in
161 fastboot mode. These are detected by fastboot.
162
163 Returns:
164 A list of android device serials. Empty if there's none.
165 """
166 out = fastboot.FastbootProxy().devices()
167 return _parse_device_list(out, "fastboot")
168
Ang Lie2139f12016-05-12 17:39:06 -0700169
Ang Li7f0e1c72016-06-14 11:23:49 -0700170def get_instances(serials):
Ang Li93420002016-05-10 19:11:44 -0700171 """Create AndroidDevice instances from a list of serials.
172
173 Args:
174 serials: A list of android device serials.
Ang Li93420002016-05-10 19:11:44 -0700175
176 Returns:
177 A list of AndroidDevice objects.
178 """
179 results = []
180 for s in serials:
Ang Li7f0e1c72016-06-14 11:23:49 -0700181 results.append(AndroidDevice(s))
Ang Li93420002016-05-10 19:11:44 -0700182 return results
183
Ang Lie2139f12016-05-12 17:39:06 -0700184
Ang Li7f0e1c72016-06-14 11:23:49 -0700185def get_instances_with_configs(configs):
Ang Li93420002016-05-10 19:11:44 -0700186 """Create AndroidDevice instances from a list of json configs.
187
188 Each config should have the required key-value pair "serial".
189
190 Args:
191 configs: A list of dicts each representing the configuration of one
192 android device.
Ang Li93420002016-05-10 19:11:44 -0700193
194 Returns:
195 A list of AndroidDevice objects.
196 """
197 results = []
198 for c in configs:
199 try:
Keun Soo Yime34754e2016-08-15 11:25:15 -0700200 serial = c.pop(keys.ConfigKeys.IKEY_SERIAL)
Ang Li93420002016-05-10 19:11:44 -0700201 except KeyError:
Keun Soo Yime34754e2016-08-15 11:25:15 -0700202 raise AndroidDeviceError(
203 ('Required value %s is missing in '
204 'AndroidDevice config %s.') % (keys.ConfigKeys.IKEY_SERIAL,
205 c))
206 try:
207 product_type = c.pop(keys.ConfigKeys.IKEY_PRODUCT_TYPE)
208 except KeyError:
209 logging.error(
210 'Required value %s is missing in '
211 'AndroidDevice config %s.',
212 keys.ConfigKeys.IKEY_PRODUCT_TYPE, c)
213 product_type = ANDROID_PRODUCT_TYPE_UNKNOWN
214
215 ad = AndroidDevice(serial, product_type)
Ang Li93420002016-05-10 19:11:44 -0700216 ad.loadConfig(c)
217 results.append(ad)
218 return results
219
Ang Lie2139f12016-05-12 17:39:06 -0700220
Ang Li7f0e1c72016-06-14 11:23:49 -0700221def get_all_instances(include_fastboot=False):
Ang Li93420002016-05-10 19:11:44 -0700222 """Create AndroidDevice instances for all attached android devices.
223
224 Args:
225 include_fastboot: Whether to include devices in bootloader mode or not.
Ang Li93420002016-05-10 19:11:44 -0700226
227 Returns:
228 A list of AndroidDevice objects each representing an android device
229 attached to the computer.
230 """
231 if include_fastboot:
232 serial_list = list_adb_devices() + list_fastboot_devices()
Ang Li7f0e1c72016-06-14 11:23:49 -0700233 return get_instances(serial_list)
234 return get_instances(list_adb_devices())
Ang Li93420002016-05-10 19:11:44 -0700235
Ang Lie2139f12016-05-12 17:39:06 -0700236
Ang Li93420002016-05-10 19:11:44 -0700237def filter_devices(ads, func):
238 """Finds the AndroidDevice instances from a list that match certain
239 conditions.
240
241 Args:
242 ads: A list of AndroidDevice instances.
243 func: A function that takes an AndroidDevice object and returns True
244 if the device satisfies the filter condition.
245
246 Returns:
247 A list of AndroidDevice instances that satisfy the filter condition.
248 """
249 results = []
250 for ad in ads:
251 if func(ad):
252 results.append(ad)
253 return results
254
Ang Lie2139f12016-05-12 17:39:06 -0700255
Ang Li93420002016-05-10 19:11:44 -0700256def get_device(ads, **kwargs):
257 """Finds a unique AndroidDevice instance from a list that has specific
258 attributes of certain values.
259
260 Example:
261 get_device(android_devices, label="foo", phone_number="1234567890")
262 get_device(android_devices, model="angler")
263
264 Args:
265 ads: A list of AndroidDevice instances.
266 kwargs: keyword arguments used to filter AndroidDevice instances.
267
268 Returns:
269 The target AndroidDevice instance.
270
271 Raises:
272 AndroidDeviceError is raised if none or more than one device is
273 matched.
274 """
Ang Lie2139f12016-05-12 17:39:06 -0700275
Ang Li93420002016-05-10 19:11:44 -0700276 def _get_device_filter(ad):
277 for k, v in kwargs.items():
278 if not hasattr(ad, k):
279 return False
280 elif getattr(ad, k) != v:
281 return False
282 return True
Ang Lie2139f12016-05-12 17:39:06 -0700283
Ang Li93420002016-05-10 19:11:44 -0700284 filtered = filter_devices(ads, _get_device_filter)
285 if not filtered:
286 raise AndroidDeviceError(("Could not find a target device that matches"
287 " condition: %s.") % kwargs)
288 elif len(filtered) == 1:
289 return filtered[0]
290 else:
291 serials = [ad.serial for ad in filtered]
292 raise AndroidDeviceError("More than one device matched: %s" % serials)
293
Ang Lie2139f12016-05-12 17:39:06 -0700294
Ang Li93420002016-05-10 19:11:44 -0700295def takeBugReports(ads, test_name, begin_time):
296 """Takes bug reports on a list of android devices.
297
298 If you want to take a bug report, call this function with a list of
299 android_device objects in on_fail. But reports will be taken on all the
300 devices in the list concurrently. Bug report takes a relative long
301 time to take, so use this cautiously.
302
303 Args:
304 ads: A list of AndroidDevice instances.
305 test_name: Name of the test case that triggered this bug report.
306 begin_time: Logline format timestamp taken when the test started.
307 """
308 begin_time = vts_logger.normalizeLogLineTimestamp(begin_time)
Ang Lie2139f12016-05-12 17:39:06 -0700309
Ang Li93420002016-05-10 19:11:44 -0700310 def take_br(test_name, begin_time, ad):
311 ad.takeBugReport(test_name, begin_time)
Ang Lie2139f12016-05-12 17:39:06 -0700312
Ang Li93420002016-05-10 19:11:44 -0700313 args = [(test_name, begin_time, ad) for ad in ads]
314 utils.concurrent_exec(take_br, args)
315
Ang Lie2139f12016-05-12 17:39:06 -0700316
Ang Li7f0e1c72016-06-14 11:23:49 -0700317class AndroidDevice(object):
Ang Li93420002016-05-10 19:11:44 -0700318 """Class representing an android device.
319
Ang Li53bb72b2016-07-19 18:29:37 -0700320 Each object of this class represents one Android device. The object holds
321 handles to adb, fastboot, and various RPC clients.
Ang Li93420002016-05-10 19:11:44 -0700322
323 Attributes:
Keun Soo Yime34754e2016-08-15 11:25:15 -0700324 serial: A string that's the serial number of the Android device.
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700325 device_command_port: int, the port number used on the Android device
326 for adb port forwarding (for command-response sessions).
327 device_callback_port: int, the port number used on the Android device
328 for adb port reverse forwarding (for callback sessions).
Ang Lie014a8b2016-06-28 18:24:52 -0700329 log: A logger project with a device-specific prefix for each line -
330 [AndroidDevice|<serial>]
Ang Li93420002016-05-10 19:11:44 -0700331 log_path: A string that is the path where all logs collected on this
332 android device should be stored.
333 adb_logcat_process: A process that collects the adb logcat.
334 adb_logcat_file_path: A string that's the full path to the adb logcat
335 file collected, if any.
Ang Lie014a8b2016-06-28 18:24:52 -0700336 vts_agent_process: A process that runs the HAL agent.
Ang Li93420002016-05-10 19:11:44 -0700337 adb: An AdbProxy object used for interacting with the device via adb.
338 fastboot: A FastbootProxy object used for interacting with the device
339 via fastboot.
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700340 host_command_port: the host-side port for runner to agent sessions
341 (to send commands and receive responses).
342 host_callback_port: the host-side port for agent to runner sessions
343 (to get callbacks from agent).
Ang Li53bb72b2016-07-19 18:29:37 -0700344 hal: HalMirror, in charge of all communications with the HAL layer.
345 lib: LibMirror, in charge of all communications with static and shared
346 native libs.
347 shell: ShellMirror, in charge of all communications with shell.
Keun Soo Yime34754e2016-08-15 11:25:15 -0700348 _product_type: A string, the device product type (e.g., bullhead) if
349 known, ANDROID_PRODUCT_TYPE_UNKNOWN otherwise.
Ang Li93420002016-05-10 19:11:44 -0700350 """
351
Keun Soo Yime34754e2016-08-15 11:25:15 -0700352 def __init__(self, serial="", product_type=ANDROID_PRODUCT_TYPE_UNKNOWN,
353 device_callback_port=5010):
Ang Li93420002016-05-10 19:11:44 -0700354 self.serial = serial
Keun Soo Yime34754e2016-08-15 11:25:15 -0700355 self._product_type = product_type
Keun Soo Yimf5d0bca2016-07-30 23:59:26 -0700356 self.device_command_port = None
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700357 self.device_callback_port = device_callback_port
Ang Lie014a8b2016-06-28 18:24:52 -0700358 self.log = AndroidDeviceLoggerAdapter(logging.getLogger(),
359 {"serial": self.serial})
360 base_log_path = getattr(logging, "log_path", "/tmp/logs/")
Ang Li7f0e1c72016-06-14 11:23:49 -0700361 self.log_path = os.path.join(base_log_path, "AndroidDevice%s" % serial)
Ang Li93420002016-05-10 19:11:44 -0700362 self.adb_logcat_process = None
363 self.adb_logcat_file_path = None
Ang Lie014a8b2016-06-28 18:24:52 -0700364 self.vts_agent_process = None
Ang Li93420002016-05-10 19:11:44 -0700365 self.adb = adb.AdbProxy(serial)
366 self.fastboot = fastboot.FastbootProxy(serial)
367 if not self.isBootloaderMode:
368 self.rootAdb()
Ang Li6c303fc2016-09-22 13:19:33 -0700369 self.host_command_port = None
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700370 self.host_callback_port = adb.get_available_host_port()
Ang Lie014a8b2016-06-28 18:24:52 -0700371 self.adb.reverse_tcp_forward(self.device_callback_port,
372 self.host_callback_port)
Ang Li53bb72b2016-07-19 18:29:37 -0700373 self.hal = None
Keun Soo Yimf5d0bca2016-07-30 23:59:26 -0700374 self.lib = None
375 self.shell = None
Ang Li6c303fc2016-09-22 13:19:33 -0700376 self.sl4a_host_port = None
377 # TODO: figure out a good way to detect which port is available
378 # on the target side, instead of hard coding a port number.
379 self.sl4a_target_port = 8082
Ang Li93420002016-05-10 19:11:44 -0700380
381 def __del__(self):
Ang Li53bb72b2016-07-19 18:29:37 -0700382 self.cleanUp()
383
384 def cleanUp(self):
385 """Cleans up the AndroidDevice object and releases any resources it
386 claimed.
387 """
388 self.stopServices()
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700389 if self.host_command_port:
390 self.adb.forward("--remove tcp:%s" % self.host_command_port)
Ang Li6c303fc2016-09-22 13:19:33 -0700391 self.host_command_port = None
392 if self.sl4a_host_port:
393 self.adb.forward("--remove tcp:%s" % self.sl4a_host_port)
394 self.sl4a_host_port = None
Ang Li93420002016-05-10 19:11:44 -0700395
396 @property
397 def isBootloaderMode(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700398 """True if the device is in bootloader mode."""
Ang Li93420002016-05-10 19:11:44 -0700399 return self.serial in list_fastboot_devices()
400
401 @property
402 def isAdbRoot(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700403 """True if adb is running as root for this device."""
404 id_str = self.adb.shell("id -u").decode("utf-8")
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700405 return "root" in id_str
Ang Li93420002016-05-10 19:11:44 -0700406
407 @property
Tri Voe1a5a852016-10-20 19:59:45 -0700408 def verityEnabled(self):
409 """True if verity is enabled for this device."""
410 try:
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800411 verified = self.adb.shell('getprop partition.system.verified').decode("utf-8")
412 if not verified:
413 return False
Tri Voe1a5a852016-10-20 19:59:45 -0700414 except adb.AdbError:
415 # If verity is disabled, there is no property 'partition.system.verified'
416 return False
417 return True
418
419 @property
Ang Li93420002016-05-10 19:11:44 -0700420 def model(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700421 """The Android code name for the device."""
Ang Li93420002016-05-10 19:11:44 -0700422 # If device is in bootloader mode, get mode name from fastboot.
423 if self.isBootloaderMode:
424 out = self.fastboot.getvar("product").strip()
425 # "out" is never empty because of the "total time" message fastboot
426 # writes to stderr.
427 lines = out.decode("utf-8").split('\n', 1)
428 if lines:
429 tokens = lines[0].split(' ')
430 if len(tokens) > 1:
431 return tokens[1].lower()
432 return None
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800433 out = self.adb.shell('getprop ro.build.product')
434 model = out.decode("utf-8").strip().lower()
Ang Li93420002016-05-10 19:11:44 -0700435 if model == "sprout":
436 return model
437 else:
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800438 out = self.adb.shell('getprop ro.product.name')
439 model = out.decode("utf-8").strip().lower()
Ang Li93420002016-05-10 19:11:44 -0700440 return model
441
442 @property
Tri Vo921bfa02016-09-20 10:25:23 -0700443 def cpu_abi(self):
444 """CPU ABI (Application Binary Interface) of the device."""
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800445 out = self.adb.shell('getprop ro.product.cpu.abi')
Tri Vo921bfa02016-09-20 10:25:23 -0700446 if not out:
447 return "unknown"
448
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800449 cpu_abi = out.decode("utf-8").strip().lower()
Tri Vo921bfa02016-09-20 10:25:23 -0700450 return cpu_abi
451
452 @property
Tri Vof07f1292016-09-21 17:27:46 -0700453 def is64Bit(self):
454 """True if device is 64 bit."""
455 out = self.adb.shell('uname -m')
456 return "64" in out
457
458 @property
Hsin-Yi Chen8a863ec2016-12-29 18:46:14 +0800459 def libPaths(self):
460 """List of strings representing the paths to the native library directories."""
461 paths_32 = ["/system/lib", "/vendor/lib"]
462 if self.is64Bit:
463 paths_64 = ["/system/lib64", "/vendor/lib64"]
464 paths_64.extend(paths_32)
465 return paths_64
466 return paths_32
467
468 @property
Ang Li93420002016-05-10 19:11:44 -0700469 def isAdbLogcatOn(self):
470 """Whether there is an ongoing adb logcat collection.
471 """
472 if self.adb_logcat_process:
473 return True
474 return False
475
476 def loadConfig(self, config):
477 """Add attributes to the AndroidDevice object based on json config.
478
479 Args:
480 config: A dictionary representing the configs.
481
482 Raises:
483 AndroidDeviceError is raised if the config is trying to overwrite
484 an existing attribute.
485 """
486 for k, v in config.items():
487 if hasattr(self, k):
Ang Li7f0e1c72016-06-14 11:23:49 -0700488 raise AndroidDeviceError(
489 "Attempting to set existing attribute %s on %s" %
490 (k, self.serial))
Ang Li93420002016-05-10 19:11:44 -0700491 setattr(self, k, v)
492
493 def rootAdb(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700494 """Changes adb to root mode for this device."""
Ang Li93420002016-05-10 19:11:44 -0700495 if not self.isAdbRoot:
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700496 try:
497 self.adb.root()
Keun Soo Yima5a0dc22016-07-16 17:56:19 -0700498 self.adb.wait_for_device()
499 self.adb.remount()
Keun Soo Yim731e9172016-07-16 17:48:39 -0700500 self.adb.wait_for_device()
501 except adb.AdbError as e:
502 # adb wait-for-device is not always possible in the lab
Keun Soo Yima5a0dc22016-07-16 17:56:19 -0700503 # continue with an assumption it's done by the harness.
Keun Soo Yim731e9172016-07-16 17:48:39 -0700504 logging.exception(e)
Ang Li93420002016-05-10 19:11:44 -0700505
Ang Li93420002016-05-10 19:11:44 -0700506 def startAdbLogcat(self):
507 """Starts a standing adb logcat collection in separate subprocesses and
508 save the logcat in a file.
509 """
510 if self.isAdbLogcatOn:
Ang Li7f0e1c72016-06-14 11:23:49 -0700511 raise AndroidDeviceError(("Android device %s already has an adb "
Ang Lie2139f12016-05-12 17:39:06 -0700512 "logcat thread going on. Cannot start "
Ang Li7f0e1c72016-06-14 11:23:49 -0700513 "another one.") % self.serial)
Ang Li7f0e1c72016-06-14 11:23:49 -0700514 f_name = "adblog,%s,%s.txt" % (self.model, self.serial)
Ang Li93420002016-05-10 19:11:44 -0700515 utils.create_dir(self.log_path)
516 logcat_file_path = os.path.join(self.log_path, f_name)
517 try:
518 extra_params = self.adb_logcat_param
519 except AttributeError:
520 extra_params = "-b all"
Ang Li7f0e1c72016-06-14 11:23:49 -0700521 cmd = "adb -s %s logcat -v threadtime %s >> %s" % (
Ang Li93420002016-05-10 19:11:44 -0700522 self.serial, extra_params, logcat_file_path)
523 self.adb_logcat_process = utils.start_standing_subprocess(cmd)
524 self.adb_logcat_file_path = logcat_file_path
525
526 def stopAdbLogcat(self):
527 """Stops the adb logcat collection subprocess.
528 """
529 if not self.isAdbLogcatOn:
Ang Li7f0e1c72016-06-14 11:23:49 -0700530 raise AndroidDeviceError(
531 "Android device %s does not have an ongoing adb logcat collection."
532 % self.serial)
Ang Li93420002016-05-10 19:11:44 -0700533 utils.stop_standing_subprocess(self.adb_logcat_process)
534 self.adb_logcat_process = None
535
536 def takeBugReport(self, test_name, begin_time):
537 """Takes a bug report on the device and stores it in a file.
538
539 Args:
540 test_name: Name of the test case that triggered this bug report.
541 begin_time: Logline format timestamp taken when the test started.
542 """
543 br_path = os.path.join(self.log_path, "BugReports")
544 utils.create_dir(br_path)
Ang Li7f0e1c72016-06-14 11:23:49 -0700545 base_name = ",%s,%s.txt" % (begin_time, self.serial)
Ang Li93420002016-05-10 19:11:44 -0700546 test_name_len = utils.MAX_FILENAME_LEN - len(base_name)
547 out_name = test_name[:test_name_len] + base_name
548 full_out_path = os.path.join(br_path, out_name.replace(' ', '\ '))
549 self.log.info("Taking bugreport for %s on %s", test_name, self.serial)
Ang Li7f0e1c72016-06-14 11:23:49 -0700550 self.adb.bugreport(" > %s" % full_out_path)
Ang Li93420002016-05-10 19:11:44 -0700551 self.log.info("Bugreport for %s taken at %s", test_name, full_out_path)
552
Ang Li93420002016-05-10 19:11:44 -0700553 @utils.timeout(15 * 60)
554 def waitForBootCompletion(self):
555 """Waits for Android framework to broadcast ACTION_BOOT_COMPLETED.
556
557 This function times out after 15 minutes.
558 """
Keun Soo Yim731e9172016-07-16 17:48:39 -0700559 try:
560 self.adb.wait_for_device()
561 except adb.AdbError as e:
562 # adb wait-for-device is not always possible in the lab
563 logging.exception(e)
Tri Vo175de122016-10-28 13:36:57 -0700564 while not self.hasBooted():
Ang Li93420002016-05-10 19:11:44 -0700565 time.sleep(5)
566
Tri Vo175de122016-10-28 13:36:57 -0700567 def hasBooted(self):
568 """Checks whether the device has booted.
569
570 Returns:
571 True if booted, False otherwise.
572 """
573 try:
574 out = self.adb.shell("getprop sys.boot_completed")
575 completed = out.decode('utf-8').strip()
576 if completed == '1':
577 return True
578 except adb.AdbError:
579 # adb shell calls may fail during certain period of booting
580 # process, which is normal. Ignoring these errors.
581 return False
582
Tri Vo091b4ac2016-12-06 15:49:38 -0800583 def stop(self):
584 """Stops Android runtime."""
585 self.adb.shell("stop")
586 self.adb.shell("setprop sys.boot_completed 0")
587
588 def start(self):
589 """Starts Android runtime and waits for ACTION_BOOT_COMPLETED."""
590 self.adb.shell("start")
591 self.waitForBootCompletion()
592
Ang Li93420002016-05-10 19:11:44 -0700593 def reboot(self):
Ang Li7f0e1c72016-06-14 11:23:49 -0700594 """Reboots the device and wait for device to complete booting.
Ang Li93420002016-05-10 19:11:44 -0700595
596 This is probably going to print some error messages in console. Only
597 use if there's no other option.
598
Ang Li93420002016-05-10 19:11:44 -0700599 Raises:
600 AndroidDeviceError is raised if waiting for completion timed
601 out.
602 """
603 if self.isBootloaderMode:
604 self.fastboot.reboot()
605 return
606 has_adb_log = self.isAdbLogcatOn
Ang Lie014a8b2016-06-28 18:24:52 -0700607 has_vts_agent = True if self.vts_agent_process else False
Ang Li93420002016-05-10 19:11:44 -0700608 if has_adb_log:
609 self.stopAdbLogcat()
Ang Lie014a8b2016-06-28 18:24:52 -0700610 if has_vts_agent:
611 self.stopVtsAgent()
Ang Li93420002016-05-10 19:11:44 -0700612 self.adb.reboot()
613 self.waitForBootCompletion()
614 self.rootAdb()
Ang Li93420002016-05-10 19:11:44 -0700615 if has_adb_log:
616 self.startAdbLogcat()
Ang Lie014a8b2016-06-28 18:24:52 -0700617 if has_vts_agent:
618 self.startVtsAgent()
Sahil Jain06dd6a22016-06-24 13:47:37 -0700619
Ang Li6c303fc2016-09-22 13:19:33 -0700620 def startServices(self):
Ang Li53bb72b2016-07-19 18:29:37 -0700621 """Starts long running services on the android device.
622
623 1. Start adb logcat capture.
Ang Li6c303fc2016-09-22 13:19:33 -0700624 2. Start VtsAgent and create HalMirror unless disabled in config.
625 3. If enabled in config, start sl4a service and create sl4a clients.
Ang Li53bb72b2016-07-19 18:29:37 -0700626 """
Ang Li6c303fc2016-09-22 13:19:33 -0700627 enable_vts_agent = getattr(self, "enable_vts_agent", True)
628 enable_sl4a = getattr(self, "enable_sl4a", False)
Ang Li53bb72b2016-07-19 18:29:37 -0700629 try:
630 self.startAdbLogcat()
631 except:
632 self.log.exception("Failed to start adb logcat!")
633 raise
Ang Li6c303fc2016-09-22 13:19:33 -0700634 if enable_vts_agent:
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700635 self.startVtsAgent()
636 self.device_command_port = int(
637 self.adb.shell("cat /data/local/tmp/vts_tcp_server_port"))
638 logging.info("device_command_port: %s", self.device_command_port)
Ang Li6c303fc2016-09-22 13:19:33 -0700639 if not self.host_command_port:
640 self.host_command_port = adb.get_available_host_port()
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700641 self.adb.tcp_forward(self.host_command_port, self.device_command_port)
642 self.hal = hal_mirror.HalMirror(self.host_command_port,
643 self.host_callback_port)
644 self.lib = lib_mirror.LibMirror(self.host_command_port)
645 self.shell = shell_mirror.ShellMirror(self.host_command_port)
Ang Li6c303fc2016-09-22 13:19:33 -0700646 if enable_sl4a:
647 self.startSl4aClient()
Ang Li53bb72b2016-07-19 18:29:37 -0700648
649 def stopServices(self):
650 """Stops long running services on the android device.
651 """
652 if self.adb_logcat_process:
653 self.stopAdbLogcat()
654 self.stopVtsAgent()
655 if self.hal:
656 self.hal.CleanUp()
657
Ang Lie014a8b2016-06-28 18:24:52 -0700658 def startVtsAgent(self):
659 """Start HAL agent on the AndroidDevice.
Sahil Jain06dd6a22016-06-24 13:47:37 -0700660
661 This function starts the target side native agent and is persisted
Ang Lie014a8b2016-06-28 18:24:52 -0700662 throughout the test run.
Sahil Jain06dd6a22016-06-24 13:47:37 -0700663 """
Ang Li6c303fc2016-09-22 13:19:33 -0700664 self.log.info("Starting VTS agent")
Ang Lie014a8b2016-06-28 18:24:52 -0700665 if self.vts_agent_process:
666 raise AndroidDeviceError("HAL agent is already running on %s." %
667 self.serial)
Keun Soo Yima066dd52016-07-01 15:18:28 -0700668
669 cleanup_commands = [
Keun Soo Yim02da0272016-07-19 07:56:38 -0700670 "rm -f /data/local/tmp/vts_driver_*",
Ang Li53bb72b2016-07-19 18:29:37 -0700671 "rm -f /data/local/tmp/vts_agent_callback*"
672 ]
Keun Soo Yim2eecdfa2016-07-29 11:48:37 -0700673 kill_commands = ["killall vts_hal_agent32", "killall vts_hal_agent64",
674 "killall fuzzer32", "killall fuzzer64",
675 "killall vts_shell_driver32",
Yuexi Ma674e59d2016-07-19 15:39:54 -0700676 "killall vts_shell_driver64"]
Keun Soo Yima066dd52016-07-01 15:18:28 -0700677 cleanup_commands.extend(kill_commands)
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -0700678 chmod_commands = [
Keun Soo Yim2eecdfa2016-07-29 11:48:37 -0700679 "chmod 755 %s/32/vts_hal_agent32" % DEFAULT_AGENT_BASE_DIR,
680 "chmod 755 %s/64/vts_hal_agent64" % DEFAULT_AGENT_BASE_DIR,
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -0700681 "chmod 755 %s/32/fuzzer32" % DEFAULT_AGENT_BASE_DIR,
Keun Soo Yim02da0272016-07-19 07:56:38 -0700682 "chmod 755 %s/64/fuzzer64" % DEFAULT_AGENT_BASE_DIR,
683 "chmod 755 %s/32/vts_shell_driver32" % DEFAULT_AGENT_BASE_DIR,
Ang Li53bb72b2016-07-19 18:29:37 -0700684 "chmod 755 %s/64/vts_shell_driver64" % DEFAULT_AGENT_BASE_DIR
685 ]
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -0700686 cleanup_commands.extend(chmod_commands)
Keun Soo Yima066dd52016-07-01 15:18:28 -0700687 for cmd in cleanup_commands:
Sahil Jain06dd6a22016-06-24 13:47:37 -0700688 try:
689 self.adb.shell(cmd)
Keun Soo Yimab7fb062016-07-13 14:47:19 -0700690 except adb.AdbError as e:
691 self.log.warning(
Ang Li53bb72b2016-07-19 18:29:37 -0700692 "A command to setup the env to start the VTS Agent failed %s",
693 e)
Tri Vo843b57f2016-09-24 14:51:38 -0700694
695 bits = ['64', '32'] if self.is64Bit else ['32']
696 for bitness in bits:
Hsin-Yi Chena9b3c312016-12-21 15:53:13 +0800697 vts_agent_log_path = os.path.join(self.log_path,
698 "vts_agent_" + bitness + ".log")
Keun Soo Yimd2aa5b82016-07-30 20:12:19 -0700699 cmd = (
700 'adb -s {s} shell LD_LIBRARY_PATH={path}/{bitness} '
701 '{path}/{bitness}/vts_hal_agent{bitness}'
702 ' {path}/32/fuzzer32 {path}/64/fuzzer64 {path}/spec'
703 ' {path}/32/vts_shell_driver32 {path}/64/vts_shell_driver64 >> {log}'
704 ).format(s=self.serial,
705 bitness=bitness,
706 path=DEFAULT_AGENT_BASE_DIR,
707 log=vts_agent_log_path)
708 try:
709 self.vts_agent_process = utils.start_standing_subprocess(
710 cmd, check_health_delay=1)
711 except utils.VTSUtilsError as e:
712 logging.exception(e)
713 with open(vts_agent_log_path, 'r') as log_file:
714 logging.error("VTS agent output:\n")
715 logging.error(log_file.read())
716 # one common cause is that 64-bit executable is not supported
717 # in low API level devices.
718 if bitness == '32':
719 raise
720 else:
721 logging.error('retrying using a 32-bit binary.')
Sahil Jain06dd6a22016-06-24 13:47:37 -0700722
Ang Lie014a8b2016-06-28 18:24:52 -0700723 def stopVtsAgent(self):
724 """Stop the HAL agent running on the AndroidDevice.
Sahil Jain06dd6a22016-06-24 13:47:37 -0700725 """
Ang Lie014a8b2016-06-28 18:24:52 -0700726 if self.vts_agent_process:
727 utils.stop_standing_subprocess(self.vts_agent_process)
728 self.vts_agent_process = None
Sahil Jain06dd6a22016-06-24 13:47:37 -0700729
Keun Soo Yime34754e2016-08-15 11:25:15 -0700730 @property
731 def product_type(self):
732 """Gets the product type name."""
733 return self._product_type
734
Ang Li6c303fc2016-09-22 13:19:33 -0700735 # Code for using SL4A client
736 def startSl4aClient(self, handle_event=True):
737 """Create an sl4a connection to the device.
738
739 Return the connection handler 'droid'. By default, another connection
740 on the same session is made for EventDispatcher, and the dispatcher is
741 returned to the caller as well.
742 If sl4a server is not started on the device, try to start it.
743
744 Args:
745 handle_event: True if this droid session will need to handle
746 events.
747 """
748 self._sl4a_sessions = {}
749 self._sl4a_event_dispatchers = {}
750 if not self.sl4a_host_port or not adb.is_port_available(self.sl4a_host_port):
751 self.sl4a_host_port = adb.get_available_host_port()
752 self.adb.tcp_forward(self.sl4a_host_port, self.sl4a_target_port)
753 try:
754 droid = self._createNewSl4aSession()
755 except sl4a_client.Error:
756 sl4a_client.start_sl4a(self.adb)
757 droid = self._createNewSl4aSession()
758 self.sl4a = droid
759 if handle_event:
760 ed = self._getSl4aEventDispatcher(droid)
761 self.sl4a_event = ed
762
763 def _getSl4aEventDispatcher(self, droid):
764 """Return an EventDispatcher for an sl4a session
765
766 Args:
767 droid: Session to create EventDispatcher for.
768
769 Returns:
770 ed: An EventDispatcher for specified session.
771 """
772 # TODO (angli): Move service-specific start/stop functions out of
773 # android_device, including VTS Agent, SL4A, and any other
774 # target-side services.
775 ed_key = self.serial + str(droid.uid)
776 if ed_key in self._sl4a_event_dispatchers:
777 if self._sl4a_event_dispatchers[ed_key] is None:
778 raise AndroidDeviceError("EventDispatcher Key Empty")
779 self.log.debug("Returning existing key %s for event dispatcher!",
780 ed_key)
781 return self._sl4a_event_dispatchers[ed_key]
782 event_droid = self._addNewConnectionToSl4aSession(droid.uid)
783 ed = event_dispatcher.EventDispatcher(event_droid)
784 self._sl4a_event_dispatchers[ed_key] = ed
785 return ed
786
787 def _createNewSl4aSession(self):
788 """Start a new session in sl4a.
789
790 Also caches the droid in a dict with its uid being the key.
791
792 Returns:
793 An Android object used to communicate with sl4a on the android
794 device.
795
796 Raises:
797 sl4a_client.Error: Something is wrong with sl4a and it returned an
798 existing uid to a new session.
799 """
800 droid = sl4a_client.Sl4aClient(port=self.sl4a_host_port)
801 droid.open()
802 if droid.uid in self._sl4a_sessions:
803 raise sl4a_client.Error(
804 "SL4A returned an existing uid for a new session. Abort.")
805 self._sl4a_sessions[droid.uid] = [droid]
806 return droid
807
808 def _addNewConnectionToSl4aSession(self, session_id):
809 """Create a new connection to an existing sl4a session.
810
811 Args:
812 session_id: UID of the sl4a session to add connection to.
813
814 Returns:
815 An Android object used to communicate with sl4a on the android
816 device.
817
818 Raises:
819 DoesNotExistError: Raised if the session it's trying to connect to
820 does not exist.
821 """
822 if session_id not in self._sl4a_sessions:
823 raise DoesNotExistError("Session %d doesn't exist." % session_id)
824 droid = sl4a_client.Sl4aClient(port=self.sl4a_host_port, uid=session_id)
825 droid.open(cmd=sl4a_client.Sl4aCommand.CONTINUE)
826 return droid
827
828 def _terminateSl4aSession(self, session_id):
829 """Terminate a session in sl4a.
830
831 Send terminate signal to sl4a server; stop dispatcher associated with
832 the session. Clear corresponding droids and dispatchers from cache.
833
834 Args:
835 session_id: UID of the sl4a session to terminate.
836 """
837 if self._sl4a_sessions and (session_id in self._sl4a_sessions):
838 for droid in self._sl4a_sessions[session_id]:
839 droid.closeSl4aSession()
840 droid.close()
841 del self._sl4a_sessions[session_id]
842 ed_key = self.serial + str(session_id)
843 if ed_key in self._sl4a_event_dispatchers:
844 self._sl4a_event_dispatchers[ed_key].clean_up()
845 del self._sl4a_event_dispatchers[ed_key]
846
847 def _terminateAllSl4aSessions(self):
848 """Terminate all sl4a sessions on the AndroidDevice instance.
849
850 Terminate all sessions and clear caches.
851 """
852 if self._sl4a_sessions:
853 session_ids = list(self._sl4a_sessions.keys())
854 for session_id in session_ids:
855 try:
856 self._terminateSl4aSession(session_id)
857 except:
858 self.log.exception("Failed to terminate session %d.",
859 session_id)
860 if self.sl4a_host_port:
861 self.adb.forward("--remove tcp:%d" % self.sl4a_host_port)
862 self.sl4a_host_port = None
863
Sahil Jain06dd6a22016-06-24 13:47:37 -0700864
Ang Lie014a8b2016-06-28 18:24:52 -0700865class AndroidDeviceLoggerAdapter(logging.LoggerAdapter):
866 """A wrapper class that attaches a prefix to all log lines from an
867 AndroidDevice object.
868 """
869
870 def process(self, msg, kwargs):
871 """Process every log message written via the wrapped logger object.
872
873 We are adding the prefix "[AndroidDevice|<serial>]" to all log lines.
874
875 Args:
876 msg: string, the original log message.
877 kwargs: dict, the key value pairs that can be used to modify the
878 original log message.
879 """
880 msg = "[AndroidDevice|%s] %s" % (self.extra["serial"], msg)
881 return (msg, kwargs)