Index: tools/testing/dart/android.dart |
diff --git a/tools/testing/dart/android.dart b/tools/testing/dart/android.dart |
index 1d390715733707bd716b615c676b5b17a7e6d3ee..07ce4bc3593e071e254a7d51e4e5681116d9d5dd 100644 |
--- a/tools/testing/dart/android.dart |
+++ b/tools/testing/dart/android.dart |
@@ -12,14 +12,37 @@ import "dart:io"; |
import "path.dart"; |
import "utils.dart"; |
+class AdbCommandResult { |
+ final String command; |
+ final String stdout; |
+ final String stderr; |
+ final int exitCode; |
+ |
+ AdbCommandResult(this.command, this.stdout, this.stderr, this.exitCode); |
+} |
+ |
Future _executeCommand(String executable, List<String> args, |
[String stdin = ""]) { |
- return _executeCommandRaw(executable, args, stdin).then((results) => null); |
+ return _executeCommandRaw(executable, args, stdin).then((result) { |
+ _throwIfFailedAdbCommand(result); |
+ }); |
} |
-Future _executeCommandGetOutput(String executable, List<String> args, |
- [String stdin = ""]) { |
- return _executeCommandRaw(executable, args, stdin).then((output) => output); |
+Future<String> _executeCommandGetOutput(String executable, List<String> args, |
+ [String stdin = ""]) async { |
+ AdbCommandResult result = await _executeCommandRaw(executable, args, stdin); |
+ _throwIfFailedAdbCommand(result); |
+ return result.stdout; |
+} |
+ |
+void _throwIfFailedAdbCommand(AdbCommandResult result) { |
+ if (result.exitCode != 0) { |
+ var error = "Running: ${result.command} failed:" |
+ "stdout: \n ${result.stdout}" |
+ "stderr: \n ${result.stderr}" |
+ "exitCode: \n ${result.exitCode}"; |
+ throw new Exception(error); |
+ } |
} |
/** |
@@ -29,8 +52,8 @@ Future _executeCommandGetOutput(String executable, List<String> args, |
* If the exit code of the process was nonzero it will complete with an error. |
* If starting the process failed, it will complete with an error as well. |
*/ |
-Future _executeCommandRaw(String executable, List<String> args, |
- [String stdin = ""]) { |
+Future<AdbCommandResult> _executeCommandRaw( |
+ String executable, List<String> args, [String stdin = ""]) { |
Future<String> getOutput(Stream<List<int>> stream) { |
return stream |
.transform(UTF8.decoder) |
@@ -38,7 +61,6 @@ Future _executeCommandRaw(String executable, List<String> args, |
.then((data) => data.join("")); |
} |
- DebugLogger.info("Running: '\$ $executable ${args.join(' ')}'"); |
return Process.start(executable, args).then((Process process) { |
if (stdin != null && stdin != '') { |
process.stdin.write(stdin); |
@@ -51,17 +73,8 @@ Future _executeCommandRaw(String executable, List<String> args, |
process.exitCode |
]; |
return Future.wait(futures).then((results) { |
- bool success = results[2] == 0; |
- if (!success) { |
- var error = "Running: '\$ $executable ${args.join(' ')}' failed:" |
- "stdout: \n ${results[0]}" |
- "stderr: \n ${results[1]}" |
- "exitCode: \n ${results[2]}"; |
- throw new Exception(error); |
- } else { |
- DebugLogger.info("Success: $executable finished"); |
- } |
- return results[0]; |
+ String command = '$executable ${args.join(' ')}'; |
+ return new AdbCommandResult(command, results[0], results[1], results[2]); |
}); |
}); |
} |
@@ -299,22 +312,50 @@ class AdbDevice { |
return _adbCommand(arguments); |
} |
- Future _adbCommand(List<String> adbArgs) { |
- if (_deviceId != null) { |
- var extendedAdbArgs = ['-s', _deviceId]; |
- extendedAdbArgs.addAll(adbArgs); |
- adbArgs = extendedAdbArgs; |
+ Future<AdbCommandResult> runAdbCommand(List<String> adbArgs) { |
+ return _executeCommandRaw("adb", _deviceSpecificArgs(adbArgs)); |
+ } |
+ |
+ Future<AdbCommandResult> runAdbShellCommand(List<String> shellArgs) async { |
+ const MARKER = 'AdbShellExitCode: '; |
+ |
+ // The exitcode of 'adb shell ...' can be 0 even though the command failed |
+ // with a non-zero exit code. We therefore explicitly print it to stdout and |
+ // search for it. |
+ |
+ var args = ['shell', 'sh', '-c', |
Florian Schneider
2016/04/27 09:10:37
For some reason I had to remove "sh -c" and the si
kustermann
2016/04/27 10:36:00
Both seem to work for me, so I changed it.
|
+ "'${shellArgs.join(' ')} ; echo $MARKER \$?'"]; |
+ AdbCommandResult result = await _executeCommandRaw( |
+ "adb", _deviceSpecificArgs(args)); |
+ int exitCode = result.exitCode; |
+ var lines = result |
+ .stdout.split('\n') |
+ .where((line) => line.trim().length > 0) |
+ .toList(); |
+ if (lines.length > 0) { |
+ int index = lines.last.indexOf(MARKER); |
+ assert(index >= 0); |
+ exitCode = int.parse(lines.last.substring(index + MARKER.length).trim()); |
} |
- return _executeCommand("adb", adbArgs); |
+ return new AdbCommandResult( |
+ result.command, result.stdout, result.stderr, exitCode); |
+ } |
+ |
+ Future _adbCommand(List<String> adbArgs) { |
+ return _executeCommand("adb", _deviceSpecificArgs(adbArgs)); |
} |
Future<String> _adbCommandGetOutput(List<String> adbArgs) { |
+ return _executeCommandGetOutput("adb", _deviceSpecificArgs(adbArgs)); |
+ } |
+ |
+ List<String> _deviceSpecificArgs(List<String> adbArgs) { |
if (_deviceId != null) { |
var extendedAdbArgs = ['-s', _deviceId]; |
extendedAdbArgs.addAll(adbArgs); |
adbArgs = extendedAdbArgs; |
} |
- return _executeCommandGetOutput("adb", adbArgs); |
+ return adbArgs; |
} |
} |
@@ -350,3 +391,43 @@ class Intent { |
Intent(this.action, this.package, this.activity, [this.dataUri]); |
} |
+ |
+/** |
+ * Discovers all available devices and supports aquire/release. |
+ */ |
+class AdbDevicePool { |
+ List<AdbDevice> _idleDevices; |
+ List<Completer> _waiter = []; |
+ |
+ AdbDevicePool(this._idleDevices); |
+ |
+ static Future<AdbDevicePool> create() async { |
+ var names = await AdbHelper.listDevices(); |
+ var devices = names.map((id) => new AdbDevice(id)).toList(); |
+ if (devices.length == 0) { |
+ throw new Exception( |
+ 'No android devices found. ' |
+ 'Please make sure "adb devices" shows your device!'); |
+ } |
+ return new AdbDevicePool(devices); |
+ } |
+ |
+ Future<AdbDevice> aquireDevice() async { |
+ if (_idleDevices.length > 0) { |
+ return _idleDevices.removeLast(); |
+ } else { |
+ var completer = new Completer(); |
+ _waiter.add(completer); |
+ return completer.future; |
+ } |
+ } |
+ |
+ void releaseDevice(AdbDevice device) { |
+ if (_waiter.length > 0) { |
+ Completer completer = _waiter.removeLast(); |
+ completer.complete(device); |
+ } else { |
+ _idleDevices.add(device); |
+ } |
+ } |
+} |