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

Side by Side Diff: tools/testing/dart/android.dart

Issue 841193003: cleanup to tools/testing/dart (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: one last bit Created 5 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « tools/test.dart ('k') | tools/testing/dart/browser_controller.dart » ('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 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library android;
6
7 import "dart:async";
8 import "dart:convert" show LineSplitter, UTF8;
9 import "dart:core";
10 import "dart:io";
11
12 import "path.dart";
13 import "utils.dart";
14
15 Future _executeCommand(String executable,
16 List<String> args,
17 [String stdin = ""]) {
18 return _executeCommandRaw(executable, args, stdin).then((results) => null);
19 }
20
21 Future _executeCommandGetOutput(String executable,
22 List<String> args,
23 [String stdin = ""]) {
24 return _executeCommandRaw(executable, args, stdin)
25 .then((output) => output);
26 }
27
28 /**
29 * [_executeCommandRaw] will write [stdin] to the standard input of the created
30 * process and will return a tuple (stdout, stderr).
31 *
32 * If the exit code of the process was nonzero it will complete with an error.
33 * If starting the process failed, it will complete with an error as well.
34 */
35 Future _executeCommandRaw(String executable,
36 List<String> args,
37 [String stdin = ""]) {
38 Future<String> getOutput(Stream<List<int>> stream) {
39 return stream.transform(UTF8.decoder).toList()
40 .then((data) => data.join(""));
41 }
42
43 DebugLogger.info("Running: '\$ $executable ${args.join(' ')}'");
44 return Process.start(executable, args).then((Process process) {
45 if (stdin != null && stdin != '') {
46 process.stdin.write(stdin);
47 }
48 process.stdin.close();
49
50 var futures = [getOutput(process.stdout),
51 getOutput(process.stderr),
52 process.exitCode];
53 return Future.wait(futures).then((results) {
54 bool success = results[2] == 0;
55 if (!success) {
56 var error = "Running: '\$ $executable ${args.join(' ')}' failed:"
57 "stdout: \n ${results[0]}"
58 "stderr: \n ${results[1]}"
59 "exitCode: \n ${results[2]}";
60 throw new Exception(error);
61 } else {
62 DebugLogger.info("Success: $executable finished");
63 }
64 return results[0];
65 });
66 });
67 }
68
69 /**
70 * Helper class to loop through all adb ports.
71 *
72 * The ports come in pairs:
73 * - even number: console connection
74 * - odd number: adb connection
75 * Note that this code doesn't check if the ports are used.
76 */
77 class AdbServerPortPool {
78 static int MIN_PORT = 5554;
79 static int MAX_PORT = 5584;
80
81 static int _nextPort = MIN_PORT;
82
83 static int next() {
84 var port = _nextPort;
85 if (port > MAX_PORT) {
86 throw new Exception("All ports are used.");
87 }
88 _nextPort += 2;
89 return port;
90 }
91 }
92
93 /**
94 * Represents the interface to the emulator.
95 * New emulators can be launched by calling the static [launchNewEmulator]
96 * method.
97 */
98 class AndroidEmulator {
99 int _port;
100 Process _emulatorProcess;
101 AdbDevice _adbDevice;
102
103 int get port => _port;
104
105 AdbDevice get adbDevice => _adbDevice;
106
107 static Future<AndroidEmulator> launchNewEmulator(String avdName) {
108 var portNumber = AdbServerPortPool.next();
109 var args = ['-avd', '$avdName', '-port', "$portNumber" /*, '-gpu', 'on'*/];
110 return Process.start("emulator64-arm", args).then((Process process) {
111 var adbDevice = new AdbDevice('emulator-$portNumber');
112 return new AndroidEmulator._private(portNumber, adbDevice, process);
113 });
114 }
115
116 AndroidEmulator._private(this._port, this._adbDevice, this._emulatorProcess) {
117 Stream<String> getLines(Stream s) {
118 return s.transform(UTF8.decoder).transform(new LineSplitter());
119 }
120
121 getLines(_emulatorProcess.stdout).listen((line) {
122 log("stdout: ${line.trim()}");
123 });
124 getLines(_emulatorProcess.stderr).listen((line) {
125 log("stderr: ${line.trim()}");
126 });
127 _emulatorProcess.exitCode.then((exitCode) {
128 log("emulator exited with exitCode: $exitCode.");
129 });
130 }
131
132 Future<bool> kill() {
133 var completer = new Completer();
134 if (_emulatorProcess.kill()) {
135 _emulatorProcess.exitCode.then((exitCode) {
136 // TODO: Should we use exitCode to do something clever?
137 completer.complete(true);
138 });
139 } else {
140 log("Sending kill signal to emulator process failed");
141 completer.complete(false);
142 }
143 return completer.future;
144 }
145
146 void log(String msg) {
147 DebugLogger.info("AndroidEmulator(${_adbDevice.deviceId}): $msg");
148 }
149 }
150
151 /**
152 * Helper class to create avd device configurations.
153 */
154 class AndroidHelper {
155 static Future createAvd(String name, String target) {
156 var args = ['--silent', 'create', 'avd', '--name', '$name',
157 '--target', '$target', '--force', '--abi', 'armeabi-v7a'];
158 // We're adding newlines to stdin to simulate <enter>.
159 return _executeCommand("android", args, "\n\n\n\n");
160 }
161 }
162
163 /**
164 * Used for communicating with an emulator or with a real device.
165 */
166 class AdbDevice {
167 static const _adbServerStartupTime = const Duration(seconds: 3);
168 String _deviceId;
169
170 String get deviceId => _deviceId;
171
172 AdbDevice(this._deviceId);
173
174 /**
175 * Blocks execution until the device is online
176 */
177 Future waitForDevice() {
178 return _adbCommand(['wait-for-device']);
179 }
180
181 /**
182 * Polls the 'sys.boot_completed' property. Returns as soon as the property is
183 * 1.
184 */
185 Future waitForBootCompleted() {
186 var timeout = const Duration(seconds: 2);
187 var completer = new Completer();
188
189 checkUntilBooted() {
190 _adbCommandGetOutput(['shell', 'getprop', 'sys.boot_completed'])
191 .then((String stdout) {
192 stdout = stdout.trim();
193 if (stdout == '1') {
194 completer.complete();
195 } else {
196 new Timer(timeout, checkUntilBooted);
197 }
198 }).catchError((error) {
199 new Timer(timeout, checkUntilBooted);
200 });
201 }
202 checkUntilBooted();
203 return completer.future;
204 }
205
206 /**
207 * Put adb in root mode.
208 */
209 Future adbRoot() {
210 var adbRootCompleter = new Completer();
211 _adbCommand(['root']).then((_) {
212 // TODO: Figure out a way to wait until the adb daemon was restarted in
213 // 'root mode' on the device.
214 new Timer(_adbServerStartupTime, () => adbRootCompleter.complete(true));
215 }).catchError((error) => adbRootCompleter.completeError(error));
216 return adbRootCompleter.future;
217 }
218
219 /**
220 * Download data form the device.
221 */
222 Future pullData(Path remote, Path local) {
223 return _adbCommand(['pull', '$remote', '$local']);
224 }
225
226 /**
227 * Upload data to the device.
228 */
229 Future pushData(Path local, Path remote) {
230 return _adbCommand(['push', '$local', '$remote']);
231 }
232
233 /**
234 * Change permission of directory recursively.
235 */
236 Future chmod(String mode, Path directory) {
237 var arguments = ['shell', 'chmod', '-R', mode, '$directory'];
238 return _adbCommand(arguments);
239 }
240
241 /**
242 * Install an application on the device.
243 */
244 Future installApk(Path filename) {
245 return _adbCommand(
246 ['install', '-i', 'com.google.android.feedback', '-r', '$filename']);
247 }
248
249 /**
250 * Start the given intent on the device.
251 */
252 Future startActivity(Intent intent) {
253 var arguments = ['shell', 'am', 'start', '-W',
254 '-a', intent.action,
255 '-n', "${intent.package}/${intent.activity}"];
256 if (intent.dataUri != null) {
257 arguments.addAll(['-d', intent.dataUri]);
258 }
259 return _adbCommand(arguments);
260 }
261
262 /**
263 * Force to stop everything associated with [package].
264 */
265 Future forceStop(String package) {
266 var arguments = ['shell', 'am', 'force-stop', package];
267 return _adbCommand(arguments);
268 }
269
270 /**
271 * Set system property name to value.
272 */
273 Future setProp(String name, String value) {
274 return _adbCommand(['shell', 'setprop', name, value]);
275 }
276
277 /**
278 * Kill all background processes.
279 */
280 Future killAll() {
281 var arguments = ['shell', 'am', 'kill-all'];
282 return _adbCommand(arguments);
283 }
284
285 Future _adbCommand(List<String> adbArgs) {
286 if (_deviceId != null) {
287 var extendedAdbArgs = ['-s', _deviceId];
288 extendedAdbArgs.addAll(adbArgs);
289 adbArgs = extendedAdbArgs;
290 }
291 return _executeCommand("adb", adbArgs);
292 }
293
294 Future<String> _adbCommandGetOutput(List<String> adbArgs) {
295 if (_deviceId != null) {
296 var extendedAdbArgs = ['-s', _deviceId];
297 extendedAdbArgs.addAll(adbArgs);
298 adbArgs = extendedAdbArgs;
299 }
300 return _executeCommandGetOutput("adb", adbArgs);
301 }
302 }
303
304 /**
305 * Helper to list all adb devices available.
306 */
307 class AdbHelper {
308 static RegExp _deviceLineRegexp =
309 new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true);
310
311 static Future<List<String>> listDevices() {
312 return Process.run('adb', ['devices']).then((ProcessResult result) {
313 if (result.exitCode != 0) {
314 throw new Exception("Could not list devices [stdout: ${result.stdout},"
315 "stderr: ${result.stderr}]");
316 }
317 return _deviceLineRegexp.allMatches(result.stdout)
318 .map((Match m) => m.group(1)).toList();
319 });
320 }
321 }
322
323 /**
324 * Represents an android intent.
325 */
326 class Intent {
327 String action;
328 String package;
329 String activity;
330 String dataUri;
331
332 Intent(this.action, this.package, this.activity, [this.dataUri]);
333 }
334
OLDNEW
« no previous file with comments | « tools/test.dart ('k') | tools/testing/dart/browser_controller.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698