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