1# 2# Copyright 2016 - The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from builtins import str 17from builtins import open 18 19import gzip 20import logging 21import os 22import re 23import socket 24import subprocess 25import tempfile 26import threading 27import time 28import traceback 29 30from vts.runners.host import asserts 31from vts.runners.host import const 32from vts.runners.host import errors 33from vts.runners.host import keys 34from vts.runners.host import logger as vts_logger 35from vts.runners.host import signals 36from vts.runners.host import utils 37from vts.runners.host.tcp_client import vts_tcp_client 38from vts.utils.python.controllers import adb 39from vts.utils.python.controllers import fastboot 40from vts.utils.python.instrumentation import test_framework_instrumentation as tfi 41from vts.utils.python.mirror import mirror_tracker 42 43VTS_CONTROLLER_CONFIG_NAME = "AndroidDevice" 44VTS_CONTROLLER_REFERENCE_NAME = "android_devices" 45 46ANDROID_DEVICE_PICK_ALL_TOKEN = "*" 47# Key name for adb logcat extra params in config file. 48ANDROID_DEVICE_ADB_LOGCAT_PARAM_KEY = "adb_logcat_param" 49ANDROID_DEVICE_EMPTY_CONFIG_MSG = "Configuration is empty, abort!" 50ANDROID_DEVICE_NOT_LIST_CONFIG_MSG = "Configuration should be a list, abort!" 51PORT_RETRY_COUNT = 3 52SL4A_APK_NAME = "com.googlecode.android_scripting" 53 54ANDROID_PRODUCT_TYPE_UNKNOWN = "unknown" 55 56# Target-side directory where the VTS binaries are uploaded 57DEFAULT_AGENT_BASE_DIR = "/data/local/tmp" 58# Name of llkd 59LLKD = 'llkd-1' 60# Time for which the current is put on sleep when the client is unable to 61# make a connection. 62THREAD_SLEEP_TIME = 1 63# Max number of attempts that the client can make to connect to the agent 64MAX_AGENT_CONNECT_RETRIES = 10 65# System property for product sku. 66PROPERTY_PRODUCT_SKU = "ro.boot.product.hardware.sku" 67 68# The argument to fastboot getvar command to determine whether the device has 69# the slot for vbmeta.img 70_FASTBOOT_VAR_HAS_VBMETA = "has-slot:vbmeta" 71 72SYSPROP_DEV_BOOTCOMPLETE = "dev.bootcomplete" 73SYSPROP_SYS_BOOT_COMPLETED = "sys.boot_completed" 74# the name of a system property which tells whether to stop properly configured 75# native servers where properly configured means a server's init.rc is 76# configured to stop when that property's value is 1. 77SYSPROP_VTS_NATIVE_SERVER = "vts.native_server.on" 78# Maximum time in seconds to wait for process/system status change. 79WAIT_TIMEOUT_SEC = 120 80 81class AndroidDeviceError(signals.ControllerError): 82 pass 83 84 85def create(configs, start_services=True): 86 """Creates AndroidDevice controller objects. 87 88 Args: 89 configs: A list of dicts, each representing a configuration for an 90 Android device. 91 start_services: boolean, controls whether services will be started. 92 93 Returns: 94 A list of AndroidDevice objects. 95 """ 96 if not configs: 97 raise AndroidDeviceError(ANDROID_DEVICE_EMPTY_CONFIG_MSG) 98 elif configs == ANDROID_DEVICE_PICK_ALL_TOKEN: 99 ads = get_all_instances() 100 elif not isinstance(configs, list): 101 raise AndroidDeviceError(ANDROID_DEVICE_NOT_LIST_CONFIG_MSG) 102 elif isinstance(configs[0], str): 103 # Configs is a list of serials. 104 ads = get_instances(configs) 105 else: 106 # Configs is a list of dicts. 107 ads = get_instances_with_configs(configs) 108 connected_ads = list_adb_devices() 109 for ad in ads: 110 ad.enable_vts_agent = start_services 111 if ad.serial not in connected_ads: 112 raise DoesNotExistError(("Android device %s is specified in config" 113 " but is not attached.") % ad.serial) 114 if start_services: 115 _startServicesOnAds(ads) 116 return ads 117 118 119def destroy(ads): 120 """Cleans up AndroidDevice objects. 121 122 Args: 123 ads: A list of AndroidDevice objects. 124 """ 125 for ad in ads: 126 try: 127 ad.cleanUp() 128 except: 129 ad.log.exception("Failed to clean up properly.") 130 131 132def _startServicesOnAds(ads): 133 """Starts long running services on multiple AndroidDevice objects. 134 135 If any one AndroidDevice object fails to start services, cleans up all 136 existing AndroidDevice objects and their services. 137 138 Args: 139 ads: A list of AndroidDevice objects whose services to start. 140 """ 141 running_ads = [] 142 for ad in ads: 143 running_ads.append(ad) 144 try: 145 ad.startServices() 146 except: 147 ad.log.exception("Failed to start some services, abort!") 148 destroy(running_ads) 149 raise 150 151 152def _parse_device_list(device_list_str, key): 153 """Parses a byte string representing a list of devices. The string is 154 generated by calling either adb or fastboot. 155 156 Args: 157 device_list_str: Output of adb or fastboot. 158 key: The token that signifies a device in device_list_str. 159 160 Returns: 161 A list of android device serial numbers. 162 """ 163 clean_lines = str(device_list_str, 'utf-8').strip().split('\n') 164 results = [] 165 for line in clean_lines: 166 tokens = line.strip().split('\t') 167 if len(tokens) == 2 and tokens[1] == key: 168 results.append(tokens[0]) 169 return results 170 171 172def list_adb_devices(): 173 """List all target devices connected to the host and detected by adb. 174 175 Returns: 176 A list of android device serials. Empty if there's none. 177 """ 178 out = adb.AdbProxy().devices() 179 return _parse_device_list(out, "device") 180 181 182def list_fastboot_devices(): 183 """List all android devices connected to the computer that are in in 184 fastboot mode. These are detected by fastboot. 185 186 Returns: 187 A list of android device serials. Empty if there's none. 188 """ 189 out = fastboot.FastbootProxy().devices() 190 return _parse_device_list(out, "fastboot") 191 192 193def get_instances(serials): 194 """Create AndroidDevice instances from a list of serials. 195 196 Args: 197 serials: A list of android device serials. 198 199 Returns: 200 A list of AndroidDevice objects. 201 """ 202 results = [] 203 for s in serials: 204 results.append(AndroidDevice(s)) 205 return results 206 207 208def get_instances_with_configs(configs): 209 """Create AndroidDevice instances from a list of json configs. 210 211 Each config should have the required key-value pair "serial". 212 213 Args: 214 configs: A list of dicts each representing the configuration of one 215 android device. 216 217 Returns: 218 A list of AndroidDevice objects. 219 """ 220 results = [] 221 for c in configs: 222 try: 223 serial = c.pop(keys.ConfigKeys.IKEY_SERIAL) 224 except KeyError: 225 raise AndroidDeviceError(('Required value %s is missing in ' 226 'AndroidDevice config %s.') % 227 (keys.ConfigKeys.IKEY_SERIAL, c)) 228 try: 229 product_type = c.pop(keys.ConfigKeys.IKEY_PRODUCT_TYPE) 230 except KeyError: 231 logging.error('Required value %s is missing in ' 232 'AndroidDevice config %s.', 233 keys.ConfigKeys.IKEY_PRODUCT_TYPE, c) 234 product_type = ANDROID_PRODUCT_TYPE_UNKNOWN 235 236 ad = AndroidDevice(serial, product_type) 237 ad.loadConfig(c) 238 results.append(ad) 239 return results 240 241 242def get_all_instances(include_fastboot=False): 243 """Create AndroidDevice instances for all attached android devices. 244 245 Args: 246 include_fastboot: Whether to include devices in bootloader mode or not. 247 248 Returns: 249 A list of AndroidDevice objects each representing an android device 250 attached to the computer. 251 """ 252 if include_fastboot: 253 serial_list = list_adb_devices() + list_fastboot_devices() 254 return get_instances(serial_list) 255 return get_instances(list_adb_devices()) 256 257 258def filter_devices(ads, func): 259 """Finds the AndroidDevice instances from a list that match certain 260 conditions. 261 262 Args: 263 ads: A list of AndroidDevice instances. 264 func: A function that takes an AndroidDevice object and returns True 265 if the device satisfies the filter condition. 266 267 Returns: 268 A list of AndroidDevice instances that satisfy the filter condition. 269 """ 270 results = [] 271 for ad in ads: 272 if func(ad): 273 results.append(ad) 274 return results 275 276 277def get_device(ads, **kwargs): 278 """Finds a unique AndroidDevice instance from a list that has specific 279 attributes of certain values. 280 281 Example: 282 get_device(android_devices, label="foo", phone_number="1234567890") 283 get_device(android_devices, model="angler") 284 285 Args: 286 ads: A list of AndroidDevice instances. 287 kwargs: keyword arguments used to filter AndroidDevice instances. 288 289 Returns: 290 The target AndroidDevice instance. 291 292 Raises: 293 AndroidDeviceError is raised if none or more than one device is 294 matched. 295 """ 296 297 def _get_device_filter(ad): 298 for k, v in kwargs.items(): 299 if not hasattr(ad, k): 300 return False 301 elif getattr(ad, k) != v: 302 return False 303 return True 304 305 filtered = filter_devices(ads, _get_device_filter) 306 if not filtered: 307 raise AndroidDeviceError(("Could not find a target device that matches" 308 " condition: %s.") % kwargs) 309 elif len(filtered) == 1: 310 return filtered[0] 311 else: 312 serials = [ad.serial for ad in filtered] 313 raise AndroidDeviceError("More than one device matched: %s" % serials) 314 315 316def takeBugReports(ads, test_name, begin_time): 317 """Takes bug reports on a list of android devices. 318 319 If you want to take a bug report, call this function with a list of 320 android_device objects in on_fail. But reports will be taken on all the 321 devices in the list concurrently. Bug report takes a relative long 322 time to take, so use this cautiously. 323 324 Args: 325 ads: A list of AndroidDevice instances. 326 test_name: Name of the test case that triggered this bug report. 327 begin_time: Logline format timestamp taken when the test started. 328 """ 329 begin_time = vts_logger.normalizeLogLineTimestamp(begin_time) 330 331 def take_br(test_name, begin_time, ad): 332 ad.takeBugReport(test_name, begin_time) 333 334 args = [(test_name, begin_time, ad) for ad in ads] 335 utils.concurrent_exec(take_br, args) 336 337 338class AndroidDevice(object): 339 """Class representing an android device. 340 341 Each object of this class represents one Android device. The object holds 342 handles to adb, fastboot, and various RPC clients. 343 344 Attributes: 345 serial: A string that's the serial number of the Android device. 346 device_command_port: int, the port number used on the Android device 347 for adb port forwarding (for command-response sessions). 348 device_callback_port: int, the port number used on the Android device 349 for adb port reverse forwarding (for callback sessions). 350 Set -1 if callback is not needed (e.g., when this class is used 351 as an adb library). 352 log: A logger project with a device-specific prefix for each line - 353 [AndroidDevice|<serial>] 354 log_path: A string that is the path where all logs collected on this 355 android device should be stored. 356 adb_logcat_process: A process that collects the adb logcat. 357 adb_logcat_file_path: A string that's the full path to the adb logcat 358 file collected, if any. 359 vts_agent_process: A process that runs the HAL agent. 360 adb: An AdbProxy object used for interacting with the device via adb. 361 fastboot: A FastbootProxy object used for interacting with the device 362 via fastboot. 363 enable_vts_agent: bool, whether VTS agent is used. 364 enable_sl4a: bool, whether SL4A is used. (unsupported) 365 enable_sl4a_ed: bool, whether SL4A Event Dispatcher is used. (unsupported) 366 host_command_port: the host-side port for runner to agent sessions 367 (to send commands and receive responses). 368 host_callback_port: the host-side port for agent to runner sessions 369 (to get callbacks from agent). 370 hal: HalMirror, in charge of all communications with the HAL layer. 371 lib: LibMirror, in charge of all communications with static and shared 372 native libs. 373 shell: ShellMirror, in charge of all communications with shell. 374 shell_default_nohup: bool, whether to use nohup by default in shell commands. 375 _product_type: A string, the device product type (e.g., bullhead) if 376 known, ANDROID_PRODUCT_TYPE_UNKNOWN otherwise. 377 """ 378 379 def __init__(self, 380 serial="", 381 product_type=ANDROID_PRODUCT_TYPE_UNKNOWN, 382 device_callback_port=5010, 383 shell_default_nohup=False): 384 self.serial = serial 385 self._product_type = product_type 386 self.device_command_port = None 387 self.device_callback_port = device_callback_port 388 self.log = AndroidDeviceLoggerAdapter(logging.getLogger(), 389 {"serial": self.serial}) 390 base_log_path = getattr(logging, "log_path", "/tmp/logs/") 391 self.log_path = os.path.join(base_log_path, "AndroidDevice%s" % serial) 392 self.adb_logcat_process = None 393 self.adb_logcat_file_path = None 394 self.vts_agent_process = None 395 self.adb = adb.AdbProxy(serial) 396 self.fastboot = fastboot.FastbootProxy(serial) 397 if not self.isBootloaderMode: 398 self.rootAdb() 399 self.host_command_port = None 400 self.host_callback_port = adb.get_available_host_port() 401 if self.device_callback_port >= 0: 402 self.adb.reverse_tcp_forward(self.device_callback_port, 403 self.host_callback_port) 404 self.hal = None 405 self.lib = None 406 self.shell = None 407 self.shell_default_nohup = shell_default_nohup 408 self.fatal_error = False 409 410 def __del__(self): 411 self.cleanUp() 412 413 def cleanUp(self): 414 """Cleans up the AndroidDevice object and releases any resources it 415 claimed. 416 """ 417 self.stopServices() 418 self._StartLLKD() 419 if self.host_command_port: 420 self.adb.forward("--remove tcp:%s" % self.host_command_port, 421 timeout=adb.DEFAULT_ADB_SHORT_TIMEOUT) 422 self.host_command_port = None 423 424 @property 425 def shell_default_nohup(self): 426 """Gets default value for shell nohup option.""" 427 if not getattr(self, '_shell_default_nohup'): 428 self._shell_default_nohup = False 429 return self._shell_default_nohup 430 431 @shell_default_nohup.setter 432 def shell_default_nohup(self, value): 433 """Sets default value for shell nohup option.""" 434 self._shell_default_nohup = value 435 if self.shell: 436 self.shell.shell_default_nohup = value 437 438 @property 439 def hasVbmetaSlot(self): 440 """True if the device has the slot for vbmeta.""" 441 if not self.isBootloaderMode: 442 self.adb.reboot_bootloader() 443 444 out = self.fastboot.getvar(_FASTBOOT_VAR_HAS_VBMETA).strip() 445 if ("%s: yes" % _FASTBOOT_VAR_HAS_VBMETA) in out: 446 return True 447 return False 448 449 @property 450 def isBootloaderMode(self): 451 """True if the device is in bootloader mode.""" 452 return self.serial in list_fastboot_devices() 453 454 @property 455 def isAdbRoot(self): 456 """True if adb is running as root for this device.""" 457 id_str = self.adb.shell("id -un").strip().decode("utf-8") 458 return id_str == "root" 459 460 @property 461 def verityEnabled(self): 462 """True if verity is enabled for this device.""" 463 try: 464 verified = self.getProp("partition.system.verified") 465 if not verified: 466 return False 467 except adb.AdbError: 468 # If verity is disabled, there is no property 'partition.system.verified' 469 return False 470 return True 471 472 @property 473 def model(self): 474 """The Android code name for the device.""" 475 # If device is in bootloader mode, get mode name from fastboot. 476 if self.isBootloaderMode: 477 out = self.fastboot.getvar("product").strip() 478 # "out" is never empty because of the "total time" message fastboot 479 # writes to stderr. 480 lines = out.decode("utf-8").split('\n', 1) 481 if lines: 482 tokens = lines[0].split(' ') 483 if len(tokens) > 1: 484 return tokens[1].lower() 485 return None 486 model = self.getProp("ro.build.product").lower() 487 if model == "sprout": 488 return model 489 else: 490 model = self.getProp("ro.product.name").lower() 491 return model 492 493 @property 494 def first_api_level(self): 495 """Gets the API level that the device was initially launched with.""" 496 return self.getProp("ro.product.first_api_level") 497 498 @property 499 def sdk_version(self): 500 """Gets the SDK version that the device is running with.""" 501 return self.getProp("ro.build.version.sdk") 502 503 def getLaunchApiLevel(self, strict=True): 504 """Gets the API level that the device was initially launched with. 505 506 This method reads ro.product.first_api_level from the device. If the 507 value is 0, it then reads ro.build.version.sdk. 508 509 Args: 510 strict: A boolean, whether to fail the test if the property is 511 not an integer or not defined. 512 513 Returns: 514 An integer, the API level. 515 0 if the property is not an integer or not defined. 516 """ 517 level_str = self.first_api_level 518 try: 519 level = int(level_str) 520 except ValueError: 521 error_msg = "Cannot parse first_api_level: %s" % level_str 522 if strict: 523 asserts.fail(error_msg) 524 logging.error(error_msg) 525 return 0 526 527 if level != 0: 528 return level 529 530 level_str = self.sdk_version 531 try: 532 return int(level_str) 533 except ValueError: 534 error_msg = "Cannot parse version.sdk: %s" % level_str 535 if strict: 536 asserts.fail(error_msg) 537 logging.error(error_msg) 538 return 0 539 540 @property 541 def kernel_version(self): 542 """Gets the kernel verison from the device. 543 544 This method reads the output of command "uname -r" from the device. 545 546 Returns: 547 A tuple of kernel version information 548 in the format of (version, patchlevel, sublevel). 549 550 It will fail if failed to get the output or correct format 551 from the output of "uname -r" command 552 """ 553 cmd = 'uname -r' 554 out = self.adb.shell(cmd) 555 out = out.strip() 556 557 match = re.match(r"(\d+)\.(\d+)\.(\d+)", out) 558 if match is None: 559 asserts.fail("Failed to detect kernel version of device. out:%s", out) 560 561 version = int(match.group(1)) 562 patchlevel = int(match.group(2)) 563 sublevel = int(match.group(3)) 564 logging.info("Detected kernel version: %s", match.group(0)) 565 return (version, patchlevel, sublevel) 566 567 @property 568 def vndk_version(self): 569 """Gets the VNDK version that the vendor partition is using.""" 570 return self.getProp("ro.vndk.version") 571 572 @property 573 def vndk_lite(self): 574 """Checks whether the vendor partition requests lite VNDK 575 enforcement. 576 577 Returns: 578 bool, True for lite vndk enforcement. 579 """ 580 vndk_lite_str = self.getProp("ro.vndk.lite") 581 if vndk_lite_str is None: 582 logging.debug('ro.vndk.lite: %s' % vndk_lite_str) 583 return False 584 return vndk_lite_str.lower() == "true" 585 586 @property 587 def cpu_abi(self): 588 """CPU ABI (Application Binary Interface) of the device.""" 589 out = self.getProp("ro.product.cpu.abi") 590 if not out: 591 return "unknown" 592 593 cpu_abi = out.lower() 594 return cpu_abi 595 596 def getCpuAbiList(self, bitness=""): 597 """Gets list of supported ABIs from property. 598 599 Args: 600 bitness: 32 or 64. If the argument is not specified, this method 601 returns both 32 and 64-bit ABIs. 602 603 Returns: 604 A list of strings, the supported ABIs. 605 """ 606 out = self.getProp("ro.product.cpu.abilist" + str(bitness)) 607 return out.lower().split(",") if out else [] 608 609 @property 610 def is64Bit(self): 611 """True if device is 64 bit.""" 612 out = self.adb.shell('uname -m') 613 return "64" in out 614 615 @property 616 def total_memory(self): 617 """Total memory on device. 618 619 Returns: 620 long, total memory in bytes. -1 if cannot get memory information. 621 """ 622 total_memory_command = 'cat /proc/meminfo | grep MemTotal' 623 out = self.adb.shell(total_memory_command) 624 value_unit = out.split(':')[-1].strip().split(' ') 625 626 if len(value_unit) != 2: 627 logging.error('Cannot get memory information. %s', out) 628 return -1 629 630 value, unit = value_unit 631 632 try: 633 value = int(value) 634 except ValueError: 635 logging.error('Unrecognized total memory value: %s', value_unit) 636 return -1 637 638 unit = unit.lower() 639 if unit == 'kb': 640 value *= 1024 641 elif unit == 'mb': 642 value *= 1024 * 1024 643 elif unit == 'b': 644 pass 645 else: 646 logging.error('Unrecognized total memory unit: %s', value_unit) 647 return -1 648 649 return value 650 651 @property 652 def libPaths(self): 653 """List of strings representing the paths to the native library directories.""" 654 paths_32 = ["/system/lib", "/vendor/lib"] 655 if self.is64Bit: 656 paths_64 = ["/system/lib64", "/vendor/lib64"] 657 paths_64.extend(paths_32) 658 return paths_64 659 return paths_32 660 661 @property 662 def isAdbLogcatOn(self): 663 """Whether there is an ongoing adb logcat collection. 664 """ 665 if self.adb_logcat_process: 666 return True 667 return False 668 669 @property 670 def mac_address(self): 671 """The MAC address of the device. 672 """ 673 try: 674 command = 'cat /sys/class/net/wlan0/address' 675 response = self.adb.shell(command) 676 return response.strip() 677 except adb.AdbError as e: 678 logging.exception(e) 679 return "unknown" 680 681 @property 682 def sim_state(self): 683 """The SIM state of the device. 684 """ 685 return self.getProp('gsm.sim.state') 686 687 @property 688 def sim_operator(self): 689 """The SIM operator of the device. 690 """ 691 return self.getProp('gsm.operator.alpha') 692 693 def getKernelConfig(self, config_name): 694 """Gets kernel config from the device. 695 696 Args: 697 config_name: A string, the name of the configuration. 698 699 Returns: 700 "y" or "m" if the config is set. 701 "" if the config is not set. 702 None if fails to read config. 703 """ 704 line_prefix = config_name + "=" 705 with tempfile.NamedTemporaryFile(delete=False) as temp_file: 706 config_path = temp_file.name 707 try: 708 logging.debug("Pull config.gz to %s", config_path) 709 self.adb.pull("/proc/config.gz", config_path) 710 with gzip.GzipFile(config_path, "rb") as config_file: 711 for line in config_file: 712 if line.strip().startswith(line_prefix): 713 logging.debug("Found config: %s", line) 714 return line.strip()[len(line_prefix):] 715 logging.debug("%s is not set.", config_name) 716 return "" 717 except (adb.AdbError, IOError) as e: 718 logging.exception("Cannot read kernel config.", e) 719 return None 720 finally: 721 os.remove(config_path) 722 723 def getBinderBitness(self): 724 """Returns the value of BINDER_IPC_32BIT in kernel config. 725 726 Returns: 727 32 or 64, binder bitness of the device. 728 None if fails to read config. 729 """ 730 config_value = self.getKernelConfig("CONFIG_ANDROID_BINDER_IPC_32BIT") 731 if config_value is None: 732 return None 733 elif config_value: 734 return 32 735 else: 736 return 64 737 738 def loadConfig(self, config): 739 """Add attributes to the AndroidDevice object based on json config. 740 741 Args: 742 config: A dictionary representing the configs. 743 744 Raises: 745 AndroidDeviceError is raised if the config is trying to overwrite 746 an existing attribute. 747 """ 748 for k, v in config.items(): 749 if hasattr(self, k): 750 raise AndroidDeviceError( 751 "Attempting to set existing attribute %s on %s" % 752 (k, self.serial)) 753 setattr(self, k, v) 754 755 def rootAdb(self): 756 """Changes adb to root mode for this device.""" 757 if not self.isAdbRoot: 758 try: 759 self.adb.root() 760 self.adb.wait_for_device() 761 except adb.AdbError as e: 762 # adb wait-for-device is not always possible in the lab 763 # continue with an assumption it's done by the harness. 764 logging.exception(e) 765 766 def startAdbLogcat(self): 767 """Starts a standing adb logcat collection in separate subprocesses and 768 save the logcat in a file. 769 """ 770 if self.isAdbLogcatOn: 771 raise AndroidDeviceError(("Android device %s already has an adb " 772 "logcat thread going on. Cannot start " 773 "another one.") % self.serial) 774 event = tfi.Begin("start adb logcat from android_device", 775 tfi.categories.FRAMEWORK_SETUP) 776 777 f_name = "adblog_%s_%s.txt" % (self.model, self.serial) 778 utils.create_dir(self.log_path) 779 logcat_file_path = os.path.join(self.log_path, f_name) 780 try: 781 extra_params = self.adb_logcat_param 782 except AttributeError: 783 extra_params = "-b all" 784 cmd = "adb -s %s logcat -v threadtime %s >> %s" % (self.serial, 785 extra_params, 786 logcat_file_path) 787 self.adb_logcat_process = utils.start_standing_subprocess(cmd) 788 self.adb_logcat_file_path = logcat_file_path 789 event.End() 790 791 def stopAdbLogcat(self): 792 """Stops the adb logcat collection subprocess. 793 """ 794 if not self.isAdbLogcatOn: 795 raise AndroidDeviceError( 796 "Android device %s does not have an ongoing adb logcat collection." 797 % self.serial) 798 799 event = tfi.Begin("stop adb logcat from android_device", 800 tfi.categories.FRAMEWORK_TEARDOWN) 801 try: 802 utils.stop_standing_subprocess(self.adb_logcat_process) 803 except utils.VTSUtilsError as e: 804 event.Remove("Cannot stop adb logcat. %s" % e) 805 logging.error("Cannot stop adb logcat. %s", e) 806 self.adb_logcat_process = None 807 event.End() 808 809 def takeBugReport(self, test_name, begin_time): 810 """Takes a bug report on the device and stores it in a file. 811 812 Args: 813 test_name: Name of the test case that triggered this bug report. 814 begin_time: Logline format timestamp taken when the test started. 815 """ 816 br_path = os.path.join(self.log_path, "BugReports") 817 utils.create_dir(br_path) 818 base_name = ",%s,%s.txt" % (begin_time, self.serial) 819 test_name_len = utils.MAX_FILENAME_LEN - len(base_name) 820 out_name = test_name[:test_name_len] + base_name 821 full_out_path = os.path.join(br_path, out_name.replace(' ', '\ ')) 822 self.log.info("Taking bugreport for %s on %s", test_name, self.serial) 823 self.adb.bugreport(" > %s" % full_out_path) 824 self.log.info("Bugreport for %s taken at %s", test_name, full_out_path) 825 826 def waitForBootCompletion(self, timeout=900): 827 """Waits for Android framework to broadcast ACTION_BOOT_COMPLETED. 828 829 Args: 830 timeout: int, seconds to wait for boot completion. Default is 831 15 minutes. 832 833 Returns: 834 bool, True if boot completed. False if any error or timeout 835 """ 836 start = time.time() 837 try: 838 self.adb.wait_for_device(timeout=timeout) 839 except adb.AdbError as e: 840 # adb wait-for-device is not always possible in the lab 841 logging.exception(e) 842 return False 843 844 while not self.isBootCompleted(): 845 if time.time() - start >= timeout: 846 logging.error("Timeout while waiting for boot completion.") 847 return False 848 time.sleep(1) 849 850 return True 851 852 # Deprecated. Use isBootCompleted instead 853 def hasBooted(self): 854 """Checks whether the device has booted. 855 856 Returns: 857 True if booted, False otherwise. 858 """ 859 return self.isBootCompleted() 860 861 def isBootCompleted(self): 862 """Checks whether the device has booted. 863 864 Returns: 865 True if booted, False otherwise. 866 """ 867 try: 868 if (self.getProp(SYSPROP_SYS_BOOT_COMPLETED) == '1' and 869 self.getProp(SYSPROP_DEV_BOOTCOMPLETE) == '1'): 870 return True 871 except adb.AdbError: 872 # adb shell calls may fail during certain period of booting 873 # process, which is normal. Ignoring these errors. 874 pass 875 876 return False 877 878 def isFrameworkRunning(self, check_boot_completion=True): 879 """Checks whether Android framework is started. 880 881 This function will first check boot_completed prop. If boot_completed 882 is 0, then return False meaning framework not started. 883 Then this function will check whether system_server process is running. 884 If yes, then return True meaning framework is started. 885 886 The assumption here is if prop boot_completed is 0 then framework 887 is stopped. 888 889 There are still cases which can make this function return wrong 890 result. For example, boot_completed is set to 0 manually without 891 without stopping framework. 892 893 Args: 894 check_boot_completion: bool, whether to check boot completion 895 before checking framework status. This is an 896 important step for ensuring framework is 897 started. Under most circumstances this value 898 should be set to True. 899 Default True. 900 901 Returns: 902 True if started, False otherwise. 903 """ 904 # First, check whether boot has completed. 905 if check_boot_completion and not self.isBootCompleted(): 906 return False 907 908 cmd = 'ps -g system | grep system_server' 909 res = self.adb.shell(cmd, no_except=True) 910 911 return 'system_server' in res[const.STDOUT] 912 913 def startFramework(self, 914 wait_for_completion=True, 915 wait_for_completion_timeout=WAIT_TIMEOUT_SEC): 916 """Starts Android framework. 917 918 By default this function will wait for framework starting process to 919 finish before returning. 920 921 Args: 922 wait_for_completion: bool, whether to wait for framework to complete 923 starting. Default: True 924 wait_for_completion_timeout: timeout in seconds for waiting framework 925 to start. Default: 2 minutes 926 927 Returns: 928 bool, True if framework start success. False otherwise. 929 """ 930 logging.debug("starting Android framework") 931 self.adb.shell("start") 932 933 if wait_for_completion: 934 if not self.waitForFrameworkStartComplete( 935 wait_for_completion_timeout): 936 return False 937 938 logging.info("Android framework started.") 939 return True 940 941 def start(self, start_native_server=True): 942 """Starts Android framework and waits for ACTION_BOOT_COMPLETED. 943 944 Args: 945 start_native_server: bool, whether to start the native server. 946 Returns: 947 bool, True if framework start success. False otherwise. 948 """ 949 if start_native_server: 950 self.startNativeServer() 951 return self.startFramework() 952 953 def stopFramework(self): 954 """Stops Android framework. 955 956 Method will block until stop is complete. 957 """ 958 logging.debug("stopping Android framework") 959 self.adb.shell("stop") 960 self.setProp(SYSPROP_SYS_BOOT_COMPLETED, 0) 961 logging.info("Android framework stopped") 962 963 def stop(self, stop_native_server=False): 964 """Stops Android framework. 965 966 Method will block until stop is complete. 967 968 Args: 969 stop_native_server: bool, whether to stop the native server. 970 """ 971 self.stopFramework() 972 if stop_native_server: 973 self.stopNativeServer() 974 975 def waitForFrameworkStartComplete(self, timeout_secs=WAIT_TIMEOUT_SEC): 976 """Wait for Android framework to complete starting. 977 978 Args: 979 timeout_secs: int, seconds to wait for boot completion. Default is 980 2 minutes. 981 982 Returns: 983 bool, True if framework is started. False otherwise or timeout 984 """ 985 start = time.time() 986 987 # First, wait for boot completion and checks 988 if not self.waitForBootCompletion(timeout_secs): 989 return False 990 991 while not self.isFrameworkRunning(check_boot_completion=False): 992 if time.time() - start >= timeout_secs: 993 logging.error("Timeout while waiting for framework to start.") 994 return False 995 time.sleep(1) 996 return True 997 998 def startNativeServer(self): 999 """Starts all native servers.""" 1000 self.setProp(SYSPROP_VTS_NATIVE_SERVER, "0") 1001 1002 def stopNativeServer(self): 1003 """Stops all native servers.""" 1004 self.setProp(SYSPROP_VTS_NATIVE_SERVER, "1") 1005 1006 def isProcessRunning(self, process_name): 1007 """Check whether the given process is running. 1008 Args: 1009 process_name: string, name of the process. 1010 1011 Returns: 1012 bool, True if the process is running. 1013 1014 Raises: 1015 AndroidDeviceError, if ps command failed. 1016 """ 1017 logging.debug("Checking process %s", process_name) 1018 cmd_result = self.adb.shell.Execute("ps -A") 1019 if cmd_result[const.EXIT_CODE][0] != 0: 1020 logging.error("ps command failed (exit code: %s", 1021 cmd_result[const.EXIT_CODE][0]) 1022 raise AndroidDeviceError("ps command failed.") 1023 if (process_name not in cmd_result[const.STDOUT][0]): 1024 logging.debug("Process %s not running", process_name) 1025 return False 1026 return True 1027 1028 def waitForProcessStop(self, process_names, timeout_secs=WAIT_TIMEOUT_SEC): 1029 """Wait until the given process is stopped or timeout. 1030 1031 Args: 1032 process_names: list of string, name of the processes. 1033 timeout_secs: int, timeout in secs. 1034 1035 Returns: 1036 bool, True if the process stopped within timeout. 1037 """ 1038 if process_names: 1039 for process_name in process_names: 1040 start = time.time() 1041 while self.isProcessRunning(process_name): 1042 if time.time() - start >= timeout_secs: 1043 logging.error( 1044 "Timeout while waiting for process %s stop.", 1045 process_name) 1046 return False 1047 time.sleep(1) 1048 1049 return True 1050 1051 def setProp(self, name, value): 1052 """Calls setprop shell command. 1053 1054 Args: 1055 name: string, the name of a system property to set 1056 value: any type, value will be converted to string. Quotes in value 1057 is not supported at this time; if value contains a quote, 1058 this method will log an error and return. 1059 1060 Raises: 1061 AdbError, if name contains invalid character 1062 """ 1063 if name is None or value is None: 1064 logging.error("name or value of system property " 1065 "should not be None. No property is set.") 1066 return 1067 1068 value = str(value) 1069 1070 if "'" in value or "\"" in value: 1071 logging.error("Quotes in value of system property " 1072 "is not yet supported. No property is set.") 1073 return 1074 1075 self.adb.shell("setprop %s \"%s\"" % (name, value)) 1076 1077 def getProp(self, name, timeout=adb.DEFAULT_ADB_SHORT_TIMEOUT): 1078 """Calls getprop shell command. 1079 1080 Args: 1081 name: string, the name of a system property to get 1082 1083 Returns: 1084 string, value of the property. If name does not exist; an empty 1085 string will be returned. decode("utf-8") and strip() will be called 1086 on the output before returning; None will be returned if input 1087 name is None 1088 1089 Raises: 1090 AdbError, if name contains invalid character 1091 """ 1092 if name is None: 1093 logging.error("name of system property should not be None.") 1094 return None 1095 1096 out = self.adb.shell("getprop %s" % name, timeout=timeout) 1097 return out.decode("utf-8").strip() 1098 1099 def reboot(self, restart_services=True): 1100 """Reboots the device and wait for device to complete booting. 1101 1102 This is probably going to print some error messages in console. Only 1103 use if there's no other option. 1104 1105 Raises: 1106 AndroidDeviceError is raised if waiting for completion timed 1107 out. 1108 """ 1109 if self.isBootloaderMode: 1110 self.fastboot.reboot() 1111 return 1112 1113 if restart_services: 1114 has_adb_log = self.isAdbLogcatOn 1115 has_vts_agent = True if self.vts_agent_process else False 1116 if has_adb_log: 1117 self.stopAdbLogcat() 1118 if has_vts_agent: 1119 self.stopVtsAgent() 1120 1121 self.adb.reboot() 1122 self.waitForBootCompletion() 1123 self.rootAdb() 1124 1125 if restart_services: 1126 if has_adb_log: 1127 self.startAdbLogcat() 1128 if has_vts_agent: 1129 self.startVtsAgent() 1130 1131 def startServices(self): 1132 """Starts long running services on the android device. 1133 1134 1. Start adb logcat capture. 1135 2. Start VtsAgent and create HalMirror unless disabled in config. 1136 """ 1137 event = tfi.Begin("start vts services", 1138 tfi.categories.FRAMEWORK_SETUP) 1139 1140 self.enable_vts_agent = getattr(self, "enable_vts_agent", True) 1141 try: 1142 self.startAdbLogcat() 1143 except Exception as e: 1144 msg = "Failed to start adb logcat!" 1145 event.Remove(msg) 1146 self.log.error(msg) 1147 self.log.exception(e) 1148 raise 1149 if self.enable_vts_agent: 1150 self.startVtsAgent() 1151 self.device_command_port = int( 1152 self.adb.shell("cat /data/local/tmp/vts_tcp_server_port")) 1153 logging.debug("device_command_port: %s", self.device_command_port) 1154 if not self.host_command_port: 1155 self.host_command_port = adb.get_available_host_port() 1156 self.adb.tcp_forward(self.host_command_port, 1157 self.device_command_port) 1158 self.hal = mirror_tracker.MirrorTracker( 1159 self.host_command_port, self.host_callback_port, True) 1160 self.lib = mirror_tracker.MirrorTracker(self.host_command_port) 1161 self.shell = mirror_tracker.MirrorTracker( 1162 host_command_port=self.host_command_port, adb=self.adb) 1163 self.shell.shell_default_nohup = self.shell_default_nohup 1164 self.resource = mirror_tracker.MirrorTracker(self.host_command_port) 1165 event.End() 1166 1167 def Heal(self): 1168 """Performs a self healing. 1169 1170 Includes self diagnosis that looks for any framework errors. 1171 1172 Returns: 1173 bool, True if everything is ok; False otherwise. 1174 """ 1175 res = True 1176 1177 if self.shell: 1178 res &= self.shell.Heal() 1179 1180 try: 1181 self.getProp("ro.build.version.sdk") 1182 except adb.AdbError: 1183 if self.serial in list_adb_devices(): 1184 self.log.error( 1185 "Device is in adb devices, but is not responding!") 1186 elif self.isBootloaderMode: 1187 self.log.info("Device is in bootloader/fastbootd mode") 1188 return True 1189 else: 1190 self.log.error("Device is not in adb devices!") 1191 self.fatal_error = True 1192 res = False 1193 else: 1194 self.fatal_error = False 1195 if not res: 1196 self.log.error('Self diagnosis found problem') 1197 1198 return res 1199 1200 def stopServices(self): 1201 """Stops long running services on the android device.""" 1202 if self.adb_logcat_process: 1203 self.stopAdbLogcat() 1204 if getattr(self, "enable_vts_agent", True): 1205 self.stopVtsAgent() 1206 if self.hal: 1207 self.hal.CleanUp() 1208 1209 def _StartLLKD(self): 1210 """Starts LLKD""" 1211 if self.fatal_error: 1212 self.log.error("Device in fatal error state, skip starting llkd") 1213 return 1214 try: 1215 self.adb.shell('start %s' % LLKD) 1216 except adb.AdbError as e: 1217 logging.error('Failed to start llkd') 1218 1219 def _StopLLKD(self): 1220 """Stops LLKD""" 1221 if self.fatal_error: 1222 self.log.error("Device in fatal error state, skip stop llkd") 1223 return 1224 try: 1225 self.adb.shell('stop %s' % LLKD) 1226 except adb.AdbError as e: 1227 logging.error('Failed to stop llkd') 1228 1229 def startVtsAgent(self): 1230 """Start HAL agent on the AndroidDevice. 1231 1232 This function starts the target side native agent and is persisted 1233 throughout the test run. 1234 """ 1235 self.log.info("Starting VTS agent") 1236 if self.vts_agent_process: 1237 raise AndroidDeviceError( 1238 "HAL agent is already running on %s." % self.serial) 1239 1240 event = tfi.Begin("start vts agent", tfi.categories.FRAMEWORK_SETUP) 1241 1242 self._StopLLKD() 1243 1244 event_cleanup = tfi.Begin("start vts agent -- cleanup", tfi.categories.FRAMEWORK_SETUP) 1245 cleanup_commands = [ 1246 "rm -f /data/local/tmp/vts_driver_*", 1247 "rm -f /data/local/tmp/vts_agent_callback*" 1248 ] 1249 1250 kill_command = "pgrep 'vts_*' | xargs kill" 1251 cleanup_commands.append(kill_command) 1252 try: 1253 self.adb.shell("\"" + " ; ".join(cleanup_commands) + "\"") 1254 except adb.AdbError as e: 1255 self.log.warning( 1256 "A command to setup the env to start the VTS Agent failed %s", 1257 e) 1258 event_cleanup.End() 1259 1260 log_severity = getattr(self, keys.ConfigKeys.KEY_LOG_SEVERITY, "INFO") 1261 bits = ['64', '32'] if self.is64Bit else ['32'] 1262 file_names = ['vts_hal_agent', 'vts_hal_driver', 'vts_shell_driver'] 1263 for bitness in bits: 1264 vts_agent_log_path = os.path.join( 1265 self.log_path, 'vts_agent_%s_%s.log' % (bitness, self.serial)) 1266 1267 chmod_cmd = ' '.join( 1268 map(lambda file_name: 'chmod 755 {path}/{bit}/{file_name}{bit};'.format( 1269 path=DEFAULT_AGENT_BASE_DIR, 1270 bit=bitness, 1271 file_name=file_name), 1272 file_names)) 1273 1274 cmd = ('adb -s {s} shell "{chmod} LD_LIBRARY_PATH={path}/{bitness} ' 1275 '{path}/{bitness}/vts_hal_agent{bitness} ' 1276 '--hal_driver_path_32={path}/32/vts_hal_driver32 ' 1277 '--hal_driver_path_64={path}/64/vts_hal_driver64 ' 1278 '--spec_dir={path}/spec ' 1279 '--shell_driver_path_32={path}/32/vts_shell_driver32 ' 1280 '--shell_driver_path_64={path}/64/vts_shell_driver64 ' 1281 '-l {severity}" >> {log} 2>&1').format( 1282 s=self.serial, 1283 chmod=chmod_cmd, 1284 bitness=bitness, 1285 path=DEFAULT_AGENT_BASE_DIR, 1286 log=vts_agent_log_path, 1287 severity=log_severity) 1288 try: 1289 self.vts_agent_process = utils.start_standing_subprocess( 1290 cmd, check_health_delay=1) 1291 break 1292 except utils.VTSUtilsError as e: 1293 logging.exception(e) 1294 with open(vts_agent_log_path, 'r') as log_file: 1295 logging.error("VTS agent output:\n") 1296 logging.error(log_file.read()) 1297 # one common cause is that 64-bit executable is not supported 1298 # in low API level devices. 1299 if bitness == '32': 1300 msg = "unrecognized bitness" 1301 event.Remove(msg) 1302 logging.error(msg) 1303 raise 1304 else: 1305 logging.error('retrying using a 32-bit binary.') 1306 event.End() 1307 1308 def stopVtsAgent(self): 1309 """Stop the HAL agent running on the AndroidDevice. 1310 """ 1311 if not self.vts_agent_process: 1312 return 1313 try: 1314 utils.stop_standing_subprocess(self.vts_agent_process) 1315 except utils.VTSUtilsError as e: 1316 logging.error("Cannot stop VTS agent. %s", e) 1317 self.vts_agent_process = None 1318 1319 @property 1320 def product_type(self): 1321 """Gets the product type name.""" 1322 return self._product_type 1323 1324 def getPackagePid(self, package_name): 1325 """Gets the pid for a given package. Returns None if not running. 1326 1327 Args: 1328 package_name: The name of the package. 1329 1330 Returns: 1331 The first pid found under a given package name. None if no process 1332 was found running the package. 1333 1334 Raises: 1335 AndroidDeviceError if the output of the phone's process list was 1336 in an unexpected format. 1337 """ 1338 for cmd in ("ps -A", "ps"): 1339 try: 1340 out = self.adb.shell('%s | grep "S %s"' % (cmd, package_name)) 1341 if package_name not in out: 1342 continue 1343 try: 1344 pid = int(out.split()[1]) 1345 self.log.info('apk %s has pid %s.', package_name, pid) 1346 return pid 1347 except (IndexError, ValueError) as e: 1348 # Possible ValueError from string to int cast. 1349 # Possible IndexError from split. 1350 self.log.warn('Command \"%s\" returned output line: ' 1351 '\"%s\".\nError: %s', cmd, out, e) 1352 except Exception as e: 1353 self.log.warn( 1354 'Device fails to check if %s running with \"%s\"\n' 1355 'Exception %s', package_name, cmd, e) 1356 self.log.debug("apk %s is not running", package_name) 1357 return None 1358 1359 def getVintfXml(self, use_lshal=True): 1360 """Reads the vendor interface manifest Xml. 1361 1362 Args: 1363 use_hal: bool, set True to use lshal command and False to fetch 1364 manifest.xml directly. 1365 1366 Returns: 1367 Vendor interface manifest string. 1368 """ 1369 if not use_lshal: 1370 return None 1371 try: 1372 stdout = self.adb.shell('"lshal --init-vintf 2> /dev/null"') 1373 return str(stdout) 1374 except adb.AdbError as e: 1375 return None 1376 1377 1378class AndroidDeviceLoggerAdapter(logging.LoggerAdapter): 1379 """A wrapper class that attaches a prefix to all log lines from an 1380 AndroidDevice object. 1381 """ 1382 1383 def process(self, msg, kwargs): 1384 """Process every log message written via the wrapped logger object. 1385 1386 We are adding the prefix "[AndroidDevice|<serial>]" to all log lines. 1387 1388 Args: 1389 msg: string, the original log message. 1390 kwargs: dict, the key value pairs that can be used to modify the 1391 original log message. 1392 """ 1393 msg = "[AndroidDevice|%s] %s" % (self.extra["serial"], msg) 1394 return (msg, kwargs) 1395 1396 def warn(self, msg, *args, **kwargs): 1397 """Function call warper for warn() to warning().""" 1398 super(AndroidDeviceLoggerAdapter, self).warning(msg, *args, **kwargs) 1399