Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1509)

Unified Diff: mojo/devtools/common/pylib/android_shell.py

Issue 1128153002: Rename the devtools library: pylib -> devtoolslib. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Address offline comments/ devtools_lib -> devtoolslib. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mojo/devtools/common/pylib/__init__.py ('k') | mojo/devtools/common/pylib/apptest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojo/devtools/common/pylib/android_shell.py
diff --git a/mojo/devtools/common/pylib/android_shell.py b/mojo/devtools/common/pylib/android_shell.py
deleted file mode 100644
index fe44283c2c3428b80296d439bcb619c9a0833828..0000000000000000000000000000000000000000
--- a/mojo/devtools/common/pylib/android_shell.py
+++ /dev/null
@@ -1,333 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import atexit
-import itertools
-import json
-import logging
-import os
-import os.path
-import random
-import subprocess
-import sys
-import threading
-import time
-import urlparse
-
-from pylib.http_server import StartHttpServer
-from pylib.shell import Shell
-
-
-# Tags used by the mojo shell application logs.
-LOGCAT_TAGS = [
- 'AndroidHandler',
- 'MojoFileHelper',
- 'MojoMain',
- 'MojoShellActivity',
- 'MojoShellApplication',
- 'chromium',
-]
-
-MOJO_SHELL_PACKAGE_NAME = 'org.chromium.mojo.shell'
-
-MAPPING_PREFIX = '--map-origin='
-
-DEFAULT_BASE_PORT = 31337
-
-_logger = logging.getLogger()
-
-
-def _IsMapOrigin(arg):
- """Returns whether arg is a --map-origin argument."""
- return arg.startswith(MAPPING_PREFIX)
-
-
-def _Split(l, pred):
- positive = []
- negative = []
- for v in l:
- if pred(v):
- positive.append(v)
- else:
- negative.append(v)
- return (positive, negative)
-
-
-def _ExitIfNeeded(process):
- """Exits |process| if it is still alive."""
- if process.poll() is None:
- process.kill()
-
-
-class AndroidShell(Shell):
- """Wrapper around Mojo shell running on an Android device.
-
- Args:
- adb_path: Path to adb, optional if adb is in PATH.
- target_device: Device to run on, if multiple devices are connected.
- """
-
- def __init__(self, adb_path="adb", target_device=None, verbose_pipe=None):
- self.adb_path = adb_path
- self.target_device = target_device
- self.stop_shell_registered = False
- self.adb_running_as_root = False
- self.verbose_pipe = verbose_pipe if verbose_pipe else open(os.devnull, 'w')
-
- def _CreateADBCommand(self, args):
- adb_command = [self.adb_path]
- if self.target_device:
- adb_command.extend(['-s', self.target_device])
- adb_command.extend(args)
- return adb_command
-
- def _ReadFifo(self, fifo_path, pipe, on_fifo_closed, max_attempts=5):
- """Reads |fifo_path| on the device and write the contents to |pipe|. Calls
- |on_fifo_closed| when the fifo is closed. This method will try to find the
- path up to |max_attempts|, waiting 1 second between each attempt. If it
- cannot find |fifo_path|, a exception will be raised.
- """
- fifo_command = self._CreateADBCommand(
- ['shell', 'test -e "%s"; echo $?' % fifo_path])
-
- def Run():
- def _WaitForFifo():
- for _ in xrange(max_attempts):
- if subprocess.check_output(fifo_command)[0] == '0':
- return
- time.sleep(1)
- if on_fifo_closed:
- on_fifo_closed()
- raise Exception("Unable to find fifo.")
- _WaitForFifo()
- stdout_cat = subprocess.Popen(self._CreateADBCommand([
- 'shell',
- 'cat',
- fifo_path]),
- stdout=pipe)
- atexit.register(_ExitIfNeeded, stdout_cat)
- stdout_cat.wait()
- if on_fifo_closed:
- on_fifo_closed()
-
- thread = threading.Thread(target=Run, name="StdoutRedirector")
- thread.start()
-
- def _MapPort(self, device_port, host_port):
- """Maps the device port to the host port. If |device_port| is 0, a random
- available port is chosen. Returns the device port.
- """
- def _FindAvailablePortOnDevice():
- opened = subprocess.check_output(
- self._CreateADBCommand(['shell', 'netstat']))
- opened = [int(x.strip().split()[3].split(':')[1])
- for x in opened if x.startswith(' tcp')]
- while True:
- port = random.randint(4096, 16384)
- if port not in opened:
- return port
- if device_port == 0:
- device_port = _FindAvailablePortOnDevice()
- subprocess.check_call(self._CreateADBCommand([
- "reverse",
- "tcp:%d" % device_port,
- "tcp:%d" % host_port]))
-
- unmap_command = self._CreateADBCommand(["reverse", "--remove",
- "tcp:%d" % device_port])
-
- def _UnmapPort():
- subprocess.Popen(unmap_command)
- atexit.register(_UnmapPort)
- return device_port
-
- def _StartHttpServerForDirectory(self, path, port=0):
- """Starts an http server serving files from |path|. Returns the local
- url.
- """
- assert path
- print 'starting http for', path
- server_address = StartHttpServer(path)
-
- print 'local port=%d' % server_address[1]
- return 'http://127.0.0.1:%d/' % self._MapPort(port, server_address[1])
-
- def _StartHttpServerForOriginMapping(self, mapping, port):
- """If |mapping| points at a local file starts an http server to serve files
- from the directory and returns the new mapping.
-
- This is intended to be called for every --map-origin value.
- """
- parts = mapping.split('=')
- if len(parts) != 2:
- return mapping
- dest = parts[1]
- # If the destination is a url, don't map it.
- if urlparse.urlparse(dest)[0]:
- return mapping
- # Assume the destination is a local file. Start a local server that
- # redirects to it.
- localUrl = self._StartHttpServerForDirectory(dest, port)
- print 'started server at %s for %s' % (dest, localUrl)
- return parts[0] + '=' + localUrl
-
- def _StartHttpServerForOriginMappings(self, map_parameters, fixed_port):
- """Calls _StartHttpServerForOriginMapping for every --map-origin
- argument.
- """
- if not map_parameters:
- return []
-
- original_values = list(itertools.chain(
- *map(lambda x: x[len(MAPPING_PREFIX):].split(','), map_parameters)))
- sorted(original_values)
- result = []
- for i, value in enumerate(original_values):
- result.append(self._StartHttpServerForOriginMapping(
- value, DEFAULT_BASE_PORT + 1 + i if fixed_port else 0))
- return [MAPPING_PREFIX + ','.join(result)]
-
- def _RunAdbAsRoot(self):
- if self.adb_running_as_root:
- return
-
- if 'cannot run as root' in subprocess.check_output(
- self._CreateADBCommand(['root'])):
- raise Exception("Unable to run adb as root.")
-
- # Wait for adbd to restart.
- subprocess.check_call(
- self._CreateADBCommand(['wait-for-device']),
- stdout=self.verbose_pipe)
- self.adb_running_as_root = True
-
- def InstallApk(self, shell_apk_path):
- """Installs the apk on the device.
-
- Args:
- shell_apk_path: Path to the shell Android binary.
- """
- subprocess.check_call(
- self._CreateADBCommand(['install', '-r', shell_apk_path, '-i',
- MOJO_SHELL_PACKAGE_NAME]),
- stdout=self.verbose_pipe)
-
- def SetUpLocalOrigin(self, local_dir, fixed_port=True):
- """Sets up a local http server to serve files in |local_dir| along with
- device port forwarding. Returns the origin flag to be set when running the
- shell.
- """
-
- origin_url = self._StartHttpServerForDirectory(
- local_dir, DEFAULT_BASE_PORT if fixed_port else 0)
- return "--origin=" + origin_url
-
- def StartShell(self,
- arguments,
- stdout=None,
- on_application_stop=None,
- fixed_port=True):
- """Starts the mojo shell, passing it the given arguments.
-
- The |arguments| list must contain the "--origin=" arg. SetUpLocalOrigin()
- can be used to set up a local directory on the host machine as origin.
- If |stdout| is not None, it should be a valid argument for subprocess.Popen.
- """
- if not self.stop_shell_registered:
- atexit.register(self.StopShell)
- self.stop_shell_registered = True
-
- STDOUT_PIPE = "/data/data/%s/stdout.fifo" % MOJO_SHELL_PACKAGE_NAME
-
- cmd = self._CreateADBCommand([
- 'shell',
- 'am',
- 'start',
- '-S',
- '-a', 'android.intent.action.VIEW',
- '-n', '%s/.MojoShellActivity' % MOJO_SHELL_PACKAGE_NAME])
-
- parameters = []
- if stdout or on_application_stop:
- # We need to run as root to access the fifo file we use for stdout
- # redirection.
- self._RunAdbAsRoot()
-
- # Remove any leftover fifo file after the previous run.
- subprocess.check_call(self._CreateADBCommand(
- ['shell', 'rm', '-f', STDOUT_PIPE]))
-
- parameters.append('--fifo-path=%s' % STDOUT_PIPE)
- self._ReadFifo(STDOUT_PIPE, stdout, on_application_stop)
- # The origin has to be specified whether it's local or external.
- assert any("--origin=" in arg for arg in arguments)
-
- # Extract map-origin arguments.
- map_parameters, other_parameters = _Split(arguments, _IsMapOrigin)
- parameters += other_parameters
- parameters += self._StartHttpServerForOriginMappings(map_parameters,
- fixed_port)
-
- if parameters:
- encodedParameters = json.dumps(parameters)
- cmd += ['--es', 'encodedParameters', encodedParameters]
-
- subprocess.check_call(cmd, stdout=self.verbose_pipe)
-
- def Run(self, arguments):
- """Runs the shell with given arguments until shell exits, passing the stdout
- mingled with stderr produced by the shell onto the stdout.
-
- Returns:
- Exit code retured by the shell or None if the exit code cannot be
- retrieved.
- """
- self.CleanLogs()
- p = self.ShowLogs()
- self.StartShell(arguments, sys.stdout, p.terminate)
- p.wait()
- return None
-
- def RunAndGetOutput(self, arguments):
- """Runs the shell with given arguments until shell exits.
-
- Args:
- arguments: list of arguments for the shell
-
- Returns:
- A tuple of (return_code, output). |return_code| is the exit code returned
- by the shell or None if the exit code cannot be retrieved. |output| is the
- stdout mingled with the stderr produced by the shell.
- """
- (r, w) = os.pipe()
- with os.fdopen(r, "r") as rf:
- with os.fdopen(w, "w") as wf:
- self.StartShell(arguments, wf, wf.close, False)
- output = rf.read()
- return None, output
-
- def StopShell(self):
- """Stops the mojo shell."""
- subprocess.check_call(self._CreateADBCommand(['shell',
- 'am',
- 'force-stop',
- MOJO_SHELL_PACKAGE_NAME]))
-
- def CleanLogs(self):
- """Cleans the logs on the device."""
- subprocess.check_call(self._CreateADBCommand(['logcat', '-c']))
-
- def ShowLogs(self):
- """Displays the log for the mojo shell.
-
- Returns:
- The process responsible for reading the logs.
- """
- logcat = subprocess.Popen(self._CreateADBCommand([
- 'logcat',
- '-s',
- ' '.join(LOGCAT_TAGS)]),
- stdout=sys.stdout)
- atexit.register(_ExitIfNeeded, logcat)
- return logcat
« no previous file with comments | « mojo/devtools/common/pylib/__init__.py ('k') | mojo/devtools/common/pylib/apptest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698