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

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

Issue 1922163002: Initial support to test.dart for running precompiler tests on android devices (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Cleanup of CL and of existing code. Created 4 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library android; 5 library android;
6 6
7 import "dart:async"; 7 import "dart:async";
8 import "dart:convert" show LineSplitter, UTF8; 8 import "dart:convert" show LineSplitter, UTF8;
9 import "dart:core"; 9 import "dart:core";
10 import "dart:collection";
10 import "dart:io"; 11 import "dart:io";
11 12
12 import "path.dart"; 13 import "path.dart";
13 import "utils.dart"; 14 import "utils.dart";
14 15
15 Future _executeCommand(String executable, List<String> args, 16 class AdbCommandResult {
16 [String stdin = ""]) { 17 final String command;
17 return _executeCommandRaw(executable, args, stdin).then((results) => null); 18 final String stdout;
18 } 19 final String stderr;
20 final int exitCode;
19 21
20 Future _executeCommandGetOutput(String executable, List<String> args, 22 AdbCommandResult(this.command, this.stdout, this.stderr, this.exitCode);
21 [String stdin = ""]) { 23
22 return _executeCommandRaw(executable, args, stdin).then((output) => output); 24 void throwIfFailed() {
25 if (exitCode != 0) {
26 var error = "Running: $command failed:"
27 "stdout: \n $stdout"
28 "stderr: \n $stderr"
29 "exitCode: \n $exitCode";
30 throw new Exception(error);
31 }
32 }
23 } 33 }
24 34
25 /** 35 /**
26 * [_executeCommandRaw] will write [stdin] to the standard input of the created 36 * [_executeCommand] will write [stdin] to the standard input of the created
27 * process and will return a tuple (stdout, stderr). 37 * process and will return a tuple (stdout, stderr).
28 * 38 *
29 * If the exit code of the process was nonzero it will complete with an error. 39 * If the exit code of the process was nonzero it will complete with an error.
30 * If starting the process failed, it will complete with an error as well. 40 * If starting the process failed, it will complete with an error as well.
31 */ 41 */
32 Future _executeCommandRaw(String executable, List<String> args, 42 Future<AdbCommandResult> _executeCommand(
33 [String stdin = ""]) { 43 String executable, List<String> args, [String stdin = ""]) {
34 Future<String> getOutput(Stream<List<int>> stream) { 44 Future<String> getOutput(Stream<List<int>> stream) {
35 return stream 45 return stream
36 .transform(UTF8.decoder) 46 .transform(UTF8.decoder)
37 .toList() 47 .toList()
38 .then((data) => data.join("")); 48 .then((data) => data.join(""));
39 } 49 }
40 50
41 DebugLogger.info("Running: '\$ $executable ${args.join(' ')}'"); 51 return Process.start(executable, args).then((Process process) async {
42 return Process.start(executable, args).then((Process process) {
43 if (stdin != null && stdin != '') { 52 if (stdin != null && stdin != '') {
44 process.stdin.write(stdin); 53 process.stdin.write(stdin);
45 } 54 }
46 process.stdin.close(); 55 process.stdin.close();
47 56
48 var futures = [ 57 var results = await Future.wait([
49 getOutput(process.stdout), 58 getOutput(process.stdout),
50 getOutput(process.stderr), 59 getOutput(process.stderr),
51 process.exitCode 60 process.exitCode
52 ]; 61 ]);
53 return Future.wait(futures).then((results) { 62 String command = '$executable ${args.join(' ')}';
Bill Hesse 2016/04/27 13:54:40 It may be legal to have ' inside ' because it is i
kustermann 2016/05/02 10:40:23 Done.
54 bool success = results[2] == 0; 63 return new AdbCommandResult(command, results[0], results[1], results[2]);
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 }); 64 });
67 } 65 }
68 66
69 /** 67 /**
70 * Helper class to loop through all adb ports. 68 * Helper class to loop through all adb ports.
71 * 69 *
72 * The ports come in pairs: 70 * The ports come in pairs:
73 * - even number: console connection 71 * - even number: console connection
74 * - odd number: adb connection 72 * - odd number: adb connection
75 * Note that this code doesn't check if the ports are used. 73 * Note that this code doesn't check if the ports are used.
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 143
146 void log(String msg) { 144 void log(String msg) {
147 DebugLogger.info("AndroidEmulator(${_adbDevice.deviceId}): $msg"); 145 DebugLogger.info("AndroidEmulator(${_adbDevice.deviceId}): $msg");
148 } 146 }
149 } 147 }
150 148
151 /** 149 /**
152 * Helper class to create avd device configurations. 150 * Helper class to create avd device configurations.
153 */ 151 */
154 class AndroidHelper { 152 class AndroidHelper {
155 static Future createAvd(String name, String target) { 153 static Future createAvd(String name, String target) async {
156 var args = [ 154 var args = [
157 '--silent', 155 '--silent',
158 'create', 156 'create',
159 'avd', 157 'avd',
160 '--name', 158 '--name',
161 '$name', 159 '$name',
162 '--target', 160 '--target',
163 '$target', 161 '$target',
164 '--force', 162 '--force',
165 '--abi', 163 '--abi',
166 'armeabi-v7a' 164 'armeabi-v7a'
167 ]; 165 ];
168 // We're adding newlines to stdin to simulate <enter>. 166 // We're adding newlines to stdin to simulate <enter>.
169 return _executeCommand("android", args, "\n\n\n\n"); 167 var result = await _executeCommand("android", args, "\n\n\n\n");
168 result.throwIfFailed();
170 } 169 }
171 } 170 }
172 171
173 /** 172 /**
174 * Used for communicating with an emulator or with a real device. 173 * Used for communicating with an emulator or with a real device.
175 */ 174 */
176 class AdbDevice { 175 class AdbDevice {
177 static const _adbServerStartupTime = const Duration(seconds: 3); 176 static const _adbServerStartupTime = const Duration(seconds: 3);
178 String _deviceId; 177 String _deviceId;
179 178
180 String get deviceId => _deviceId; 179 String get deviceId => _deviceId;
181 180
182 AdbDevice(this._deviceId); 181 AdbDevice(this._deviceId);
183 182
184 /** 183 /**
185 * Blocks execution until the device is online 184 * Blocks execution until the device is online
186 */ 185 */
187 Future waitForDevice() { 186 Future waitForDevice() {
188 return _adbCommand(['wait-for-device']); 187 return _adbCommand(['wait-for-device']);
189 } 188 }
190 189
191 /** 190 /**
192 * Polls the 'sys.boot_completed' property. Returns as soon as the property is 191 * Polls the 'sys.boot_completed' property. Returns as soon as the property is
193 * 1. 192 * 1.
194 */ 193 */
195 Future waitForBootCompleted() { 194 Future waitForBootCompleted() async {
196 var timeout = const Duration(seconds: 2); 195 while (true) {
197 var completer = new Completer(); 196 try {
198 197 AdbCommandResult result =
199 checkUntilBooted() { 198 await _adbCommand(['shell', 'getprop', 'sys.boot_completed']);
200 _adbCommandGetOutput(['shell', 'getprop', 'sys.boot_completed']) 199 if (result.stdout.trim() == '1') return;
201 .then((String stdout) { 200 } catch (_) { }
202 stdout = stdout.trim(); 201 await new Future.delayed(const Duration(seconds: 2));
203 if (stdout == '1') {
204 completer.complete();
205 } else {
206 new Timer(timeout, checkUntilBooted);
207 }
208 }).catchError((error) {
209 new Timer(timeout, checkUntilBooted);
210 });
211 } 202 }
212 checkUntilBooted();
213 return completer.future;
214 } 203 }
215 204
216 /** 205 /**
217 * Put adb in root mode. 206 * Put adb in root mode.
218 */ 207 */
219 Future adbRoot() { 208 Future adbRoot() {
220 var adbRootCompleter = new Completer(); 209 var adbRootCompleter = new Completer();
221 _adbCommand(['root']).then((_) { 210 _adbCommand(['root']).then((_) {
222 // TODO: Figure out a way to wait until the adb daemon was restarted in 211 // TODO: Figure out a way to wait until the adb daemon was restarted in
223 // 'root mode' on the device. 212 // 'root mode' on the device.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 } 281 }
293 282
294 /** 283 /**
295 * Kill all background processes. 284 * Kill all background processes.
296 */ 285 */
297 Future killAll() { 286 Future killAll() {
298 var arguments = ['shell', 'am', 'kill-all']; 287 var arguments = ['shell', 'am', 'kill-all'];
299 return _adbCommand(arguments); 288 return _adbCommand(arguments);
300 } 289 }
301 290
302 Future _adbCommand(List<String> adbArgs) { 291 Future<AdbCommandResult> runAdbCommand(List<String> adbArgs) {
292 return _executeCommand("adb", _deviceSpecificArgs(adbArgs));
293 }
294
295 Future<AdbCommandResult> runAdbShellCommand(List<String> shellArgs) async {
296 const MARKER = 'AdbShellExitCode: ';
297
298 // The exitcode of 'adb shell ...' can be 0 even though the command failed
299 // with a non-zero exit code. We therefore explicitly print it to stdout and
300 // search for it.
301
302 var args = ['shell',
303 "${shellArgs.join(' ')} ; echo $MARKER \$?"];
304 AdbCommandResult result = await _executeCommand(
305 "adb", _deviceSpecificArgs(args));
306 int exitCode = result.exitCode;
307 var lines = result
308 .stdout.split('\n')
309 .where((line) => line.trim().length > 0)
310 .toList();
311 if (lines.length > 0) {
312 int index = lines.last.indexOf(MARKER);
313 assert(index >= 0);
314 exitCode = int.parse(lines.last.substring(index + MARKER.length).trim());
315 }
316 return new AdbCommandResult(
317 result.command, result.stdout, result.stderr, exitCode);
318 }
319
320 Future<AdbCommandResult> _adbCommand(List<String> adbArgs) async {
321 var result = await _executeCommand("adb", _deviceSpecificArgs(adbArgs));
322 result.throwIfFailed();
323 return result;
324 }
325
326 List<String> _deviceSpecificArgs(List<String> adbArgs) {
303 if (_deviceId != null) { 327 if (_deviceId != null) {
304 var extendedAdbArgs = ['-s', _deviceId]; 328 var extendedAdbArgs = ['-s', _deviceId];
305 extendedAdbArgs.addAll(adbArgs); 329 extendedAdbArgs.addAll(adbArgs);
306 adbArgs = extendedAdbArgs; 330 adbArgs = extendedAdbArgs;
307 } 331 }
308 return _executeCommand("adb", adbArgs); 332 return adbArgs;
309 }
310
311 Future<String> _adbCommandGetOutput(List<String> adbArgs) {
312 if (_deviceId != null) {
313 var extendedAdbArgs = ['-s', _deviceId];
314 extendedAdbArgs.addAll(adbArgs);
315 adbArgs = extendedAdbArgs;
316 }
317 return _executeCommandGetOutput("adb", adbArgs);
318 } 333 }
319 } 334 }
320 335
321 /** 336 /**
322 * Helper to list all adb devices available. 337 * Helper to list all adb devices available.
323 */ 338 */
324 class AdbHelper { 339 class AdbHelper {
325 static RegExp _deviceLineRegexp = 340 static RegExp _deviceLineRegexp =
326 new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true); 341 new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true);
327 342
(...skipping 15 matching lines...) Expand all
343 * Represents an android intent. 358 * Represents an android intent.
344 */ 359 */
345 class Intent { 360 class Intent {
346 String action; 361 String action;
347 String package; 362 String package;
348 String activity; 363 String activity;
349 String dataUri; 364 String dataUri;
350 365
351 Intent(this.action, this.package, this.activity, [this.dataUri]); 366 Intent(this.action, this.package, this.activity, [this.dataUri]);
352 } 367 }
368
369 /**
370 * Discovers all available devices and supports acquire/release.
371 */
372 class AdbDevicePool {
373 final Queue<AdbDevice> _idleDevices = new Queue<AdbDevice>();
374 final Queue<Completer> _waiter = new Queue<Completer>();
375
376 AdbDevicePool(List<AdbDevice> idleDevices) {
377 _idleDevices.addAll(idleDevices);
378 }
379
380 static Future<AdbDevicePool> create() async {
381 var names = await AdbHelper.listDevices();
382 var devices = names.map((id) => new AdbDevice(id)).toList();
383 if (devices.length == 0) {
384 throw new Exception(
385 'No android devices found. '
386 'Please make sure "adb devices" shows your device!');
387 }
388 return new AdbDevicePool(devices);
389 }
390
391 Future<AdbDevice> acquireDevice() async {
392 if (_idleDevices.length > 0) {
393 return _idleDevices.removeFirst();
394 } else {
395 var completer = new Completer();
396 _waiter.add(completer);
397 return completer.future;
398 }
399 }
400
401 void releaseDevice(AdbDevice device) {
402 if (_waiter.length > 0) {
403 Completer completer = _waiter.removeFirst();
404 completer.complete(device);
405 } else {
406 _idleDevices.add(device);
407 }
408 }
409 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698