1#!/usr/bin/env python3 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 17import collections 18import logging 19import math 20import os 21import re 22import socket 23import time 24from builtins import open 25from builtins import str 26from datetime import datetime 27 28from acts import context 29from acts import logger as acts_logger 30from acts import tracelogger 31from acts import utils 32from acts.controllers import adb 33from acts.controllers.adb_lib.error import AdbError 34from acts.controllers import fastboot 35from acts.controllers.android_lib import errors 36from acts.controllers.android_lib import events as android_events 37from acts.controllers.android_lib import logcat 38from acts.controllers.android_lib import services 39from acts.controllers.sl4a_lib import sl4a_manager 40from acts.controllers.utils_lib.ssh import connection 41from acts.controllers.utils_lib.ssh import settings 42from acts.event import event_bus 43from acts.libs.proc import job 44from acts.metrics.loggers.usage_metadata_logger import record_api_usage 45 46MOBLY_CONTROLLER_CONFIG_NAME = "AndroidDevice" 47ACTS_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!" 54CRASH_REPORT_PATHS = ("/data/tombstones/", "/data/vendor/ramdump/", 55 "/data/ramdump/", "/data/vendor/ssrdump", 56 "/data/vendor/ramdump/bluetooth", "/data/vendor/log/cbd") 57CRASH_REPORT_SKIPS = ("RAMDUMP_RESERVED", "RAMDUMP_STATUS", "RAMDUMP_OUTPUT", 58 "bluetooth") 59DEFAULT_QXDM_LOG_PATH = "/data/vendor/radio/diag_logs" 60DEFAULT_SDM_LOG_PATH = "/data/vendor/slog/" 61BUG_REPORT_TIMEOUT = 1800 62PULL_TIMEOUT = 300 63PORT_RETRY_COUNT = 3 64IPERF_TIMEOUT = 60 65SL4A_APK_NAME = "com.googlecode.android_scripting" 66WAIT_FOR_DEVICE_TIMEOUT = 180 67ENCRYPTION_WINDOW = "CryptKeeper" 68DEFAULT_DEVICE_PASSWORD = "1111" 69RELEASE_ID_REGEXES = [re.compile(r'\w+\.\d+\.\d+'), re.compile(r'N\w+')] 70 71 72def create(configs): 73 """Creates AndroidDevice controller objects. 74 75 Args: 76 configs: A list of dicts, each representing a configuration for an 77 Android device. 78 79 Returns: 80 A list of AndroidDevice objects. 81 """ 82 if not configs: 83 raise errors.AndroidDeviceConfigError(ANDROID_DEVICE_EMPTY_CONFIG_MSG) 84 elif configs == ANDROID_DEVICE_PICK_ALL_TOKEN: 85 ads = get_all_instances() 86 elif not isinstance(configs, list): 87 raise errors.AndroidDeviceConfigError( 88 ANDROID_DEVICE_NOT_LIST_CONFIG_MSG) 89 elif isinstance(configs[0], str): 90 # Configs is a list of serials. 91 ads = get_instances(configs) 92 else: 93 # Configs is a list of dicts. 94 ads = get_instances_with_configs(configs) 95 96 ads[0].log.info('The primary device under test is "%s".' % ads[0].serial) 97 98 for ad in ads: 99 if not ad.is_connected(): 100 raise errors.AndroidDeviceError( 101 ("Android device %s is specified in config" 102 " but is not attached.") % ad.serial, 103 serial=ad.serial) 104 _start_services_on_ads(ads) 105 for ad in ads: 106 if ad.droid: 107 utils.set_location_service(ad, False) 108 utils.sync_device_time(ad) 109 return ads 110 111 112def destroy(ads): 113 """Cleans up AndroidDevice objects. 114 115 Args: 116 ads: A list of AndroidDevice objects. 117 """ 118 for ad in ads: 119 try: 120 ad.clean_up() 121 except: 122 ad.log.exception("Failed to clean up properly.") 123 124 125def get_info(ads): 126 """Get information on a list of AndroidDevice objects. 127 128 Args: 129 ads: A list of AndroidDevice objects. 130 131 Returns: 132 A list of dict, each representing info for an AndroidDevice objects. 133 """ 134 device_info = [] 135 for ad in ads: 136 info = {"serial": ad.serial, "model": ad.model} 137 info.update(ad.build_info) 138 device_info.append(info) 139 return device_info 140 141 142def _start_services_on_ads(ads): 143 """Starts long running services on multiple AndroidDevice objects. 144 145 If any one AndroidDevice object fails to start services, cleans up all 146 existing AndroidDevice objects and their services. 147 148 Args: 149 ads: A list of AndroidDevice objects whose services to start. 150 """ 151 running_ads = [] 152 for ad in ads: 153 running_ads.append(ad) 154 try: 155 ad.start_services() 156 except: 157 ad.log.exception('Failed to start some services, abort!') 158 destroy(running_ads) 159 raise 160 161 162def _parse_device_list(device_list_str, key): 163 """Parses a byte string representing a list of devices. The string is 164 generated by calling either adb or fastboot. 165 166 Args: 167 device_list_str: Output of adb or fastboot. 168 key: The token that signifies a device in device_list_str. 169 170 Returns: 171 A list of android device serial numbers. 172 """ 173 return re.findall(r"(\S+)\t%s" % key, device_list_str) 174 175 176def list_adb_devices(): 177 """List all android devices connected to the computer that are detected by 178 adb. 179 180 Returns: 181 A list of android device serials. Empty if there's none. 182 """ 183 out = adb.AdbProxy().devices() 184 return _parse_device_list(out, "device") 185 186 187def list_fastboot_devices(): 188 """List all android devices connected to the computer that are in in 189 fastboot mode. These are detected by fastboot. 190 191 Returns: 192 A list of android device serials. Empty if there's none. 193 """ 194 out = fastboot.FastbootProxy().devices() 195 return _parse_device_list(out, "fastboot") 196 197 198def get_instances(serials): 199 """Create AndroidDevice instances from a list of serials. 200 201 Args: 202 serials: A list of android device serials. 203 204 Returns: 205 A list of AndroidDevice objects. 206 """ 207 results = [] 208 for s in serials: 209 results.append(AndroidDevice(s)) 210 return results 211 212 213def get_instances_with_configs(configs): 214 """Create AndroidDevice instances from a list of json configs. 215 216 Each config should have the required key-value pair "serial". 217 218 Args: 219 configs: A list of dicts each representing the configuration of one 220 android device. 221 222 Returns: 223 A list of AndroidDevice objects. 224 """ 225 results = [] 226 for c in configs: 227 try: 228 serial = c.pop('serial') 229 except KeyError: 230 raise errors.AndroidDeviceConfigError( 231 "Required value 'serial' is missing in AndroidDevice config %s." 232 % c) 233 ssh_config = c.pop('ssh_config', None) 234 ssh_connection = None 235 if ssh_config is not None: 236 ssh_settings = settings.from_config(ssh_config) 237 ssh_connection = connection.SshConnection(ssh_settings) 238 ad = AndroidDevice(serial, ssh_connection=ssh_connection) 239 ad.load_config(c) 240 results.append(ad) 241 return results 242 243 244def get_all_instances(include_fastboot=False): 245 """Create AndroidDevice instances for all attached android devices. 246 247 Args: 248 include_fastboot: Whether to include devices in bootloader mode or not. 249 250 Returns: 251 A list of AndroidDevice objects each representing an android device 252 attached to the computer. 253 """ 254 if include_fastboot: 255 serial_list = list_adb_devices() + list_fastboot_devices() 256 return get_instances(serial_list) 257 return get_instances(list_adb_devices()) 258 259 260def filter_devices(ads, func): 261 """Finds the AndroidDevice instances from a list that match certain 262 conditions. 263 264 Args: 265 ads: A list of AndroidDevice instances. 266 func: A function that takes an AndroidDevice object and returns True 267 if the device satisfies the filter condition. 268 269 Returns: 270 A list of AndroidDevice instances that satisfy the filter condition. 271 """ 272 results = [] 273 for ad in ads: 274 if func(ad): 275 results.append(ad) 276 return results 277 278 279def get_device(ads, **kwargs): 280 """Finds a unique AndroidDevice instance from a list that has specific 281 attributes of certain values. 282 283 Example: 284 get_device(android_devices, label="foo", phone_number="1234567890") 285 get_device(android_devices, model="angler") 286 287 Args: 288 ads: A list of AndroidDevice instances. 289 kwargs: keyword arguments used to filter AndroidDevice instances. 290 291 Returns: 292 The target AndroidDevice instance. 293 294 Raises: 295 AndroidDeviceError is raised if none or more than one device is 296 matched. 297 """ 298 299 def _get_device_filter(ad): 300 for k, v in kwargs.items(): 301 if not hasattr(ad, k): 302 return False 303 elif getattr(ad, k) != v: 304 return False 305 return True 306 307 filtered = filter_devices(ads, _get_device_filter) 308 if not filtered: 309 raise ValueError( 310 "Could not find a target device that matches condition: %s." % 311 kwargs) 312 elif len(filtered) == 1: 313 return filtered[0] 314 else: 315 serials = [ad.serial for ad in filtered] 316 raise ValueError("More than one device matched: %s" % serials) 317 318 319def take_bug_reports(ads, test_name, begin_time): 320 """Takes bug reports on a list of android devices. 321 322 If you want to take a bug report, call this function with a list of 323 android_device objects in on_fail. But reports will be taken on all the 324 devices in the list concurrently. Bug report takes a relative long 325 time to take, so use this cautiously. 326 327 Args: 328 ads: A list of AndroidDevice instances. 329 test_name: Name of the test case that triggered this bug report. 330 begin_time: Logline format timestamp taken when the test started. 331 """ 332 333 def take_br(test_name, begin_time, ad): 334 ad.take_bug_report(test_name, begin_time) 335 336 args = [(test_name, begin_time, ad) for ad in ads] 337 utils.concurrent_exec(take_br, args) 338 339 340class AndroidDevice: 341 """Class representing an android device. 342 343 Each object of this class represents one Android device in ACTS, including 344 handles to adb, fastboot, and sl4a clients. In addition to direct adb 345 commands, this object also uses adb port forwarding to talk to the Android 346 device. 347 348 Attributes: 349 serial: A string that's the serial number of the Android device. 350 log_path: A string that is the path where all logs collected on this 351 android device should be stored. 352 log: A logger adapted from root logger with added token specific to an 353 AndroidDevice instance. 354 adb_logcat_process: A process that collects the adb logcat. 355 adb: An AdbProxy object used for interacting with the device via adb. 356 fastboot: A FastbootProxy object used for interacting with the device 357 via fastboot. 358 """ 359 360 def __init__(self, serial='', ssh_connection=None): 361 self.serial = serial 362 # logging.log_path only exists when this is used in an ACTS test run. 363 log_path_base = getattr(logging, 'log_path', '/tmp/logs') 364 self.log_dir = 'AndroidDevice%s' % serial 365 self.log_path = os.path.join(log_path_base, self.log_dir) 366 self.log = tracelogger.TraceLogger( 367 AndroidDeviceLoggerAdapter(logging.getLogger(), 368 {'serial': serial})) 369 self._event_dispatchers = {} 370 self._services = [] 371 self.register_service(services.AdbLogcatService(self)) 372 self.register_service(services.Sl4aService(self)) 373 self.adb_logcat_process = None 374 self.adb = adb.AdbProxy(serial, ssh_connection=ssh_connection) 375 self.fastboot = fastboot.FastbootProxy( 376 serial, ssh_connection=ssh_connection) 377 if not self.is_bootloader: 378 self.root_adb() 379 self._ssh_connection = ssh_connection 380 self.skip_sl4a = False 381 self.crash_report = None 382 self.data_accounting = collections.defaultdict(int) 383 self._sl4a_manager = sl4a_manager.Sl4aManager(self.adb) 384 self.last_logcat_timestamp = None 385 # Device info cache. 386 self._user_added_device_info = {} 387 self._sdk_api_level = None 388 389 def clean_up(self): 390 """Cleans up the AndroidDevice object and releases any resources it 391 claimed. 392 """ 393 self.stop_services() 394 for service in self._services: 395 service.unregister() 396 self._services.clear() 397 if self._ssh_connection: 398 self._ssh_connection.close() 399 400 def register_service(self, service): 401 """Registers the service on the device. """ 402 service.register() 403 self._services.append(service) 404 405 # TODO(angli): This function shall be refactored to accommodate all services 406 # and not have hard coded switch for SL4A when b/29157104 is done. 407 def start_services(self, skip_setup_wizard=True): 408 """Starts long running services on the android device. 409 410 1. Start adb logcat capture. 411 2. Start SL4A if not skipped. 412 413 Args: 414 skip_setup_wizard: Whether or not to skip the setup wizard. 415 """ 416 if skip_setup_wizard: 417 self.exit_setup_wizard() 418 419 event_bus.post(android_events.AndroidStartServicesEvent(self)) 420 421 def stop_services(self): 422 """Stops long running services on the android device. 423 424 Stop adb logcat and terminate sl4a sessions if exist. 425 """ 426 event_bus.post( 427 android_events.AndroidStopServicesEvent(self), ignore_errors=True) 428 429 def is_connected(self): 430 out = self.adb.devices() 431 devices = _parse_device_list(out, "device") 432 return self.serial in devices 433 434 @property 435 def build_info(self): 436 """Get the build info of this Android device, including build id and 437 build type. 438 439 This is not available if the device is in bootloader mode. 440 441 Returns: 442 A dict with the build info of this Android device, or None if the 443 device is in bootloader mode. 444 """ 445 if self.is_bootloader: 446 self.log.error("Device is in fastboot mode, could not get build " 447 "info.") 448 return 449 450 build_id = self.adb.getprop("ro.build.id") 451 incremental_build_id = self.adb.getprop("ro.build.version.incremental") 452 valid_build_id = False 453 for regex in RELEASE_ID_REGEXES: 454 if re.match(regex, build_id): 455 valid_build_id = True 456 break 457 if not valid_build_id: 458 build_id = incremental_build_id 459 460 info = { 461 "build_id": build_id, 462 "incremental_build_id": incremental_build_id, 463 "build_type": self.adb.getprop("ro.build.type") 464 } 465 return info 466 467 @property 468 def device_info(self): 469 """Information to be pulled into controller info. 470 471 The latest serial, model, and build_info are included. Additional info 472 can be added via `add_device_info`. 473 """ 474 info = { 475 'serial': self.serial, 476 'model': self.model, 477 'build_info': self.build_info, 478 'user_added_info': self._user_added_device_info, 479 'flavor': self.flavor 480 } 481 return info 482 483 def sdk_api_level(self): 484 if self._sdk_api_level is not None: 485 return self._sdk_api_level 486 if self.is_bootloader: 487 self.log.error( 488 'Device is in fastboot mode. Cannot get build info.') 489 return 490 self._sdk_api_level = int( 491 self.adb.shell('getprop ro.build.version.sdk')) 492 return self._sdk_api_level 493 494 @property 495 def is_bootloader(self): 496 """True if the device is in bootloader mode. 497 """ 498 return self.serial in list_fastboot_devices() 499 500 @property 501 def is_adb_root(self): 502 """True if adb is running as root for this device. 503 """ 504 try: 505 return "0" == self.adb.shell("id -u") 506 except AdbError: 507 # Wait a bit and retry to work around adb flakiness for this cmd. 508 time.sleep(0.2) 509 return "0" == self.adb.shell("id -u") 510 511 @property 512 def model(self): 513 """The Android code name for the device.""" 514 # If device is in bootloader mode, get mode name from fastboot. 515 if self.is_bootloader: 516 out = self.fastboot.getvar("product").strip() 517 # "out" is never empty because of the "total time" message fastboot 518 # writes to stderr. 519 lines = out.split('\n', 1) 520 if lines: 521 tokens = lines[0].split(' ') 522 if len(tokens) > 1: 523 return tokens[1].lower() 524 return None 525 model = self.adb.getprop("ro.build.product").lower() 526 if model == "sprout": 527 return model 528 else: 529 return self.adb.getprop("ro.product.name").lower() 530 531 @property 532 def flavor(self): 533 """Returns the specific flavor of Android build the device is using.""" 534 return self.adb.getprop("ro.build.flavor").lower() 535 536 @property 537 def droid(self): 538 """Returns the RPC Service of the first Sl4aSession created.""" 539 if len(self._sl4a_manager.sessions) > 0: 540 session_id = sorted(self._sl4a_manager.sessions.keys())[0] 541 return self._sl4a_manager.sessions[session_id].rpc_client 542 else: 543 return None 544 545 @property 546 def ed(self): 547 """Returns the event dispatcher of the first Sl4aSession created.""" 548 if len(self._sl4a_manager.sessions) > 0: 549 session_id = sorted(self._sl4a_manager.sessions.keys())[0] 550 return self._sl4a_manager.sessions[ 551 session_id].get_event_dispatcher() 552 else: 553 return None 554 555 @property 556 def sl4a_sessions(self): 557 """Returns a dictionary of session ids to sessions.""" 558 return list(self._sl4a_manager.sessions) 559 560 @property 561 def is_adb_logcat_on(self): 562 """Whether there is an ongoing adb logcat collection. 563 """ 564 if self.adb_logcat_process: 565 if self.adb_logcat_process.is_running(): 566 return True 567 else: 568 # if skip_sl4a is true, there is no sl4a session 569 # if logcat died due to device reboot and sl4a session has 570 # not restarted there is no droid. 571 if self.droid: 572 self.droid.logI('Logcat died') 573 self.log.info("Logcat to %s died", self.log_path) 574 return False 575 return False 576 577 @property 578 def device_log_path(self): 579 """Returns the directory for all Android device logs for the current 580 test context and serial. 581 """ 582 return context.get_current_context().get_full_output_path(self.serial) 583 584 def update_sdk_api_level(self): 585 self._sdk_api_level = None 586 self.sdk_api_level() 587 588 def load_config(self, config): 589 """Add attributes to the AndroidDevice object based on json config. 590 591 Args: 592 config: A dictionary representing the configs. 593 594 Raises: 595 AndroidDeviceError is raised if the config is trying to overwrite 596 an existing attribute. 597 """ 598 for k, v in config.items(): 599 # skip_sl4a value can be reset from config file 600 if hasattr(self, k) and k != "skip_sl4a": 601 raise errors.AndroidDeviceError( 602 "Attempting to set existing attribute %s on %s" % 603 (k, self.serial), 604 serial=self.serial) 605 setattr(self, k, v) 606 607 def root_adb(self): 608 """Change adb to root mode for this device if allowed. 609 610 If executed on a production build, adb will not be switched to root 611 mode per security restrictions. 612 """ 613 self.adb.root() 614 self.adb.wait_for_device() 615 616 def get_droid(self, handle_event=True): 617 """Create an sl4a connection to the device. 618 619 Return the connection handler 'droid'. By default, another connection 620 on the same session is made for EventDispatcher, and the dispatcher is 621 returned to the caller as well. 622 If sl4a server is not started on the device, try to start it. 623 624 Args: 625 handle_event: True if this droid session will need to handle 626 events. 627 628 Returns: 629 droid: Android object used to communicate with sl4a on the android 630 device. 631 ed: An optional EventDispatcher to organize events for this droid. 632 633 Examples: 634 Don't need event handling: 635 >>> ad = AndroidDevice() 636 >>> droid = ad.get_droid(False) 637 638 Need event handling: 639 >>> ad = AndroidDevice() 640 >>> droid, ed = ad.get_droid() 641 """ 642 session = self._sl4a_manager.create_session() 643 droid = session.rpc_client 644 if handle_event: 645 ed = session.get_event_dispatcher() 646 return droid, ed 647 return droid 648 649 def get_package_pid(self, package_name): 650 """Gets the pid for a given package. Returns None if not running. 651 Args: 652 package_name: The name of the package. 653 Returns: 654 The first pid found under a given package name. None if no process 655 was found running the package. 656 Raises: 657 AndroidDeviceError if the output of the phone's process list was 658 in an unexpected format. 659 """ 660 for cmd in ("ps -A", "ps"): 661 try: 662 out = self.adb.shell( 663 '%s | grep "S %s"' % (cmd, package_name), 664 ignore_status=True) 665 if package_name not in out: 666 continue 667 try: 668 pid = int(out.split()[1]) 669 self.log.info('apk %s has pid %s.', package_name, pid) 670 return pid 671 except (IndexError, ValueError) as e: 672 # Possible ValueError from string to int cast. 673 # Possible IndexError from split. 674 self.log.warn( 675 'Command \"%s\" returned output line: ' 676 '\"%s\".\nError: %s', cmd, out, e) 677 except Exception as e: 678 self.log.warn( 679 'Device fails to check if %s running with \"%s\"\n' 680 'Exception %s', package_name, cmd, e) 681 self.log.debug("apk %s is not running", package_name) 682 return None 683 684 def get_dispatcher(self, droid): 685 """Return an EventDispatcher for an sl4a session 686 687 Args: 688 droid: Session to create EventDispatcher for. 689 690 Returns: 691 ed: An EventDispatcher for specified session. 692 """ 693 return self._sl4a_manager.sessions[droid.uid].get_event_dispatcher() 694 695 def _is_timestamp_in_range(self, target, log_begin_time, log_end_time): 696 low = acts_logger.logline_timestamp_comparator(log_begin_time, 697 target) <= 0 698 high = acts_logger.logline_timestamp_comparator(log_end_time, 699 target) >= 0 700 return low and high 701 702 def cat_adb_log(self, 703 tag, 704 begin_time, 705 end_time=None, 706 dest_path="AdbLogExcerpts"): 707 """Takes an excerpt of the adb logcat log from a certain time point to 708 current time. 709 710 Args: 711 tag: An identifier of the time period, usually the name of a test. 712 begin_time: Epoch time of the beginning of the time period. 713 end_time: Epoch time of the ending of the time period, default None 714 dest_path: Destination path of the excerpt file. 715 """ 716 log_begin_time = acts_logger.epoch_to_log_line_timestamp(begin_time) 717 if end_time is None: 718 log_end_time = acts_logger.get_log_line_timestamp() 719 else: 720 log_end_time = acts_logger.epoch_to_log_line_timestamp(end_time) 721 self.log.debug("Extracting adb log from logcat.") 722 logcat_path = os.path.join(self.device_log_path, 723 'adblog_%s_debug.txt' % self.serial) 724 if not os.path.exists(logcat_path): 725 self.log.warning("Logcat file %s does not exist." % logcat_path) 726 return 727 adb_excerpt_dir = os.path.join(self.log_path, dest_path) 728 os.makedirs(adb_excerpt_dir, exist_ok=True) 729 out_name = '%s,%s.txt' % (acts_logger.normalize_log_line_timestamp( 730 log_begin_time), self.serial) 731 tag_len = utils.MAX_FILENAME_LEN - len(out_name) 732 out_name = '%s,%s' % (tag[:tag_len], out_name) 733 adb_excerpt_path = os.path.join(adb_excerpt_dir, out_name) 734 with open(adb_excerpt_path, 'w', encoding='utf-8') as out: 735 in_file = logcat_path 736 with open(in_file, 'r', encoding='utf-8', errors='replace') as f: 737 while True: 738 line = None 739 try: 740 line = f.readline() 741 if not line: 742 break 743 except: 744 continue 745 line_time = line[:acts_logger.log_line_timestamp_len] 746 if not acts_logger.is_valid_logline_timestamp(line_time): 747 continue 748 if self._is_timestamp_in_range(line_time, log_begin_time, 749 log_end_time): 750 if not line.endswith('\n'): 751 line += '\n' 752 out.write(line) 753 return adb_excerpt_path 754 755 def search_logcat(self, matching_string, begin_time=None): 756 """Search logcat message with given string. 757 758 Args: 759 matching_string: matching_string to search. 760 761 Returns: 762 A list of dictionaries with full log message, time stamp string 763 and time object. For example: 764 [{"log_message": "05-03 17:39:29.898 968 1001 D" 765 "ActivityManager: Sending BOOT_COMPLETE user #0", 766 "time_stamp": "2017-05-03 17:39:29.898", 767 "datetime_obj": datetime object}] 768 """ 769 logcat_path = os.path.join(self.device_log_path, 770 'adblog_%s_debug.txt' % self.serial) 771 if not os.path.exists(logcat_path): 772 self.log.warning("Logcat file %s does not exist." % logcat_path) 773 return 774 output = job.run( 775 "grep '%s' %s" % (matching_string, logcat_path), 776 ignore_status=True) 777 if not output.stdout or output.exit_status != 0: 778 return [] 779 if begin_time: 780 log_begin_time = acts_logger.epoch_to_log_line_timestamp( 781 begin_time) 782 begin_time = datetime.strptime(log_begin_time, 783 "%Y-%m-%d %H:%M:%S.%f") 784 result = [] 785 logs = re.findall(r'(\S+\s\S+)(.*)', output.stdout) 786 for log in logs: 787 time_stamp = log[0] 788 time_obj = datetime.strptime(time_stamp, "%Y-%m-%d %H:%M:%S.%f") 789 if begin_time and time_obj < begin_time: 790 continue 791 result.append({ 792 "log_message": "".join(log), 793 "time_stamp": time_stamp, 794 "datetime_obj": time_obj 795 }) 796 return result 797 798 def start_adb_logcat(self): 799 """Starts a standing adb logcat collection in separate subprocesses and 800 save the logcat in a file. 801 """ 802 if self.is_adb_logcat_on: 803 self.log.warn( 804 'Android device %s already has a running adb logcat thread. ' % 805 self.serial) 806 return 807 # Disable adb log spam filter. Have to stop and clear settings first 808 # because 'start' doesn't support --clear option before Android N. 809 self.adb.shell("logpersist.stop --clear") 810 self.adb.shell("logpersist.start") 811 if hasattr(self, 'adb_logcat_param'): 812 extra_params = self.adb_logcat_param 813 else: 814 extra_params = "-b all" 815 816 self.adb_logcat_process = logcat.create_logcat_keepalive_process( 817 self.serial, self.log_dir, extra_params) 818 self.adb_logcat_process.start() 819 820 def stop_adb_logcat(self): 821 """Stops the adb logcat collection subprocess. 822 """ 823 if not self.is_adb_logcat_on: 824 self.log.warn( 825 'Android device %s does not have an ongoing adb logcat ' % 826 self.serial) 827 return 828 # Set the last timestamp to the current timestamp. This may cause 829 # a race condition that allows the same line to be logged twice, 830 # but it does not pose a problem for our logging purposes. 831 self.adb_logcat_process.stop() 832 self.adb_logcat_process = None 833 834 def get_apk_uid(self, apk_name): 835 """Get the uid of the given apk. 836 837 Args: 838 apk_name: Name of the package, e.g., com.android.phone. 839 840 Returns: 841 Linux UID for the apk. 842 """ 843 output = self.adb.shell( 844 "dumpsys package %s | grep userId=" % apk_name, ignore_status=True) 845 result = re.search(r"userId=(\d+)", output) 846 if result: 847 return result.group(1) 848 else: 849 None 850 851 def is_apk_installed(self, package_name): 852 """Check if the given apk is already installed. 853 854 Args: 855 package_name: Name of the package, e.g., com.android.phone. 856 857 Returns: 858 True if package is installed. False otherwise. 859 """ 860 861 try: 862 return bool( 863 self.adb.shell( 864 '(pm list packages | grep -w "package:%s") || true' % 865 package_name)) 866 867 except Exception as err: 868 self.log.error( 869 'Could not determine if %s is installed. ' 870 'Received error:\n%s', package_name, err) 871 return False 872 873 def is_sl4a_installed(self): 874 return self.is_apk_installed(SL4A_APK_NAME) 875 876 def is_apk_running(self, package_name): 877 """Check if the given apk is running. 878 879 Args: 880 package_name: Name of the package, e.g., com.android.phone. 881 882 Returns: 883 True if package is installed. False otherwise. 884 """ 885 for cmd in ("ps -A", "ps"): 886 try: 887 out = self.adb.shell( 888 '%s | grep "S %s"' % (cmd, package_name), 889 ignore_status=True) 890 if package_name in out: 891 self.log.info("apk %s is running", package_name) 892 return True 893 except Exception as e: 894 self.log.warn( 895 "Device fails to check is %s running by %s " 896 "Exception %s", package_name, cmd, e) 897 continue 898 self.log.debug("apk %s is not running", package_name) 899 return False 900 901 def is_sl4a_running(self): 902 return self.is_apk_running(SL4A_APK_NAME) 903 904 def force_stop_apk(self, package_name): 905 """Force stop the given apk. 906 907 Args: 908 package_name: Name of the package, e.g., com.android.phone. 909 910 Returns: 911 True if package is installed. False otherwise. 912 """ 913 try: 914 self.adb.shell( 915 'am force-stop %s' % package_name, ignore_status=True) 916 except Exception as e: 917 self.log.warn("Fail to stop package %s: %s", package_name, e) 918 919 def stop_sl4a(self): 920 # TODO(markdr): Move this into sl4a_manager. 921 return self.force_stop_apk(SL4A_APK_NAME) 922 923 def start_sl4a(self): 924 self._sl4a_manager.start_sl4a_service() 925 926 def take_bug_report(self, test_name, begin_time): 927 """Takes a bug report on the device and stores it in a file. 928 929 Args: 930 test_name: Name of the test case that triggered this bug report. 931 begin_time: Epoch time when the test started. 932 """ 933 self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT) 934 new_br = True 935 try: 936 stdout = self.adb.shell("bugreportz -v") 937 # This check is necessary for builds before N, where adb shell's ret 938 # code and stderr are not propagated properly. 939 if "not found" in stdout: 940 new_br = False 941 except AdbError: 942 new_br = False 943 br_path = self.device_log_path 944 os.makedirs(br_path, exist_ok=True) 945 time_stamp = acts_logger.normalize_log_line_timestamp( 946 acts_logger.epoch_to_log_line_timestamp(begin_time)) 947 out_name = "AndroidDevice%s_%s" % ( 948 self.serial, time_stamp.replace(" ", "_").replace(":", "-")) 949 out_name = "%s.zip" % out_name if new_br else "%s.txt" % out_name 950 full_out_path = os.path.join(br_path, out_name) 951 # in case device restarted, wait for adb interface to return 952 self.wait_for_boot_completion() 953 self.log.info("Taking bugreport for %s.", test_name) 954 if new_br: 955 out = self.adb.shell("bugreportz", timeout=BUG_REPORT_TIMEOUT) 956 if not out.startswith("OK"): 957 raise errors.AndroidDeviceError( 958 'Failed to take bugreport on %s: %s' % (self.serial, out), 959 serial=self.serial) 960 br_out_path = out.split(':')[1].strip().split()[0] 961 self.adb.pull("%s %s" % (br_out_path, full_out_path)) 962 else: 963 self.adb.bugreport( 964 " > {}".format(full_out_path), timeout=BUG_REPORT_TIMEOUT) 965 self.log.info("Bugreport for %s taken at %s.", test_name, 966 full_out_path) 967 self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT) 968 969 def get_file_names(self, 970 directory, 971 begin_time=None, 972 skip_files=[], 973 match_string=None): 974 """Get files names with provided directory.""" 975 cmd = "find %s -type f" % directory 976 if begin_time: 977 current_time = utils.get_current_epoch_time() 978 seconds = int(math.ceil((current_time - begin_time) / 1000.0)) 979 cmd = "%s -mtime -%ss" % (cmd, seconds) 980 if match_string: 981 cmd = "%s -iname %s" % (cmd, match_string) 982 for skip_file in skip_files: 983 cmd = "%s ! -iname %s" % (cmd, skip_file) 984 out = self.adb.shell(cmd, ignore_status=True) 985 if not out or "No such" in out or "Permission denied" in out or \ 986 "Not a directory" in out: 987 return [] 988 files = out.split("\n") 989 self.log.debug("Find files in directory %s: %s", directory, files) 990 return files 991 992 @property 993 def external_storage_path(self): 994 """ 995 The $EXTERNAL_STORAGE path on the device. Most commonly set to '/sdcard' 996 """ 997 return self.adb.shell('echo $EXTERNAL_STORAGE') 998 999 def pull_files(self, device_paths, host_path=None): 1000 """Pull files from devices. 1001 1002 Args: 1003 device_paths: List of paths on the device to pull from. 1004 host_path: Destination path 1005 """ 1006 if isinstance(device_paths, str): 1007 device_paths = [device_paths] 1008 if not host_path: 1009 host_path = self.log_path 1010 for device_path in device_paths: 1011 self.log.info( 1012 'Pull from device: %s -> %s' % (device_path, host_path)) 1013 self.adb.pull( 1014 "%s %s" % (device_path, host_path), timeout=PULL_TIMEOUT) 1015 1016 def check_crash_report(self, 1017 test_name=None, 1018 begin_time=None, 1019 log_crash_report=False): 1020 """check crash report on the device.""" 1021 crash_reports = [] 1022 for crash_path in CRASH_REPORT_PATHS: 1023 try: 1024 cmd = 'cd %s' % crash_path 1025 self.adb.shell(cmd) 1026 except Exception as e: 1027 self.log.debug("received exception %s", e) 1028 continue 1029 crashes = self.get_file_names( 1030 crash_path, 1031 skip_files=CRASH_REPORT_SKIPS, 1032 begin_time=begin_time) 1033 if crash_path == "/data/tombstones/" and crashes: 1034 tombstones = crashes[:] 1035 for tombstone in tombstones: 1036 if self.adb.shell( 1037 'cat %s | grep "crash_dump failed to dump process"' 1038 % tombstone): 1039 crashes.remove(tombstone) 1040 if crashes: 1041 crash_reports.extend(crashes) 1042 if crash_reports and log_crash_report: 1043 test_name = test_name or time.strftime("%Y-%m-%d-%Y-%H-%M-%S") 1044 crash_log_path = os.path.join(self.log_path, test_name, 1045 "Crashes_%s" % self.serial) 1046 os.makedirs(crash_log_path, exist_ok=True) 1047 self.pull_files(crash_reports, crash_log_path) 1048 return crash_reports 1049 1050 def get_qxdm_logs(self, test_name="", begin_time=None): 1051 """Get qxdm logs.""" 1052 # Sleep 10 seconds for the buffered log to be written in qxdm log file 1053 time.sleep(10) 1054 log_path = getattr(self, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH) 1055 qxdm_logs = self.get_file_names( 1056 log_path, begin_time=begin_time, match_string="*.qmdl") 1057 if qxdm_logs: 1058 qxdm_log_path = os.path.join(self.device_log_path, 1059 "QXDM_%s" % self.serial) 1060 os.makedirs(qxdm_log_path, exist_ok=True) 1061 self.log.info("Pull QXDM Log %s to %s", qxdm_logs, qxdm_log_path) 1062 self.pull_files(qxdm_logs, qxdm_log_path) 1063 self.adb.pull( 1064 "/firmware/image/qdsp6m.qdb %s" % qxdm_log_path, 1065 timeout=PULL_TIMEOUT, 1066 ignore_status=True) 1067 else: 1068 self.log.error("Didn't find QXDM logs in %s." % log_path) 1069 if "Verizon" in self.adb.getprop("gsm.sim.operator.alpha"): 1070 omadm_log_path = os.path.join(self.device_log_path, 1071 "OMADM_%s" % self.serial) 1072 os.makedirs(omadm_log_path, exist_ok=True) 1073 self.log.info("Pull OMADM Log") 1074 self.adb.pull( 1075 "/data/data/com.android.omadm.service/files/dm/log/ %s" % 1076 omadm_log_path, 1077 timeout=PULL_TIMEOUT, 1078 ignore_status=True) 1079 1080 def get_sdm_logs(self, test_name="", begin_time=None): 1081 """Get sdm logs.""" 1082 # Sleep 10 seconds for the buffered log to be written in sdm log file 1083 time.sleep(10) 1084 log_path = getattr(self, "sdm_log_path", DEFAULT_SDM_LOG_PATH) 1085 sdm_logs = self.get_file_names( 1086 log_path, begin_time=begin_time, match_string="*.sdm*") 1087 if sdm_logs: 1088 sdm_log_path = os.path.join(self.device_log_path, 1089 "SDM_%s" % self.serial) 1090 os.makedirs(sdm_log_path, exist_ok=True) 1091 self.log.info("Pull SDM Log %s to %s", sdm_logs, sdm_log_path) 1092 self.pull_files(sdm_logs, sdm_log_path) 1093 else: 1094 self.log.error("Didn't find SDM logs in %s." % log_path) 1095 if "Verizon" in self.adb.getprop("gsm.sim.operator.alpha"): 1096 omadm_log_path = os.path.join(self.device_log_path, 1097 "OMADM_%s" % self.serial) 1098 os.makedirs(omadm_log_path, exist_ok=True) 1099 self.log.info("Pull OMADM Log") 1100 self.adb.pull( 1101 "/data/data/com.android.omadm.service/files/dm/log/ %s" % 1102 omadm_log_path, 1103 timeout=PULL_TIMEOUT, 1104 ignore_status=True) 1105 1106 def start_new_session(self, max_connections=None, server_port=None): 1107 """Start a new session in sl4a. 1108 1109 Also caches the droid in a dict with its uid being the key. 1110 1111 Returns: 1112 An Android object used to communicate with sl4a on the android 1113 device. 1114 1115 Raises: 1116 Sl4aException: Something is wrong with sl4a and it returned an 1117 existing uid to a new session. 1118 """ 1119 session = self._sl4a_manager.create_session( 1120 max_connections=max_connections, server_port=server_port) 1121 1122 self._sl4a_manager.sessions[session.uid] = session 1123 return session.rpc_client 1124 1125 def terminate_all_sessions(self): 1126 """Terminate all sl4a sessions on the AndroidDevice instance. 1127 1128 Terminate all sessions and clear caches. 1129 """ 1130 self._sl4a_manager.terminate_all_sessions() 1131 1132 def run_iperf_client_nb(self, 1133 server_host, 1134 extra_args="", 1135 timeout=IPERF_TIMEOUT, 1136 log_file_path=None): 1137 """Start iperf client on the device asynchronously. 1138 1139 Return status as true if iperf client start successfully. 1140 And data flow information as results. 1141 1142 Args: 1143 server_host: Address of the iperf server. 1144 extra_args: A string representing extra arguments for iperf client, 1145 e.g. "-i 1 -t 30". 1146 log_file_path: The complete file path to log the results. 1147 1148 """ 1149 cmd = "iperf3 -c {} {}".format(server_host, extra_args) 1150 if log_file_path: 1151 cmd += " --logfile {} &".format(log_file_path) 1152 self.adb.shell_nb(cmd) 1153 1154 def run_iperf_client(self, 1155 server_host, 1156 extra_args="", 1157 timeout=IPERF_TIMEOUT): 1158 """Start iperf client on the device. 1159 1160 Return status as true if iperf client start successfully. 1161 And data flow information as results. 1162 1163 Args: 1164 server_host: Address of the iperf server. 1165 extra_args: A string representing extra arguments for iperf client, 1166 e.g. "-i 1 -t 30". 1167 1168 Returns: 1169 status: true if iperf client start successfully. 1170 results: results have data flow information 1171 """ 1172 out = self.adb.shell( 1173 "iperf3 -c {} {}".format(server_host, extra_args), timeout=timeout) 1174 clean_out = out.split('\n') 1175 if "error" in clean_out[0].lower(): 1176 return False, clean_out 1177 return True, clean_out 1178 1179 def run_iperf_server(self, extra_args=""): 1180 """Start iperf server on the device 1181 1182 Return status as true if iperf server started successfully. 1183 1184 Args: 1185 extra_args: A string representing extra arguments for iperf server. 1186 1187 Returns: 1188 status: true if iperf server started successfully. 1189 results: results have output of command 1190 """ 1191 out = self.adb.shell("iperf3 -s {}".format(extra_args)) 1192 clean_out = out.split('\n') 1193 if "error" in clean_out[0].lower(): 1194 return False, clean_out 1195 return True, clean_out 1196 1197 def wait_for_boot_completion(self, timeout=900.0): 1198 """Waits for Android framework to broadcast ACTION_BOOT_COMPLETED. 1199 1200 Args: 1201 timeout: Seconds to wait for the device to boot. Default value is 1202 15 minutes. 1203 """ 1204 timeout_start = time.time() 1205 1206 self.log.debug("ADB waiting for device") 1207 self.adb.wait_for_device(timeout=timeout) 1208 self.log.debug("Waiting for sys.boot_completed") 1209 while time.time() < timeout_start + timeout: 1210 try: 1211 completed = self.adb.getprop("sys.boot_completed") 1212 if completed == '1': 1213 self.log.debug("devie has rebooted") 1214 return 1215 except AdbError: 1216 # adb shell calls may fail during certain period of booting 1217 # process, which is normal. Ignoring these errors. 1218 pass 1219 time.sleep(5) 1220 raise errors.AndroidDeviceError( 1221 'Device %s booting process timed out.' % self.serial, 1222 serial=self.serial) 1223 1224 def reboot(self, stop_at_lock_screen=False, timeout=180): 1225 """Reboots the device. 1226 1227 Terminate all sl4a sessions, reboot the device, wait for device to 1228 complete booting, and restart an sl4a session if restart_sl4a is True. 1229 1230 Args: 1231 stop_at_lock_screen: whether to unlock after reboot. Set to False 1232 if want to bring the device to reboot up to password locking 1233 phase. Sl4a checking need the device unlocked after rebooting. 1234 timeout: time in seconds to wait for the device to complete 1235 rebooting. 1236 """ 1237 if self.is_bootloader: 1238 self.fastboot.reboot() 1239 return 1240 self.stop_services() 1241 self.log.info("Rebooting") 1242 self.adb.reboot() 1243 1244 timeout_start = time.time() 1245 # b/111791239: Newer versions of android sometimes return early after 1246 # `adb reboot` is called. This means subsequent calls may make it to 1247 # the device before the reboot goes through, return false positives for 1248 # getprops such as sys.boot_completed. 1249 while time.time() < timeout_start + timeout: 1250 try: 1251 self.adb.get_state() 1252 time.sleep(.1) 1253 except AdbError: 1254 # get_state will raise an error if the device is not found. We 1255 # want the device to be missing to prove the device has kicked 1256 # off the reboot. 1257 break 1258 self.wait_for_boot_completion( 1259 timeout=(timeout - time.time() + timeout_start)) 1260 self.root_adb() 1261 skip_sl4a = self.skip_sl4a 1262 self.skip_sl4a = self.skip_sl4a or stop_at_lock_screen 1263 self.start_services() 1264 self.skip_sl4a = skip_sl4a 1265 1266 def restart_runtime(self): 1267 """Restarts android runtime. 1268 1269 Terminate all sl4a sessions, restarts runtime, wait for framework 1270 complete restart, and restart an sl4a session if restart_sl4a is True. 1271 """ 1272 self.stop_services() 1273 self.log.info("Restarting android runtime") 1274 self.adb.shell("stop") 1275 # Reset the boot completed flag before we restart the framework 1276 # to correctly detect when the framework has fully come up. 1277 self.adb.shell("setprop sys.boot_completed 0") 1278 self.adb.shell("start") 1279 self.wait_for_boot_completion() 1280 self.root_adb() 1281 1282 self.start_services() 1283 1284 def get_ipv4_address(self, interface='wlan0', timeout=5): 1285 for timer in range(0, timeout): 1286 try: 1287 ip_string = self.adb.shell('ifconfig %s|grep inet' % interface) 1288 break 1289 except adb.AdbError as e: 1290 if timer + 1 == timeout: 1291 self.log.warning( 1292 'Unable to find IP address for %s.' % interface) 1293 return None 1294 else: 1295 time.sleep(1) 1296 result = re.search('addr:(.*) Bcast', ip_string) 1297 if result != None: 1298 ip_address = result.group(1) 1299 try: 1300 socket.inet_aton(ip_address) 1301 return ip_address 1302 except socket.error: 1303 return None 1304 else: 1305 return None 1306 1307 def get_ipv4_gateway(self, timeout=5): 1308 for timer in range(0, timeout): 1309 try: 1310 gateway_string = self.adb.shell( 1311 'dumpsys wifi | grep mDhcpResults') 1312 break 1313 except adb.AdbError as e: 1314 if timer + 1 == timeout: 1315 self.log.warning('Unable to find gateway') 1316 return None 1317 else: 1318 time.sleep(1) 1319 result = re.search('Gateway (.*) DNS servers', gateway_string) 1320 if result != None: 1321 ipv4_gateway = result.group(1) 1322 try: 1323 socket.inet_aton(ipv4_gateway) 1324 return ipv4_gateway 1325 except socket.error: 1326 return None 1327 else: 1328 return None 1329 1330 @record_api_usage 1331 def send_keycode(self, keycode): 1332 self.adb.shell("input keyevent KEYCODE_%s" % keycode) 1333 1334 @record_api_usage 1335 def get_my_current_focus_window(self): 1336 """Get the current focus window on screen""" 1337 output = self.adb.shell( 1338 'dumpsys window displays | grep -E mCurrentFocus', 1339 ignore_status=True) 1340 if not output or "not found" in output or "Can't find" in output or ( 1341 "mCurrentFocus=null" in output): 1342 result = '' 1343 else: 1344 result = output.split(' ')[-1].strip("}") 1345 self.log.debug("Current focus window is %s", result) 1346 return result 1347 1348 @record_api_usage 1349 def get_my_current_focus_app(self): 1350 """Get the current focus application""" 1351 dumpsys_cmd = [ 1352 'dumpsys window | grep -E mFocusedApp', 1353 'dumpsys window displays | grep -E mFocusedApp' 1354 ] 1355 for cmd in dumpsys_cmd: 1356 output = self.adb.shell(cmd, ignore_status=True) 1357 if not output or "not found" in output or "Can't find" in output or ( 1358 "mFocusedApp=null" in output): 1359 result = '' 1360 else: 1361 result = output.split(' ')[-2] 1362 break 1363 self.log.debug("Current focus app is %s", result) 1364 return result 1365 1366 @record_api_usage 1367 def is_window_ready(self, window_name=None): 1368 current_window = self.get_my_current_focus_window() 1369 if window_name: 1370 return window_name in current_window 1371 return current_window and ENCRYPTION_WINDOW not in current_window 1372 1373 @record_api_usage 1374 def wait_for_window_ready(self, 1375 window_name=None, 1376 check_interval=5, 1377 check_duration=60): 1378 elapsed_time = 0 1379 while elapsed_time < check_duration: 1380 if self.is_window_ready(window_name=window_name): 1381 return True 1382 time.sleep(check_interval) 1383 elapsed_time += check_interval 1384 self.log.info("Current focus window is %s", 1385 self.get_my_current_focus_window()) 1386 return False 1387 1388 @record_api_usage 1389 def is_user_setup_complete(self): 1390 return "1" in self.adb.shell("settings get secure user_setup_complete") 1391 1392 @record_api_usage 1393 def is_screen_awake(self): 1394 """Check if device screen is in sleep mode""" 1395 return "Awake" in self.adb.shell("dumpsys power | grep mWakefulness=") 1396 1397 @record_api_usage 1398 def is_screen_emergency_dialer(self): 1399 """Check if device screen is in emergency dialer mode""" 1400 return "EmergencyDialer" in self.get_my_current_focus_window() 1401 1402 @record_api_usage 1403 def is_screen_in_call_activity(self): 1404 """Check if device screen is in in-call activity notification""" 1405 return "InCallActivity" in self.get_my_current_focus_window() 1406 1407 @record_api_usage 1408 def is_setupwizard_on(self): 1409 """Check if device screen is in emergency dialer mode""" 1410 return "setupwizard" in self.get_my_current_focus_app() 1411 1412 @record_api_usage 1413 def is_screen_lock_enabled(self): 1414 """Check if screen lock is enabled""" 1415 cmd = ("sqlite3 /data/system/locksettings.db .dump" 1416 " | grep lockscreen.password_type | grep -v alternate") 1417 out = self.adb.shell(cmd, ignore_status=True) 1418 if "unable to open" in out: 1419 self.root_adb() 1420 out = self.adb.shell(cmd, ignore_status=True) 1421 if ",0,'0'" not in out and out != "": 1422 self.log.info("Screen lock is enabled") 1423 return True 1424 return False 1425 1426 @record_api_usage 1427 def is_waiting_for_unlock_pin(self): 1428 """Check if device is waiting for unlock pin to boot up""" 1429 current_window = self.get_my_current_focus_window() 1430 current_app = self.get_my_current_focus_app() 1431 if ENCRYPTION_WINDOW in current_window: 1432 self.log.info("Device is in CrpytKeeper window") 1433 return True 1434 if "StatusBar" in current_window and ( 1435 (not current_app) or "FallbackHome" in current_app): 1436 self.log.info("Device is locked") 1437 return True 1438 return False 1439 1440 @record_api_usage 1441 def ensure_screen_on(self): 1442 """Ensure device screen is powered on""" 1443 if self.is_screen_lock_enabled(): 1444 for _ in range(2): 1445 self.unlock_screen() 1446 time.sleep(1) 1447 if self.is_waiting_for_unlock_pin(): 1448 self.unlock_screen(password=DEFAULT_DEVICE_PASSWORD) 1449 time.sleep(1) 1450 if not self.is_waiting_for_unlock_pin( 1451 ) and self.wait_for_window_ready(): 1452 return True 1453 return False 1454 else: 1455 self.wakeup_screen() 1456 return True 1457 1458 @record_api_usage 1459 def wakeup_screen(self): 1460 if not self.is_screen_awake(): 1461 self.log.info("Screen is not awake, wake it up") 1462 self.send_keycode("WAKEUP") 1463 1464 @record_api_usage 1465 def go_to_sleep(self): 1466 if self.is_screen_awake(): 1467 self.send_keycode("SLEEP") 1468 1469 @record_api_usage 1470 def send_keycode_number_pad(self, number): 1471 self.send_keycode("NUMPAD_%s" % number) 1472 1473 @record_api_usage 1474 def unlock_screen(self, password=None): 1475 self.log.info("Unlocking with %s", password or "swipe up") 1476 # Bring device to SLEEP so that unlock process can start fresh 1477 self.send_keycode("SLEEP") 1478 time.sleep(1) 1479 self.send_keycode("WAKEUP") 1480 if ENCRYPTION_WINDOW not in self.get_my_current_focus_app(): 1481 self.send_keycode("MENU") 1482 if password: 1483 self.send_keycode("DEL") 1484 for number in password: 1485 self.send_keycode_number_pad(number) 1486 self.send_keycode("ENTER") 1487 self.send_keycode("BACK") 1488 1489 @record_api_usage 1490 def exit_setup_wizard(self): 1491 # Handling Android TV's setupwizard is ignored for now. 1492 if 'feature:com.google.android.tv.installed' in self.adb.shell( 1493 'pm list features'): 1494 return 1495 if not self.is_user_setup_complete() or self.is_setupwizard_on(): 1496 # b/116709539 need this to prevent reboot after skip setup wizard 1497 self.adb.shell( 1498 "am start -a com.android.setupwizard.EXIT", ignore_status=True) 1499 self.adb.shell( 1500 "pm disable %s" % self.get_setupwizard_package_name()) 1501 # Wait up to 5 seconds for user_setup_complete to be updated 1502 end_time = time.time() + 5 1503 while time.time() < end_time: 1504 if self.is_user_setup_complete() or not self.is_setupwizard_on(): 1505 return 1506 1507 # If fail to exit setup wizard, set local.prop and reboot 1508 if not self.is_user_setup_complete() and self.is_setupwizard_on(): 1509 self.adb.shell("echo ro.test_harness=1 > /data/local.prop") 1510 self.adb.shell("chmod 644 /data/local.prop") 1511 self.reboot(stop_at_lock_screen=True) 1512 1513 @record_api_usage 1514 def get_setupwizard_package_name(self): 1515 """Finds setupwizard package/.activity 1516 1517 Bypass setupwizard or setupwraith depending on device. 1518 1519 Returns: 1520 packageName/.ActivityName 1521 """ 1522 packages_to_skip = "'setupwizard|setupwraith'" 1523 android_package_name = "com.google.android" 1524 package = self.adb.shell( 1525 "pm list packages -f | grep -E {} | grep {}".format( 1526 packages_to_skip, android_package_name)) 1527 wizard_package = package.split('=')[1] 1528 activity = package.split('=')[0].split('/')[-2] 1529 self.log.info("%s/.%sActivity" % (wizard_package, activity)) 1530 return "%s/.%sActivity" % (wizard_package, activity) 1531 1532 @record_api_usage 1533 def push_system_file(self, src_file_path, dst_file_path, push_timeout=300): 1534 """Pushes a file onto the read-only file system. 1535 1536 For speed, the device is left in root mode after this call, and leaves 1537 verity disabled. To re-enable verity, call ensure_verity_enabled(). 1538 1539 Args: 1540 src_file_path: The path to the system app to install. 1541 dst_file_path: The destination of the file. 1542 push_timeout: How long to wait for the push to finish. 1543 Returns: 1544 Whether or not the install was successful. 1545 """ 1546 self.adb.ensure_root() 1547 try: 1548 self.ensure_verity_disabled() 1549 self.adb.remount() 1550 out = self.adb.push( 1551 '%s %s' % (src_file_path, dst_file_path), timeout=push_timeout) 1552 if 'error' in out: 1553 self.log.error('Unable to push system file %s to %s due to %s', 1554 src_file_path, dst_file_path, out) 1555 return False 1556 return True 1557 except Exception as e: 1558 self.log.error('Unable to push system file %s to %s due to %s', 1559 src_file_path, dst_file_path, e) 1560 return False 1561 1562 @record_api_usage 1563 def ensure_verity_enabled(self): 1564 """Ensures that verity is enabled. 1565 1566 If verity is not enabled, this call will reboot the phone. Note that 1567 this only works on debuggable builds. 1568 """ 1569 user = self.adb.get_user_id() 1570 # The below properties will only exist if verity has been enabled. 1571 system_verity = self.adb.getprop('partition.system.verified') 1572 vendor_verity = self.adb.getprop('partition.vendor.verified') 1573 if not system_verity or not vendor_verity: 1574 self.adb.ensure_root() 1575 self.adb.enable_verity() 1576 self.reboot() 1577 self.adb.ensure_user(user) 1578 1579 @record_api_usage 1580 def ensure_verity_disabled(self): 1581 """Ensures that verity is disabled. 1582 1583 If verity is enabled, this call will reboot the phone. 1584 """ 1585 user = self.adb.get_user_id() 1586 # The below properties will only exist if verity has been enabled. 1587 system_verity = self.adb.getprop('partition.system.verified') 1588 vendor_verity = self.adb.getprop('partition.vendor.verified') 1589 if system_verity or vendor_verity: 1590 self.adb.ensure_root() 1591 self.adb.disable_verity() 1592 self.reboot() 1593 self.adb.ensure_user(user) 1594 1595 1596class AndroidDeviceLoggerAdapter(logging.LoggerAdapter): 1597 def process(self, msg, kwargs): 1598 msg = "[AndroidDevice|%s] %s" % (self.extra["serial"], msg) 1599 return (msg, kwargs) 1600