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

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: Some fixes 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:io"; 10 import "dart:io";
11 11
12 import "path.dart"; 12 import "path.dart";
13 import "utils.dart"; 13 import "utils.dart";
14 14
15 class AdbCommandResult {
16 final String command;
17 final String stdout;
18 final String stderr;
19 final int exitCode;
20
21 AdbCommandResult(this.command, this.stdout, this.stderr, this.exitCode);
22 }
23
15 Future _executeCommand(String executable, List<String> args, 24 Future _executeCommand(String executable, List<String> args,
16 [String stdin = ""]) { 25 [String stdin = ""]) {
17 return _executeCommandRaw(executable, args, stdin).then((results) => null); 26 return _executeCommandRaw(executable, args, stdin).then((result) {
27 _throwIfFailedAdbCommand(result);
28 });
18 } 29 }
19 30
20 Future _executeCommandGetOutput(String executable, List<String> args, 31 Future<String> _executeCommandGetOutput(String executable, List<String> args,
Bill Hesse 2016/04/27 12:22:31 Do we really need two functions, especially since
kustermann 2016/04/27 13:25:08 Done.
21 [String stdin = ""]) { 32 [String stdin = ""]) async {
22 return _executeCommandRaw(executable, args, stdin).then((output) => output); 33 AdbCommandResult result = await _executeCommandRaw(executable, args, stdin);
34 _throwIfFailedAdbCommand(result);
35 return result.stdout;
36 }
37
38 void _throwIfFailedAdbCommand(AdbCommandResult result) {
39 if (result.exitCode != 0) {
40 var error = "Running: ${result.command} failed:"
41 "stdout: \n ${result.stdout}"
42 "stderr: \n ${result.stderr}"
43 "exitCode: \n ${result.exitCode}";
44 throw new Exception(error);
45 }
23 } 46 }
24 47
25 /** 48 /**
26 * [_executeCommandRaw] will write [stdin] to the standard input of the created 49 * [_executeCommandRaw] will write [stdin] to the standard input of the created
27 * process and will return a tuple (stdout, stderr). 50 * process and will return a tuple (stdout, stderr).
28 * 51 *
29 * If the exit code of the process was nonzero it will complete with an error. 52 * 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. 53 * If starting the process failed, it will complete with an error as well.
31 */ 54 */
32 Future _executeCommandRaw(String executable, List<String> args, 55 Future<AdbCommandResult> _executeCommandRaw(
33 [String stdin = ""]) { 56 String executable, List<String> args, [String stdin = ""]) {
34 Future<String> getOutput(Stream<List<int>> stream) { 57 Future<String> getOutput(Stream<List<int>> stream) {
35 return stream 58 return stream
36 .transform(UTF8.decoder) 59 .transform(UTF8.decoder)
37 .toList() 60 .toList()
38 .then((data) => data.join("")); 61 .then((data) => data.join(""));
39 } 62 }
40 63
41 DebugLogger.info("Running: '\$ $executable ${args.join(' ')}'");
42 return Process.start(executable, args).then((Process process) { 64 return Process.start(executable, args).then((Process process) {
43 if (stdin != null && stdin != '') { 65 if (stdin != null && stdin != '') {
44 process.stdin.write(stdin); 66 process.stdin.write(stdin);
45 } 67 }
46 process.stdin.close(); 68 process.stdin.close();
47 69
48 var futures = [ 70 var futures = [
49 getOutput(process.stdout), 71 getOutput(process.stdout),
50 getOutput(process.stderr), 72 getOutput(process.stderr),
51 process.exitCode 73 process.exitCode
52 ]; 74 ];
Bill Hesse 2016/04/27 12:22:31 I think this is much simpler with async-await. We
kustermann 2016/04/27 13:25:08 If we don't drain stdout/stderr, then the buffer r
Bill Hesse 2016/04/27 13:54:40 The draining in parallel does happen, if we do the
53 return Future.wait(futures).then((results) { 75 return Future.wait(futures).then((results) {
54 bool success = results[2] == 0; 76 String command = '$executable ${args.join(' ')}';
55 if (!success) { 77 return new AdbCommandResult(command, results[0], results[1], results[2]);
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 }); 78 });
66 }); 79 });
67 } 80 }
68 81
69 /** 82 /**
70 * Helper class to loop through all adb ports. 83 * Helper class to loop through all adb ports.
71 * 84 *
72 * The ports come in pairs: 85 * The ports come in pairs:
73 * - even number: console connection 86 * - even number: console connection
74 * - odd number: adb connection 87 * - odd number: adb connection
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 } 305 }
293 306
294 /** 307 /**
295 * Kill all background processes. 308 * Kill all background processes.
296 */ 309 */
297 Future killAll() { 310 Future killAll() {
298 var arguments = ['shell', 'am', 'kill-all']; 311 var arguments = ['shell', 'am', 'kill-all'];
299 return _adbCommand(arguments); 312 return _adbCommand(arguments);
300 } 313 }
301 314
315 Future<AdbCommandResult> runAdbCommand(List<String> adbArgs) {
316 return _executeCommandRaw("adb", _deviceSpecificArgs(adbArgs));
317 }
318
319 Future<AdbCommandResult> runAdbShellCommand(List<String> shellArgs) async {
320 const MARKER = 'AdbShellExitCode: ';
321
322 // The exitcode of 'adb shell ...' can be 0 even though the command failed
323 // with a non-zero exit code. We therefore explicitly print it to stdout and
324 // search for it.
325
326 var args = ['shell',
327 "${shellArgs.join(' ')} ; echo $MARKER \$?"];
328 AdbCommandResult result = await _executeCommandRaw(
329 "adb", _deviceSpecificArgs(args));
330 int exitCode = result.exitCode;
331 var lines = result
332 .stdout.split('\n')
333 .where((line) => line.trim().length > 0)
334 .toList();
335 if (lines.length > 0) {
336 int index = lines.last.indexOf(MARKER);
337 assert(index >= 0);
338 exitCode = int.parse(lines.last.substring(index + MARKER.length).trim());
339 }
340 return new AdbCommandResult(
341 result.command, result.stdout, result.stderr, exitCode);
342 }
343
302 Future _adbCommand(List<String> adbArgs) { 344 Future _adbCommand(List<String> adbArgs) {
Bill Hesse 2016/04/27 12:22:31 These two could also be united to one that returns
kustermann 2016/04/27 13:25:09 Done.
345 return _executeCommand("adb", _deviceSpecificArgs(adbArgs));
346 }
347
348 Future<String> _adbCommandGetOutput(List<String> adbArgs) {
349 return _executeCommandGetOutput("adb", _deviceSpecificArgs(adbArgs));
350 }
351
352 List<String> _deviceSpecificArgs(List<String> adbArgs) {
303 if (_deviceId != null) { 353 if (_deviceId != null) {
304 var extendedAdbArgs = ['-s', _deviceId]; 354 var extendedAdbArgs = ['-s', _deviceId];
305 extendedAdbArgs.addAll(adbArgs); 355 extendedAdbArgs.addAll(adbArgs);
306 adbArgs = extendedAdbArgs; 356 adbArgs = extendedAdbArgs;
307 } 357 }
308 return _executeCommand("adb", adbArgs); 358 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 } 359 }
319 } 360 }
320 361
321 /** 362 /**
322 * Helper to list all adb devices available. 363 * Helper to list all adb devices available.
323 */ 364 */
324 class AdbHelper { 365 class AdbHelper {
325 static RegExp _deviceLineRegexp = 366 static RegExp _deviceLineRegexp =
326 new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true); 367 new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true);
327 368
(...skipping 15 matching lines...) Expand all
343 * Represents an android intent. 384 * Represents an android intent.
344 */ 385 */
345 class Intent { 386 class Intent {
346 String action; 387 String action;
347 String package; 388 String package;
348 String activity; 389 String activity;
349 String dataUri; 390 String dataUri;
350 391
351 Intent(this.action, this.package, this.activity, [this.dataUri]); 392 Intent(this.action, this.package, this.activity, [this.dataUri]);
352 } 393 }
394
395 /**
396 * Discovers all available devices and supports aquire/release.
Bill Hesse 2016/04/27 12:22:31 acquire
kustermann 2016/04/27 13:25:08 Done.
397 */
398 class AdbDevicePool {
399 List<AdbDevice> _idleDevices;
400 List<Completer> _waiter = [];
401
402 AdbDevicePool(this._idleDevices);
403
404 static Future<AdbDevicePool> create() async {
405 var names = await AdbHelper.listDevices();
406 var devices = names.map((id) => new AdbDevice(id)).toList();
407 if (devices.length == 0) {
408 throw new Exception(
409 'No android devices found. '
410 'Please make sure "adb devices" shows your device!');
411 }
412 return new AdbDevicePool(devices);
413 }
414
415 Future<AdbDevice> aquireDevice() async {
Bill Hesse 2016/04/27 12:22:31 acquire
kustermann 2016/04/27 13:25:09 Done.
416 if (_idleDevices.length > 0) {
417 return _idleDevices.removeLast();
418 } else {
419 var completer = new Completer();
420 _waiter.add(completer);
421 return completer.future;
422 }
423 }
424
425 void releaseDevice(AdbDevice device) {
426 if (_waiter.length > 0) {
427 Completer completer = _waiter.removeLast();
Bill Hesse 2016/04/27 12:22:31 Both idle devices and waiting requests are LIFO.
kustermann 2016/04/27 13:25:08 Fair enough. Though we have just about 4 devices a
428 completer.complete(device);
429 } else {
430 _idleDevices.add(device);
431 }
432 }
433 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698