Index: build/android/pylib/android_commands.py |
diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py |
index da87f39f4dae86130a6507681404fa322fc808f0..fbf144d548a727742f23cebe39377f8544eced4d 100644 |
--- a/build/android/pylib/android_commands.py |
+++ b/build/android/pylib/android_commands.py |
@@ -9,11 +9,8 @@ Assumes adb binary is currently on system path. |
import collections |
import datetime |
-import io_stats_parser |
import logging |
-import optparse |
import os |
-import pexpect |
import re |
import shlex |
import subprocess |
@@ -21,10 +18,12 @@ import sys |
import tempfile |
import time |
+import pexpect |
+import io_stats_parser |
# adb_interface.py is under ../../../third_party/android_testrunner/ |
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', |
- '..', '..', 'third_party', 'android_testrunner')) |
+ '..', '..', 'third_party', 'android_testrunner')) |
import adb_interface |
import cmd_helper |
import errors # is under ../../../third_party/android_testrunner/errors.py |
@@ -51,7 +50,7 @@ JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' |
BOOT_COMPLETE_RE = re.compile( |
'android.intent.action.MEDIA_MOUNTED path: /\w+/sdcard\d?' |
- + '|' + 'PowerManagerService(\(\s+\d+\))?: bootCompleted') |
+ '|PowerManagerService(\(\s+\d+\))?: bootCompleted') |
MEMORY_INFO_RE = re.compile('^(?P<key>\w+):\s+(?P<usage_kb>\d+) kB$') |
NVIDIA_MEMORY_INFO_RE = re.compile('^\s*(?P<user>\S+)\s*(?P<name>\S+)\s*' |
@@ -107,7 +106,7 @@ def GetAttachedDevices(): |
""" |
re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE) |
devices = re_device.findall(cmd_helper.GetCmdOutput(['adb', 'devices'])) |
- preferred_device = os.environ.get("ANDROID_SERIAL") |
+ preferred_device = os.environ.get('ANDROID_SERIAL') |
if preferred_device in devices: |
devices.remove(preferred_device) |
devices.insert(0, preferred_device) |
@@ -196,7 +195,7 @@ def _GetFilesFromRecursiveLsOutput(path, ls_output, re_file, utc_offset=None): |
utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), |
minutes=int(utc_offset[3:5])) |
if utc_offset[0:1] == '-': |
- utc_delta = -utc_delta; |
+ utc_delta = -utc_delta |
lastmod -= utc_delta |
files[filename] = (int(file_match.group('size')), lastmod) |
return files |
@@ -241,7 +240,7 @@ class AndroidCommands(object): |
return self._root_enabled |
def GetDeviceYear(self): |
- """Returns the year information of the date on device""" |
+ """Returns the year information of the date on device.""" |
return self.RunShellCommand('date +%Y')[0] |
def WaitForDevicePm(self): |
@@ -261,7 +260,7 @@ class AndroidCommands(object): |
return # Success |
except errors.WaitForResponseTimedOutError as e: |
last_err = e |
- logging.warning('Restarting and retrying after timeout: %s' % str(e)) |
+ logging.warning('Restarting and retrying after timeout: %s', e) |
retries -= 1 |
self.RestartShell() |
raise last_err # Only reached after max retries, re-raise the last error. |
@@ -286,12 +285,14 @@ class AndroidCommands(object): |
if os.environ.get('USING_HIVE'): |
logging.warning('Ignoring reboot request as we are on hive') |
return |
- if full_reboot: |
+ if full_reboot or not self.IsRootEnabled(): |
self._adb.SendCommand('reboot') |
+ timeout = 300 |
else: |
self.RestartShell() |
+ timeout = 120 |
self.WaitForDevicePm() |
- self.StartMonitoringLogcat(timeout=120) |
+ self.StartMonitoringLogcat(timeout=timeout) |
self.WaitForLogMatch(BOOT_COMPLETE_RE, None) |
def Uninstall(self, package): |
@@ -308,24 +309,59 @@ class AndroidCommands(object): |
logging.info('>>> $' + uninstall_command) |
return self._adb.SendCommand(uninstall_command, timeout_time=60) |
- def Install(self, package_file_path): |
+ def Install(self, package_file_path, reinstall=False): |
"""Installs the specified package to the device. |
Args: |
package_file_path: Path to .apk file to install. |
+ reinstall: Whether to reinstall over existing package |
Returns: |
A status string returned by adb install |
""" |
assert os.path.isfile(package_file_path) |
- install_command = 'install %s' % package_file_path |
+ if reinstall: |
+ install_cmd = 'install -r %s' |
+ else: |
+ install_cmd = 'install %s' |
+ |
+ return self._adb.SendCommand(install_cmd % package_file_path, |
+ timeout_time=2*60, retry_count=0) |
+ |
+ def ManagedInstall(self, apk_path, keep_data, package_name=None, |
+ reboots_on_failure=2): |
+ """Installs specified package and reboots device on timeouts. |
+ |
+ Args: |
+ apk_path: Path to .apk file to install. |
+ keep_data: Whether to keep data if package already exists |
+ package_name: Package name (only needed if keep_data=False) |
+ reboots_on_failure: number of time to reboot if package manager is frozen. |
+ |
+ Returns: |
+ A status string returned by adb install |
+ """ |
+ reboots_left = reboots_on_failure |
+ while True: |
+ try: |
+ if not keep_data: |
+ self.Uninstall(package_name) |
+ install_status = self.Install(apk_path, keep_data) |
+ if 'Success' in install_status: |
+ return install_status |
+ except errors.WaitForResponseTimedOutError: |
+ logging.info('Timout on installing %s' % apk_path) |
- logging.info('>>> $' + install_command) |
- return self._adb.SendCommand(install_command, timeout_time=2*60) |
+ if reboots_left <= 0: |
+ raise Exception('Install failure') |
+ |
+ # Force a hard reboot on last attempt |
+ self.Reboot(full_reboot=(reboots_left == 1)) |
+ reboots_left -= 1 |
def MakeSystemFolderWritable(self): |
- """Remounts the /system folder rw. """ |
+ """Remounts the /system folder rw.""" |
out = self._adb.SendCommand('remount') |
if out.strip() != 'remount succeeded': |
raise errors.MsgException('Remount failed: %s' % out) |
@@ -388,7 +424,7 @@ class AndroidCommands(object): |
wait_period = 5 |
while not sdcard_ready and attempts * wait_period < timeout_time: |
output = self.RunShellCommand('ls /sdcard/') |
- if len(output) > 0: |
+ if output: |
sdcard_ready = True |
else: |
time.sleep(wait_period) |
@@ -417,8 +453,10 @@ class AndroidCommands(object): |
""" |
logging.info('>>> $' + command) |
if "'" in command: logging.warning(command + " contains ' quotes") |
- result = self._adb.SendShellCommand("'%s'" % command, |
- timeout_time).splitlines() |
+ result = self._adb.SendShellCommand( |
+ "'%s'" % command, timeout_time).splitlines() |
+ if ['error: device not found'] == result: |
+ raise errors.DeviceUnresponsiveError('device not found') |
if log_result: |
logging.info('\n>>> '.join(result)) |
return result |
@@ -480,7 +518,6 @@ class AndroidCommands(object): |
cmd += ' --start-profiler ' + trace_file_name |
self.RunShellCommand(cmd) |
- |
def CloseApplication(self, package): |
"""Attempt to close down the application, using increasing violence. |
@@ -529,7 +566,7 @@ class AndroidCommands(object): |
else: |
is_equal = local_contents == device_contents |
if is_equal: |
- logging.info('%s is up-to-date. Skipping file push.' % device_path) |
+ logging.info('%s is up-to-date. Skipping file push.', device_path) |
return |
# They don't match, so remove everything first and then create it. |
@@ -645,7 +682,7 @@ class AndroidCommands(object): |
self.RunShellCommand('echo 3 > ' + DROP_CACHES) |
def StartMonitoringLogcat(self, clear=True, timeout=10, logfile=None, |
- filters=[]): |
+ filters=None): |
"""Starts monitoring the output of logcat, for use with WaitForLogMatch. |
Args: |
@@ -756,7 +793,7 @@ class AndroidCommands(object): |
# Cannot evaluate directly as 0 is a possible value. |
# Better to read the self.logcat_process.stdout before killing it, |
# Otherwise the communicate may return incomplete output due to pipe break. |
- if self.logcat_process.poll() == None: |
+ if self.logcat_process.poll() is None: |
self.logcat_process.kill() |
(output, _) = self.logcat_process.communicate() |
self.logcat_process = None |
@@ -895,7 +932,7 @@ class AndroidCommands(object): |
"""Returns the memory usage for all processes whose name contains |pacakge|. |
Args: |
- name: A string holding process name to lookup pid list for. |
+ package: A string holding process name to lookup pid list for. |
Returns: |
A tuple containg: |
@@ -919,8 +956,7 @@ class AndroidCommands(object): |
return usage_dict, smaps |
def ProcessesUsingDevicePort(self, device_port): |
- """Lists the processes using the specified device port on loopback |
- interface. |
+ """Lists processes using the specified device port on loopback interface. |
Args: |
device_port: Port on device we want to check. |
@@ -929,7 +965,7 @@ class AndroidCommands(object): |
A list of (pid, process_name) tuples using the specified port. |
""" |
tcp_results = self.RunShellCommand('cat /proc/net/tcp', log_result=False) |
- tcp_address = "0100007F:%04X" % device_port |
+ tcp_address = '0100007F:%04X' % device_port |
pids = [] |
for single_connect in tcp_results: |
connect_results = single_connect.split() |
@@ -948,7 +984,7 @@ class AndroidCommands(object): |
# Column 1 is the pid |
# Column 8 is the Inode in use |
if process_results[8] == socket_name: |
- pids.append( (int(process_results[1]), process_results[0]) ) |
+ pids.append((int(process_results[1]), process_results[0])) |
break |
logging.info('PidsUsingDevicePort: %s', pids) |
return pids |