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