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

Side by Side Diff: mojo/tools/mopy/android.py

Issue 878933003: Move the apptest runner and parts of mopy to the public SDK. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 10 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 unified diff | Download patch
« no previous file with comments | « mojo/tools/mopy/__init__.py ('k') | mojo/tools/mopy/background_app_group.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 import atexit
7 import logging
8 import os
9 import os.path
10 import subprocess
11 import sys
12 import threading
13 import time
14
15 import SimpleHTTPServer
16 import SocketServer
17
18 from mopy.config import Config
19 from mopy.paths import Paths
20
21 sys.path.insert(0, os.path.join(Paths().src_root, 'build', 'android'))
22 from pylib import android_commands
23 from pylib import constants
24 from pylib import forwarder
25
26
27 # Tags used by the mojo shell application logs.
28 LOGCAT_TAGS = [
29 'AndroidHandler',
30 'MojoFileHelper',
31 'MojoMain',
32 'MojoShellActivity',
33 'MojoShellApplication',
34 'chromium',
35 ]
36
37 MOJO_SHELL_PACKAGE_NAME = 'org.chromium.mojo.shell'
38
39
40 class Context(object):
41 """
42 The context object allowing to run multiple runs of the shell.
43 """
44 def __init__(self, device, device_port):
45 self.device = device
46 self.device_port = device_port
47
48
49 class _SilentTCPServer(SocketServer.TCPServer):
50 """
51 A TCPServer that won't display any error, unless debugging is enabled. This is
52 useful because the client might stop while it is fetching an URL, which causes
53 spurious error messages.
54 """
55 def handle_error(self, request, client_address):
56 """
57 Override the base class method to have conditional logging.
58 """
59 if logging.getLogger().isEnabledFor(logging.DEBUG):
60 super(_SilentTCPServer, self).handle_error(request, client_address)
61
62
63 def _GetHandlerClassForPath(base_path):
64 class RequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
65 """
66 Handler for SocketServer.TCPServer that will serve the files from
67 |base_path| directory over http.
68 """
69
70 def translate_path(self, path):
71 path_from_current = (
72 SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path(self, path))
73 return os.path.join(base_path, os.path.relpath(path_from_current))
74
75 def log_message(self, *_):
76 """
77 Override the base class method to disable logging.
78 """
79 pass
80
81 return RequestHandler
82
83
84 def _ExitIfNeeded(process):
85 """
86 Exits |process| if it is still alive.
87 """
88 if process.poll() is None:
89 process.kill()
90
91
92 def _ReadFifo(context, fifo_path, pipe, on_fifo_closed):
93 """
94 Reads |fifo_path| on the device and write the contents to |pipe|. Calls
95 |on_fifo_closed| when the fifo is closed. This method will block until
96 |fifo_path| exists.
97 """
98 def Run():
99 while not context.device.FileExistsOnDevice(fifo_path):
100 time.sleep(1)
101 stdout_cat = subprocess.Popen([constants.GetAdbPath(),
102 'shell',
103 'cat',
104 fifo_path],
105 stdout=pipe)
106 atexit.register(_ExitIfNeeded, stdout_cat)
107 stdout_cat.wait()
108 if on_fifo_closed:
109 on_fifo_closed()
110
111 thread = threading.Thread(target=Run, name="StdoutRedirector")
112 thread.start()
113
114
115 def PrepareShellRun(config):
116 """
117 Returns a context allowing a shell to be run.
118
119 This will start an internal http server to serve mojo applications, forward a
120 local port on the device to this http server and install the current version
121 of the mojo shell.
122 """
123 build_dir = Paths(config).build_dir
124 constants.SetOutputDirectort(build_dir)
125
126 httpd = _SilentTCPServer(('127.0.0.1', 0), _GetHandlerClassForPath(build_dir))
127 atexit.register(httpd.shutdown)
128 host_port = httpd.server_address[1]
129
130 http_thread = threading.Thread(target=httpd.serve_forever)
131 http_thread.daemon = True
132 http_thread.start()
133
134 device = android_commands.AndroidCommands(
135 android_commands.GetAttachedDevices()[0])
136 device.EnableAdbRoot()
137
138 device.ManagedInstall(os.path.join(build_dir, 'apks', 'MojoShell.apk'),
139 keep_data=True,
140 package_name=MOJO_SHELL_PACKAGE_NAME)
141
142 atexit.register(forwarder.Forwarder.UnmapAllDevicePorts, device)
143 forwarder.Forwarder.Map([(0, host_port)], device)
144 context = Context(device,
145 forwarder.Forwarder.DevicePortForHostPort(host_port))
146
147 atexit.register(StopShell, context)
148 return context
149
150
151 def StartShell(context, arguments, stdout=None, on_application_stop=None):
152 """
153 Starts the mojo shell, passing it the given arguments.
154
155 If stdout is not None, it should be a valid argument for subprocess.Popen.
156 """
157 STDOUT_PIPE = "/data/data/%s/stdout.fifo" % MOJO_SHELL_PACKAGE_NAME
158
159 cmd = ('am start'
160 ' -W'
161 ' -S'
162 ' -a android.intent.action.VIEW'
163 ' -n %s/.MojoShellActivity' % MOJO_SHELL_PACKAGE_NAME)
164
165 parameters = ['--origin=http://127.0.0.1:%d/' % context.device_port]
166 if stdout or on_application_stop:
167 context.device.RunShellCommand('rm %s' % STDOUT_PIPE)
168 parameters.append('--fifo-path=%s' % STDOUT_PIPE)
169 _ReadFifo(context, STDOUT_PIPE, stdout, on_application_stop)
170 parameters += arguments
171 cmd += ' --esa parameters \"%s\"' % ','.join(parameters)
172
173 context.device.RunShellCommand(cmd)
174
175
176 def StopShell(context):
177 """
178 Stops the mojo shell.
179 """
180 context.device.RunShellCommand('am force-stop %s' % MOJO_SHELL_PACKAGE_NAME)
181
182 def CleanLogs(context):
183 """
184 Cleans the logs on the device.
185 """
186 context.device.RunShellCommand('logcat -c')
187
188
189 def ShowLogs():
190 """
191 Displays the log for the mojo shell.
192
193 Returns the process responsible for reading the logs.
194 """
195 logcat = subprocess.Popen([constants.GetAdbPath(),
196 'logcat',
197 '-s',
198 ' '.join(LOGCAT_TAGS)],
199 stdout=sys.stdout)
200 atexit.register(_ExitIfNeeded, logcat)
201 return logcat
202
203
204 def GetFilePath(filename):
205 """
206 Returns a path suitable for the application to create a file.
207 """
208 return '/data/data/%s/files/%s' % (MOJO_SHELL_PACKAGE_NAME, filename)
OLDNEW
« no previous file with comments | « mojo/tools/mopy/__init__.py ('k') | mojo/tools/mopy/background_app_group.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698