blob: 03d48c7b832eef4a694f5e5ddc0ac0f86fd5c68c [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
26import Queue
Ang Li93420002016-05-10 19:11:44 -070027
Keun Soo Yime34754e2016-08-15 11:25:15 -070028from vts.runners.host import keys
Ang Li93420002016-05-10 19:11:44 -070029from vts.runners.host import logger as vts_logger
30from vts.runners.host import signals
31from vts.runners.host import utils
Ang Li7f0e1c72016-06-14 11:23:49 -070032from vts.utils.python.controllers import adb
33from vts.utils.python.controllers import event_dispatcher
34from vts.utils.python.controllers import fastboot
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
Keun Soo Yimf2b590c2016-07-31 19:54:18 -070065def create(configs, use_vts_agent=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.
Keun Soo Yim4231b6e2016-07-31 19:01:05 -070071 use_vts_agent: bool, whether to use VTS agent.
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()
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -070089
Ang Li93420002016-05-10 19:11:44 -070090 for ad in ads:
91 if ad.serial not in connected_ads:
Ang Li53bb72b2016-07-19 18:29:37 -070092 raise DoesNotExistError(("Android device %s is specified in config"
93 " but is not attached.") % ad.serial)
Keun Soo Yim4231b6e2016-07-31 19:01:05 -070094 _startServicesOnAds(ads, use_vts_agent)
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
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700111def _startServicesOnAds(ads, use_vts_agent):
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.
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700119 use_vts_agent: bool, whether to use the VTS agent.
Ang Li53bb72b2016-07-19 18:29:37 -0700120 """
121 running_ads = []
122 for ad in ads:
123 running_ads.append(ad)
124 try:
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700125 ad.startServices(use_vts_agent)
Ang Li53bb72b2016-07-19 18:29:37 -0700126 except:
127 ad.log.exception("Failed to start some services, abort!")
128 destroy(running_ads)
129 raise
Ang Li93420002016-05-10 19:11:44 -0700130
Ang Lie2139f12016-05-12 17:39:06 -0700131
Ang Li93420002016-05-10 19:11:44 -0700132def _parse_device_list(device_list_str, key):
133 """Parses a byte string representing a list of devices. The string is
134 generated by calling either adb or fastboot.
135
136 Args:
137 device_list_str: Output of adb or fastboot.
138 key: The token that signifies a device in device_list_str.
139
140 Returns:
141 A list of android device serial numbers.
142 """
143 clean_lines = str(device_list_str, 'utf-8').strip().split('\n')
144 results = []
145 for line in clean_lines:
146 tokens = line.strip().split('\t')
147 if len(tokens) == 2 and tokens[1] == key:
148 results.append(tokens[0])
149 return results
150
Ang Lie2139f12016-05-12 17:39:06 -0700151
Ang Li93420002016-05-10 19:11:44 -0700152def list_adb_devices():
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700153 """List all target devices connected to the host and detected by adb.
Ang Li93420002016-05-10 19:11:44 -0700154
155 Returns:
156 A list of android device serials. Empty if there's none.
157 """
158 out = adb.AdbProxy().devices()
159 return _parse_device_list(out, "device")
160
Ang Lie2139f12016-05-12 17:39:06 -0700161
Ang Li93420002016-05-10 19:11:44 -0700162def list_fastboot_devices():
163 """List all android devices connected to the computer that are in in
164 fastboot mode. These are detected by fastboot.
165
166 Returns:
167 A list of android device serials. Empty if there's none.
168 """
169 out = fastboot.FastbootProxy().devices()
170 return _parse_device_list(out, "fastboot")
171
Ang Lie2139f12016-05-12 17:39:06 -0700172
Ang Li7f0e1c72016-06-14 11:23:49 -0700173def get_instances(serials):
Ang Li93420002016-05-10 19:11:44 -0700174 """Create AndroidDevice instances from a list of serials.
175
176 Args:
177 serials: A list of android device serials.
Ang Li93420002016-05-10 19:11:44 -0700178
179 Returns:
180 A list of AndroidDevice objects.
181 """
182 results = []
183 for s in serials:
Ang Li7f0e1c72016-06-14 11:23:49 -0700184 results.append(AndroidDevice(s))
Ang Li93420002016-05-10 19:11:44 -0700185 return results
186
Ang Lie2139f12016-05-12 17:39:06 -0700187
Ang Li7f0e1c72016-06-14 11:23:49 -0700188def get_instances_with_configs(configs):
Ang Li93420002016-05-10 19:11:44 -0700189 """Create AndroidDevice instances from a list of json configs.
190
191 Each config should have the required key-value pair "serial".
192
193 Args:
194 configs: A list of dicts each representing the configuration of one
195 android device.
Ang Li93420002016-05-10 19:11:44 -0700196
197 Returns:
198 A list of AndroidDevice objects.
199 """
200 results = []
201 for c in configs:
202 try:
Keun Soo Yime34754e2016-08-15 11:25:15 -0700203 serial = c.pop(keys.ConfigKeys.IKEY_SERIAL)
Ang Li93420002016-05-10 19:11:44 -0700204 except KeyError:
Keun Soo Yime34754e2016-08-15 11:25:15 -0700205 raise AndroidDeviceError(
206 ('Required value %s is missing in '
207 'AndroidDevice config %s.') % (keys.ConfigKeys.IKEY_SERIAL,
208 c))
209 try:
210 product_type = c.pop(keys.ConfigKeys.IKEY_PRODUCT_TYPE)
211 except KeyError:
212 logging.error(
213 'Required value %s is missing in '
214 'AndroidDevice config %s.',
215 keys.ConfigKeys.IKEY_PRODUCT_TYPE, c)
216 product_type = ANDROID_PRODUCT_TYPE_UNKNOWN
217
218 ad = AndroidDevice(serial, product_type)
Ang Li93420002016-05-10 19:11:44 -0700219 ad.loadConfig(c)
220 results.append(ad)
221 return results
222
Ang Lie2139f12016-05-12 17:39:06 -0700223
Ang Li7f0e1c72016-06-14 11:23:49 -0700224def get_all_instances(include_fastboot=False):
Ang Li93420002016-05-10 19:11:44 -0700225 """Create AndroidDevice instances for all attached android devices.
226
227 Args:
228 include_fastboot: Whether to include devices in bootloader mode or not.
Ang Li93420002016-05-10 19:11:44 -0700229
230 Returns:
231 A list of AndroidDevice objects each representing an android device
232 attached to the computer.
233 """
234 if include_fastboot:
235 serial_list = list_adb_devices() + list_fastboot_devices()
Ang Li7f0e1c72016-06-14 11:23:49 -0700236 return get_instances(serial_list)
237 return get_instances(list_adb_devices())
Ang Li93420002016-05-10 19:11:44 -0700238
Ang Lie2139f12016-05-12 17:39:06 -0700239
Ang Li93420002016-05-10 19:11:44 -0700240def filter_devices(ads, func):
241 """Finds the AndroidDevice instances from a list that match certain
242 conditions.
243
244 Args:
245 ads: A list of AndroidDevice instances.
246 func: A function that takes an AndroidDevice object and returns True
247 if the device satisfies the filter condition.
248
249 Returns:
250 A list of AndroidDevice instances that satisfy the filter condition.
251 """
252 results = []
253 for ad in ads:
254 if func(ad):
255 results.append(ad)
256 return results
257
Ang Lie2139f12016-05-12 17:39:06 -0700258
Ang Li93420002016-05-10 19:11:44 -0700259def get_device(ads, **kwargs):
260 """Finds a unique AndroidDevice instance from a list that has specific
261 attributes of certain values.
262
263 Example:
264 get_device(android_devices, label="foo", phone_number="1234567890")
265 get_device(android_devices, model="angler")
266
267 Args:
268 ads: A list of AndroidDevice instances.
269 kwargs: keyword arguments used to filter AndroidDevice instances.
270
271 Returns:
272 The target AndroidDevice instance.
273
274 Raises:
275 AndroidDeviceError is raised if none or more than one device is
276 matched.
277 """
Ang Lie2139f12016-05-12 17:39:06 -0700278
Ang Li93420002016-05-10 19:11:44 -0700279 def _get_device_filter(ad):
280 for k, v in kwargs.items():
281 if not hasattr(ad, k):
282 return False
283 elif getattr(ad, k) != v:
284 return False
285 return True
Ang Lie2139f12016-05-12 17:39:06 -0700286
Ang Li93420002016-05-10 19:11:44 -0700287 filtered = filter_devices(ads, _get_device_filter)
288 if not filtered:
289 raise AndroidDeviceError(("Could not find a target device that matches"
290 " condition: %s.") % kwargs)
291 elif len(filtered) == 1:
292 return filtered[0]
293 else:
294 serials = [ad.serial for ad in filtered]
295 raise AndroidDeviceError("More than one device matched: %s" % serials)
296
Ang Lie2139f12016-05-12 17:39:06 -0700297
Ang Li93420002016-05-10 19:11:44 -0700298def takeBugReports(ads, test_name, begin_time):
299 """Takes bug reports on a list of android devices.
300
301 If you want to take a bug report, call this function with a list of
302 android_device objects in on_fail. But reports will be taken on all the
303 devices in the list concurrently. Bug report takes a relative long
304 time to take, so use this cautiously.
305
306 Args:
307 ads: A list of AndroidDevice instances.
308 test_name: Name of the test case that triggered this bug report.
309 begin_time: Logline format timestamp taken when the test started.
310 """
311 begin_time = vts_logger.normalizeLogLineTimestamp(begin_time)
Ang Lie2139f12016-05-12 17:39:06 -0700312
Ang Li93420002016-05-10 19:11:44 -0700313 def take_br(test_name, begin_time, ad):
314 ad.takeBugReport(test_name, begin_time)
Ang Lie2139f12016-05-12 17:39:06 -0700315
Ang Li93420002016-05-10 19:11:44 -0700316 args = [(test_name, begin_time, ad) for ad in ads]
317 utils.concurrent_exec(take_br, args)
318
Ang Lie2139f12016-05-12 17:39:06 -0700319
Ang Li7f0e1c72016-06-14 11:23:49 -0700320class AndroidDevice(object):
Ang Li93420002016-05-10 19:11:44 -0700321 """Class representing an android device.
322
Ang Li53bb72b2016-07-19 18:29:37 -0700323 Each object of this class represents one Android device. The object holds
324 handles to adb, fastboot, and various RPC clients.
Ang Li93420002016-05-10 19:11:44 -0700325
326 Attributes:
Keun Soo Yime34754e2016-08-15 11:25:15 -0700327 serial: A string that's the serial number of the Android device.
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700328 device_command_port: int, the port number used on the Android device
329 for adb port forwarding (for command-response sessions).
330 device_callback_port: int, the port number used on the Android device
331 for adb port reverse forwarding (for callback sessions).
Ang Lie014a8b2016-06-28 18:24:52 -0700332 log: A logger project with a device-specific prefix for each line -
333 [AndroidDevice|<serial>]
Ang Li93420002016-05-10 19:11:44 -0700334 log_path: A string that is the path where all logs collected on this
335 android device should be stored.
336 adb_logcat_process: A process that collects the adb logcat.
337 adb_logcat_file_path: A string that's the full path to the adb logcat
338 file collected, if any.
Ang Lie014a8b2016-06-28 18:24:52 -0700339 vts_agent_process: A process that runs the HAL agent.
Ang Li93420002016-05-10 19:11:44 -0700340 adb: An AdbProxy object used for interacting with the device via adb.
341 fastboot: A FastbootProxy object used for interacting with the device
342 via fastboot.
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700343 host_command_port: the host-side port for runner to agent sessions
344 (to send commands and receive responses).
345 host_callback_port: the host-side port for agent to runner sessions
346 (to get callbacks from agent).
Ang Li53bb72b2016-07-19 18:29:37 -0700347 hal: HalMirror, in charge of all communications with the HAL layer.
348 lib: LibMirror, in charge of all communications with static and shared
349 native libs.
350 shell: ShellMirror, in charge of all communications with shell.
Keun Soo Yime34754e2016-08-15 11:25:15 -0700351 _product_type: A string, the device product type (e.g., bullhead) if
352 known, ANDROID_PRODUCT_TYPE_UNKNOWN otherwise.
Ang Li93420002016-05-10 19:11:44 -0700353 """
354
Keun Soo Yime34754e2016-08-15 11:25:15 -0700355 def __init__(self, serial="", product_type=ANDROID_PRODUCT_TYPE_UNKNOWN,
356 device_callback_port=5010):
Ang Li93420002016-05-10 19:11:44 -0700357 self.serial = serial
Keun Soo Yime34754e2016-08-15 11:25:15 -0700358 self._product_type = product_type
Keun Soo Yimf5d0bca2016-07-30 23:59:26 -0700359 self.device_command_port = None
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700360 self.device_callback_port = device_callback_port
Ang Lie014a8b2016-06-28 18:24:52 -0700361 self.log = AndroidDeviceLoggerAdapter(logging.getLogger(),
362 {"serial": self.serial})
363 base_log_path = getattr(logging, "log_path", "/tmp/logs/")
Ang Li7f0e1c72016-06-14 11:23:49 -0700364 self.log_path = os.path.join(base_log_path, "AndroidDevice%s" % serial)
Ang Li93420002016-05-10 19:11:44 -0700365 self.adb_logcat_process = None
366 self.adb_logcat_file_path = None
Ang Lie014a8b2016-06-28 18:24:52 -0700367 self.vts_agent_process = None
Ang Li93420002016-05-10 19:11:44 -0700368 self.adb = adb.AdbProxy(serial)
369 self.fastboot = fastboot.FastbootProxy(serial)
370 if not self.isBootloaderMode:
371 self.rootAdb()
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700372 self.host_command_port = adb.get_available_host_port()
373 self.host_callback_port = adb.get_available_host_port()
Ang Lie014a8b2016-06-28 18:24:52 -0700374 self.adb.reverse_tcp_forward(self.device_callback_port,
375 self.host_callback_port)
Ang Li53bb72b2016-07-19 18:29:37 -0700376 self.hal = None
Keun Soo Yimf5d0bca2016-07-30 23:59:26 -0700377 self.lib = None
378 self.shell = None
Ang Li93420002016-05-10 19:11:44 -0700379
380 def __del__(self):
Ang Li53bb72b2016-07-19 18:29:37 -0700381 self.cleanUp()
382
383 def cleanUp(self):
384 """Cleans up the AndroidDevice object and releases any resources it
385 claimed.
386 """
387 self.stopServices()
Keun Soo Yimcbd8c052016-06-20 15:10:58 -0700388 if self.host_command_port:
389 self.adb.forward("--remove tcp:%s" % self.host_command_port)
Ang Li93420002016-05-10 19:11:44 -0700390
391 @property
392 def isBootloaderMode(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700393 """True if the device is in bootloader mode."""
Ang Li93420002016-05-10 19:11:44 -0700394 return self.serial in list_fastboot_devices()
395
396 @property
397 def isAdbRoot(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700398 """True if adb is running as root for this device."""
399 id_str = self.adb.shell("id -u").decode("utf-8")
400 self.log.info(id_str)
401 return "root" in id_str
Ang Li93420002016-05-10 19:11:44 -0700402
403 @property
404 def model(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700405 """The Android code name for the device."""
Ang Li93420002016-05-10 19:11:44 -0700406 # If device is in bootloader mode, get mode name from fastboot.
407 if self.isBootloaderMode:
408 out = self.fastboot.getvar("product").strip()
409 # "out" is never empty because of the "total time" message fastboot
410 # writes to stderr.
411 lines = out.decode("utf-8").split('\n', 1)
412 if lines:
413 tokens = lines[0].split(' ')
414 if len(tokens) > 1:
415 return tokens[1].lower()
416 return None
417 out = self.adb.shell('getprop | grep ro.build.product')
418 model = out.decode("utf-8").strip().split('[')[-1][:-1].lower()
419 if model == "sprout":
420 return model
421 else:
422 out = self.adb.shell('getprop | grep ro.product.name')
423 model = out.decode("utf-8").strip().split('[')[-1][:-1].lower()
424 return model
425
426 @property
Tri Vo921bfa02016-09-20 10:25:23 -0700427 def cpu_abi(self):
428 """CPU ABI (Application Binary Interface) of the device."""
429 out = self.adb.shell('getprop | grep "\[ro.product.cpu.abi\]"')
430 if not out:
431 return "unknown"
432
433 cpu_abi = out.decode("utf-8").strip().split('[')[-1][:-1].lower()
434 return cpu_abi
435
436 @property
Ang Li93420002016-05-10 19:11:44 -0700437 def isAdbLogcatOn(self):
438 """Whether there is an ongoing adb logcat collection.
439 """
440 if self.adb_logcat_process:
441 return True
442 return False
443
444 def loadConfig(self, config):
445 """Add attributes to the AndroidDevice object based on json config.
446
447 Args:
448 config: A dictionary representing the configs.
449
450 Raises:
451 AndroidDeviceError is raised if the config is trying to overwrite
452 an existing attribute.
453 """
454 for k, v in config.items():
455 if hasattr(self, k):
Ang Li7f0e1c72016-06-14 11:23:49 -0700456 raise AndroidDeviceError(
457 "Attempting to set existing attribute %s on %s" %
458 (k, self.serial))
Ang Li93420002016-05-10 19:11:44 -0700459 setattr(self, k, v)
460
461 def rootAdb(self):
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700462 """Changes adb to root mode for this device."""
Ang Li93420002016-05-10 19:11:44 -0700463 if not self.isAdbRoot:
Keun Soo Yimc2bc9f82016-07-16 15:36:36 -0700464 try:
465 self.adb.root()
Keun Soo Yima5a0dc22016-07-16 17:56:19 -0700466 self.adb.wait_for_device()
467 self.adb.remount()
Keun Soo Yim731e9172016-07-16 17:48:39 -0700468 self.adb.wait_for_device()
469 except adb.AdbError as e:
470 # adb wait-for-device is not always possible in the lab
Keun Soo Yima5a0dc22016-07-16 17:56:19 -0700471 # continue with an assumption it's done by the harness.
Keun Soo Yim731e9172016-07-16 17:48:39 -0700472 logging.exception(e)
Ang Li93420002016-05-10 19:11:44 -0700473
Ang Li93420002016-05-10 19:11:44 -0700474 def startAdbLogcat(self):
475 """Starts a standing adb logcat collection in separate subprocesses and
476 save the logcat in a file.
477 """
478 if self.isAdbLogcatOn:
Ang Li7f0e1c72016-06-14 11:23:49 -0700479 raise AndroidDeviceError(("Android device %s already has an adb "
Ang Lie2139f12016-05-12 17:39:06 -0700480 "logcat thread going on. Cannot start "
Ang Li7f0e1c72016-06-14 11:23:49 -0700481 "another one.") % self.serial)
Ang Li7f0e1c72016-06-14 11:23:49 -0700482 f_name = "adblog,%s,%s.txt" % (self.model, self.serial)
Ang Li93420002016-05-10 19:11:44 -0700483 utils.create_dir(self.log_path)
484 logcat_file_path = os.path.join(self.log_path, f_name)
485 try:
486 extra_params = self.adb_logcat_param
487 except AttributeError:
488 extra_params = "-b all"
Ang Li7f0e1c72016-06-14 11:23:49 -0700489 cmd = "adb -s %s logcat -v threadtime %s >> %s" % (
Ang Li93420002016-05-10 19:11:44 -0700490 self.serial, extra_params, logcat_file_path)
491 self.adb_logcat_process = utils.start_standing_subprocess(cmd)
492 self.adb_logcat_file_path = logcat_file_path
493
494 def stopAdbLogcat(self):
495 """Stops the adb logcat collection subprocess.
496 """
497 if not self.isAdbLogcatOn:
Ang Li7f0e1c72016-06-14 11:23:49 -0700498 raise AndroidDeviceError(
499 "Android device %s does not have an ongoing adb logcat collection."
500 % self.serial)
Ang Li93420002016-05-10 19:11:44 -0700501 utils.stop_standing_subprocess(self.adb_logcat_process)
502 self.adb_logcat_process = None
503
504 def takeBugReport(self, test_name, begin_time):
505 """Takes a bug report on the device and stores it in a file.
506
507 Args:
508 test_name: Name of the test case that triggered this bug report.
509 begin_time: Logline format timestamp taken when the test started.
510 """
511 br_path = os.path.join(self.log_path, "BugReports")
512 utils.create_dir(br_path)
Ang Li7f0e1c72016-06-14 11:23:49 -0700513 base_name = ",%s,%s.txt" % (begin_time, self.serial)
Ang Li93420002016-05-10 19:11:44 -0700514 test_name_len = utils.MAX_FILENAME_LEN - len(base_name)
515 out_name = test_name[:test_name_len] + base_name
516 full_out_path = os.path.join(br_path, out_name.replace(' ', '\ '))
517 self.log.info("Taking bugreport for %s on %s", test_name, self.serial)
Ang Li7f0e1c72016-06-14 11:23:49 -0700518 self.adb.bugreport(" > %s" % full_out_path)
Ang Li93420002016-05-10 19:11:44 -0700519 self.log.info("Bugreport for %s taken at %s", test_name, full_out_path)
520
Ang Li93420002016-05-10 19:11:44 -0700521 @utils.timeout(15 * 60)
522 def waitForBootCompletion(self):
523 """Waits for Android framework to broadcast ACTION_BOOT_COMPLETED.
524
525 This function times out after 15 minutes.
526 """
Keun Soo Yim731e9172016-07-16 17:48:39 -0700527 try:
528 self.adb.wait_for_device()
529 except adb.AdbError as e:
530 # adb wait-for-device is not always possible in the lab
531 logging.exception(e)
Ang Li93420002016-05-10 19:11:44 -0700532 while True:
533 try:
534 out = self.adb.shell("getprop sys.boot_completed")
535 completed = out.decode('utf-8').strip()
536 if completed == '1':
537 return
538 except adb.AdbError:
539 # adb shell calls may fail during certain period of booting
540 # process, which is normal. Ignoring these errors.
541 pass
542 time.sleep(5)
543
544 def reboot(self):
Ang Li7f0e1c72016-06-14 11:23:49 -0700545 """Reboots the device and wait for device to complete booting.
Ang Li93420002016-05-10 19:11:44 -0700546
547 This is probably going to print some error messages in console. Only
548 use if there's no other option.
549
Ang Li93420002016-05-10 19:11:44 -0700550 Raises:
551 AndroidDeviceError is raised if waiting for completion timed
552 out.
553 """
554 if self.isBootloaderMode:
555 self.fastboot.reboot()
556 return
557 has_adb_log = self.isAdbLogcatOn
Ang Lie014a8b2016-06-28 18:24:52 -0700558 has_vts_agent = True if self.vts_agent_process else False
Ang Li93420002016-05-10 19:11:44 -0700559 if has_adb_log:
560 self.stopAdbLogcat()
Ang Lie014a8b2016-06-28 18:24:52 -0700561 if has_vts_agent:
562 self.stopVtsAgent()
Ang Li93420002016-05-10 19:11:44 -0700563 self.adb.reboot()
564 self.waitForBootCompletion()
565 self.rootAdb()
Ang Li93420002016-05-10 19:11:44 -0700566 if has_adb_log:
567 self.startAdbLogcat()
Ang Lie014a8b2016-06-28 18:24:52 -0700568 if has_vts_agent:
569 self.startVtsAgent()
Sahil Jain06dd6a22016-06-24 13:47:37 -0700570
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700571 def startServices(self, use_vts_agent):
Ang Li53bb72b2016-07-19 18:29:37 -0700572 """Starts long running services on the android device.
573
574 1. Start adb logcat capture.
575 2. Start VtsAgent.
576 3. Create HalMirror
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700577
578 Args:
579 use_vts_agent: bool, whether to use the VTS agent.
Ang Li53bb72b2016-07-19 18:29:37 -0700580 """
581 try:
582 self.startAdbLogcat()
583 except:
584 self.log.exception("Failed to start adb logcat!")
585 raise
Keun Soo Yim4231b6e2016-07-31 19:01:05 -0700586 if use_vts_agent:
587 self.startVtsAgent()
588 self.device_command_port = int(
589 self.adb.shell("cat /data/local/tmp/vts_tcp_server_port"))
590 logging.info("device_command_port: %s", self.device_command_port)
591 self.adb.tcp_forward(self.host_command_port, self.device_command_port)
592 self.hal = hal_mirror.HalMirror(self.host_command_port,
593 self.host_callback_port)
594 self.lib = lib_mirror.LibMirror(self.host_command_port)
595 self.shell = shell_mirror.ShellMirror(self.host_command_port)
596 else:
597 logging.info("not using VTS agent.")
Ang Li53bb72b2016-07-19 18:29:37 -0700598
599 def stopServices(self):
600 """Stops long running services on the android device.
601 """
602 if self.adb_logcat_process:
603 self.stopAdbLogcat()
604 self.stopVtsAgent()
605 if self.hal:
606 self.hal.CleanUp()
607
Ang Lie014a8b2016-06-28 18:24:52 -0700608 def startVtsAgent(self):
609 """Start HAL agent on the AndroidDevice.
Sahil Jain06dd6a22016-06-24 13:47:37 -0700610
611 This function starts the target side native agent and is persisted
Ang Lie014a8b2016-06-28 18:24:52 -0700612 throughout the test run.
Sahil Jain06dd6a22016-06-24 13:47:37 -0700613 """
Keun Soo Yimab7fb062016-07-13 14:47:19 -0700614 self.log.info("start a VTS agent")
Ang Lie014a8b2016-06-28 18:24:52 -0700615 if self.vts_agent_process:
616 raise AndroidDeviceError("HAL agent is already running on %s." %
617 self.serial)
Keun Soo Yima066dd52016-07-01 15:18:28 -0700618
619 cleanup_commands = [
Keun Soo Yim02da0272016-07-19 07:56:38 -0700620 "rm -f /data/local/tmp/vts_driver_*",
Ang Li53bb72b2016-07-19 18:29:37 -0700621 "rm -f /data/local/tmp/vts_agent_callback*"
622 ]
Keun Soo Yim2eecdfa2016-07-29 11:48:37 -0700623 kill_commands = ["killall vts_hal_agent32", "killall vts_hal_agent64",
624 "killall fuzzer32", "killall fuzzer64",
625 "killall vts_shell_driver32",
Yuexi Ma674e59d2016-07-19 15:39:54 -0700626 "killall vts_shell_driver64"]
Keun Soo Yima066dd52016-07-01 15:18:28 -0700627 cleanup_commands.extend(kill_commands)
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -0700628 chmod_commands = [
Keun Soo Yim2eecdfa2016-07-29 11:48:37 -0700629 "chmod 755 %s/32/vts_hal_agent32" % DEFAULT_AGENT_BASE_DIR,
630 "chmod 755 %s/64/vts_hal_agent64" % DEFAULT_AGENT_BASE_DIR,
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -0700631 "chmod 755 %s/32/fuzzer32" % DEFAULT_AGENT_BASE_DIR,
Keun Soo Yim02da0272016-07-19 07:56:38 -0700632 "chmod 755 %s/64/fuzzer64" % DEFAULT_AGENT_BASE_DIR,
633 "chmod 755 %s/32/vts_shell_driver32" % DEFAULT_AGENT_BASE_DIR,
Ang Li53bb72b2016-07-19 18:29:37 -0700634 "chmod 755 %s/64/vts_shell_driver64" % DEFAULT_AGENT_BASE_DIR
635 ]
Keun Soo Yimbf8f7b42016-07-13 13:58:28 -0700636 cleanup_commands.extend(chmod_commands)
Keun Soo Yima066dd52016-07-01 15:18:28 -0700637 for cmd in cleanup_commands:
Sahil Jain06dd6a22016-06-24 13:47:37 -0700638 try:
639 self.adb.shell(cmd)
Keun Soo Yimab7fb062016-07-13 14:47:19 -0700640 except adb.AdbError as e:
641 self.log.warning(
Ang Li53bb72b2016-07-19 18:29:37 -0700642 "A command to setup the env to start the VTS Agent failed %s",
643 e)
Ang Lie014a8b2016-06-28 18:24:52 -0700644 vts_agent_log_path = os.path.join(self.log_path, "vts_agent.log")
Keun Soo Yimd2aa5b82016-07-30 20:12:19 -0700645 for bitness in ['64', '32']:
646 cmd = (
647 'adb -s {s} shell LD_LIBRARY_PATH={path}/{bitness} '
648 '{path}/{bitness}/vts_hal_agent{bitness}'
649 ' {path}/32/fuzzer32 {path}/64/fuzzer64 {path}/spec'
650 ' {path}/32/vts_shell_driver32 {path}/64/vts_shell_driver64 >> {log}'
651 ).format(s=self.serial,
652 bitness=bitness,
653 path=DEFAULT_AGENT_BASE_DIR,
654 log=vts_agent_log_path)
655 try:
656 self.vts_agent_process = utils.start_standing_subprocess(
657 cmd, check_health_delay=1)
658 except utils.VTSUtilsError as e:
659 logging.exception(e)
660 with open(vts_agent_log_path, 'r') as log_file:
661 logging.error("VTS agent output:\n")
662 logging.error(log_file.read())
663 # one common cause is that 64-bit executable is not supported
664 # in low API level devices.
665 if bitness == '32':
666 raise
667 else:
668 logging.error('retrying using a 32-bit binary.')
Sahil Jain06dd6a22016-06-24 13:47:37 -0700669
Ang Lie014a8b2016-06-28 18:24:52 -0700670 def stopVtsAgent(self):
671 """Stop the HAL agent running on the AndroidDevice.
Sahil Jain06dd6a22016-06-24 13:47:37 -0700672 """
Ang Lie014a8b2016-06-28 18:24:52 -0700673 if self.vts_agent_process:
674 utils.stop_standing_subprocess(self.vts_agent_process)
675 self.vts_agent_process = None
Sahil Jain06dd6a22016-06-24 13:47:37 -0700676
Keun Soo Yime34754e2016-08-15 11:25:15 -0700677 @property
678 def product_type(self):
679 """Gets the product type name."""
680 return self._product_type
681
Sahil Jain06dd6a22016-06-24 13:47:37 -0700682
Ang Lie014a8b2016-06-28 18:24:52 -0700683class AndroidDeviceLoggerAdapter(logging.LoggerAdapter):
684 """A wrapper class that attaches a prefix to all log lines from an
685 AndroidDevice object.
686 """
687
688 def process(self, msg, kwargs):
689 """Process every log message written via the wrapped logger object.
690
691 We are adding the prefix "[AndroidDevice|<serial>]" to all log lines.
692
693 Args:
694 msg: string, the original log message.
695 kwargs: dict, the key value pairs that can be used to modify the
696 original log message.
697 """
698 msg = "[AndroidDevice|%s] %s" % (self.extra["serial"], msg)
699 return (msg, kwargs)