Index: mojo/tools/mopy/android.py |
diff --git a/mojo/tools/mopy/android.py b/mojo/tools/mopy/android.py |
index 50d7df4dacc49b0df72fabf986e2f2bde128646c..e1c747df374db5bfdacc2e2c0d916f678afbcfdf 100644 |
--- a/mojo/tools/mopy/android.py |
+++ b/mojo/tools/mopy/android.py |
@@ -23,6 +23,7 @@ from pylib import constants |
from pylib.base import base_test_runner |
from pylib.device import device_errors |
from pylib.device import device_utils |
+from pylib.utils import base_error |
from pylib.utils import apk_helper |
@@ -54,6 +55,7 @@ class AndroidShell(object): |
self.adb_path = constants.GetAdbPath() |
self.paths = Paths(config) |
self.device = None |
+ self.shell_args = [] |
self.target_package = apk_helper.GetPackageName(self.paths.apk_path) |
# This is used by decive_utils.Install to check if the apk needs updating. |
constants.SetOutputDirectory(self.paths.build_dir) |
@@ -131,45 +133,42 @@ class AndroidShell(object): |
result.append(self._StartHttpServerForOriginMapping(value)) |
return [MAPPING_PREFIX + ','.join(result)] |
- def PrepareShellRun(self, origin=None, device=None, gdb=False): |
+ def InitShell(self, origin='localhost', device=None): |
""" |
- Prepares for StartShell: runs adb as root and installs the apk as needed. |
- If the origin specified is 'localhost', a local http server will be set up |
- to serve files from the build directory along with port forwarding. |
- |device| is the device to run on, if multiple devices are connected. |
- Returns arguments that should be appended to shell argument list. |
+ Runs adb as root, starts an origin server, and installs the apk as needed. |
+ |origin| is the origin for mojo: URLs; if its value is 'localhost', a local |
+ http server will be set up to serve files from the build directory. |
+ |device| is the target device to run on, if multiple devices are connected. |
+ Returns 0 on success or a non-zero exit code on a terminal failure. |
""" |
- devices = device_utils.DeviceUtils.HealthyDevices() |
- if device: |
- self.device = next((d for d in devices if d == device), None) |
- if not self.device: |
- raise device_errors.DeviceUnreachableError(device) |
- elif devices: |
- self.device = devices[0] |
- else: |
- raise device_errors.NoDevicesError() |
- |
- logging.getLogger().debug("Using device: %s", self.device) |
- self.device.EnableRoot() |
- |
- # TODO(msw): Install fails often, retry as needed; http://crbug.com/493900 |
try: |
+ devices = device_utils.DeviceUtils.HealthyDevices() |
+ if device: |
+ self.device = next((d for d in devices if d == device), None) |
+ if not self.device: |
+ raise device_errors.DeviceUnreachableError(device) |
+ elif devices: |
+ self.device = devices[0] |
+ else: |
+ raise device_errors.NoDevicesError() |
+ |
+ logging.getLogger().debug("Using device: %s", self.device) |
+ # Clean the logs on the device to avoid displaying prior activity. |
+ subprocess.check_call(self._CreateADBCommand(['logcat', '-c'])) |
+ self.device.EnableRoot() |
self.device.Install(self.paths.apk_path) |
- except device_errors.CommandFailedError as e: |
- logging.getLogger().error("APK install failed:\n%s", str(e)) |
- self.device.Install(self.paths.apk_path) |
+ except base_error.BaseError as e: |
+ # Report "device not found" as infra failures. See http://crbug.com/493900 |
+ print "Exception in AndroidShell.InitShell:\n%s" % str(e) |
+ if e.is_infra_error or "error: device not found" in str(e): |
+ return constants.INFRA_EXIT_CODE |
+ return constants.ERROR_EXIT_CODE |
- extra_args = [] |
if origin is 'localhost': |
origin = self._StartHttpServerForDirectory(self.paths.build_dir) |
if origin: |
- extra_args.append("--origin=" + origin) |
- |
- if gdb: |
- # Remote debugging needs a port forwarded. |
- self.device.adb.Forward('tcp:5039', 'tcp:5039') |
- |
- return extra_args |
+ self.shell_args.append("--origin=" + origin) |
+ return 0 |
def _GetProcessId(self, process): |
"""Returns the process id of the process on the remote device.""" |
@@ -229,11 +228,15 @@ class AndroidShell(object): |
local_gdb_process.wait() |
signal.signal(signal.SIGINT, signal.SIG_DFL) |
- def StartShell(self, arguments, stdout, on_application_stop, gdb=False): |
+ def StartShell(self, arguments, stdout, on_fifo_closed, gdb=False): |
""" |
- Starts the shell with the given arguments, directing output to |stdout|. |
- The |arguments| list must contain the "--origin=" arg from PrepareShellRun. |
+ Starts the shell with the given |arguments|, directing output to |stdout|. |
+ |on_fifo_closed| will be run if the FIFO can't be found or when it's closed. |
+ |gdb| is a flag that attaches gdb to the device's remote process on startup. |
""" |
+ assert self.device |
+ arguments += self.shell_args |
+ |
cmd = self._CreateADBCommand([ |
'shell', |
'am', |
@@ -245,7 +248,9 @@ class AndroidShell(object): |
logcat_process = None |
if gdb: |
- arguments += ['--wait-for-debugger'] |
+ arguments.append('--wait-for-debugger') |
+ # Remote debugging needs a port forwarded. |
+ self.device.adb.Forward('tcp:5039', 'tcp:5039') |
logcat_process = self.ShowLogs(stdout=subprocess.PIPE) |
fifo_path = "/data/data/%s/stdout.fifo" % self.target_package |
@@ -253,15 +258,14 @@ class AndroidShell(object): |
['shell', 'rm', '-f', fifo_path])) |
arguments.append('--fifo-path=%s' % fifo_path) |
max_attempts = 200 if '--wait-for-debugger' in arguments else 5 |
- self._ReadFifo(fifo_path, stdout, on_application_stop, max_attempts) |
+ self._ReadFifo(fifo_path, stdout, on_fifo_closed, max_attempts) |
# Extract map-origin args and add the extras array with commas escaped. |
parameters = [a for a in arguments if not a.startswith(MAPPING_PREFIX)] |
map_parameters = [a for a in arguments if a.startswith(MAPPING_PREFIX)] |
parameters += self._StartHttpServerForOriginMappings(map_parameters) |
parameters = [p.replace(',', '\,') for p in parameters] |
- if parameters: |
- cmd += ['--esa', 'org.chromium.mojo.shell.extras', ','.join(parameters)] |
+ cmd += ['--esa', 'org.chromium.mojo.shell.extras', ','.join(parameters)] |
atexit.register(self.StopShell) |
with open(os.devnull, 'w') as devnull: |
@@ -274,10 +278,6 @@ class AndroidShell(object): |
"""Stops the mojo shell.""" |
self.device.ForceStop(self.target_package) |
- def CleanLogs(self): |
- """Cleans the logs on the device.""" |
- subprocess.check_call(self._CreateADBCommand(['logcat', '-c'])) |
- |
def ShowLogs(self, stdout=sys.stdout): |
"""Displays the mojo shell logs and returns the process reading the logs.""" |
logcat = subprocess.Popen(self._CreateADBCommand([ |