Chromium Code Reviews| OLD | NEW |
|---|---|
| 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:collection"; |
| 11 import "dart:io"; | 11 import "dart:io"; |
| 12 | 12 |
| 13 import "path.dart"; | 13 import "path.dart"; |
| 14 import "utils.dart"; | 14 import "utils.dart"; |
| 15 | 15 |
| 16 class AdbCommandResult { | 16 class AdbCommandResult { |
| 17 final String command; | 17 final String command; |
| 18 final String stdout; | 18 final String stdout; |
| 19 final String stderr; | 19 final String stderr; |
| 20 final int exitCode; | 20 final int exitCode; |
| 21 final bool timedOut; | |
| 21 | 22 |
| 22 AdbCommandResult(this.command, this.stdout, this.stderr, this.exitCode); | 23 AdbCommandResult(this.command, this.stdout, this.stderr, this.exitCode, |
| 24 this.timedOut); | |
| 23 | 25 |
| 24 void throwIfFailed() { | 26 void throwIfFailed() { |
| 25 if (exitCode != 0) { | 27 if (exitCode != 0) { |
| 26 var error = "Running: $command failed:" | 28 var error = "Running: $command failed:" |
| 27 "stdout: \n $stdout" | 29 "stdout:\n ${stdout.trim()}\n" |
| 28 "stderr: \n $stderr" | 30 "stderr:\n ${stderr.trim()}\n" |
| 29 "exitCode: \n $exitCode"; | 31 "exitCode: $exitCode\n" |
| 32 "timedOut: $timedOut"; | |
| 30 throw new Exception(error); | 33 throw new Exception(error); |
| 31 } | 34 } |
| 32 } | 35 } |
| 33 } | 36 } |
| 34 | 37 |
| 35 /** | 38 /** |
| 36 * [_executeCommand] will write [stdin] to the standard input of the created | 39 * [_executeCommand] will write [stdin] to the standard input of the created |
| 37 * process and will return a tuple (stdout, stderr). | 40 * process and will return a tuple (stdout, stderr). |
| 38 * | 41 * |
| 39 * If the exit code of the process was nonzero it will complete with an error. | 42 * If the exit code of the process was nonzero it will complete with an error. |
| 40 * If starting the process failed, it will complete with an error as well. | 43 * If starting the process failed, it will complete with an error as well. |
| 41 */ | 44 */ |
| 42 Future<AdbCommandResult> _executeCommand( | 45 Future<AdbCommandResult> _executeCommand( |
| 43 String executable, List<String> args, [String stdin = ""]) { | 46 String executable, List<String> args, |
| 47 [String stdin = "", Duration timeout]) { | |
|
Bill Hesse
2016/05/02 11:54:17
Should these now be named, not positional, optiona
kustermann
2016/05/02 11:59:40
Done.
| |
| 44 Future<String> getOutput(Stream<List<int>> stream) { | 48 Future<String> getOutput(Stream<List<int>> stream) { |
| 45 return stream | 49 return stream |
| 46 .transform(UTF8.decoder) | 50 .transform(UTF8.decoder) |
| 47 .toList() | 51 .toList() |
| 48 .then((data) => data.join("")); | 52 .then((data) => data.join("")); |
| 49 } | 53 } |
| 50 | 54 |
| 51 return Process.start(executable, args).then((Process process) async { | 55 return Process.start(executable, args).then((Process process) async { |
| 52 if (stdin != null && stdin != '') { | 56 if (stdin != null && stdin != '') { |
| 53 process.stdin.write(stdin); | 57 process.stdin.write(stdin); |
| 54 } | 58 } |
| 55 process.stdin.close(); | 59 process.stdin.close(); |
| 56 | 60 |
| 61 Timer timer; | |
| 62 bool timedOut = false; | |
| 63 if (timeout != null) { | |
| 64 timer = new Timer(timeout, () { | |
| 65 timedOut = true; | |
| 66 process.kill(ProcessSignal.SIGTERM); | |
| 67 timer = null; | |
| 68 }); | |
| 69 } | |
| 70 | |
| 57 var results = await Future.wait([ | 71 var results = await Future.wait([ |
| 58 getOutput(process.stdout), | 72 getOutput(process.stdout), |
| 59 getOutput(process.stderr), | 73 getOutput(process.stderr), |
| 60 process.exitCode | 74 process.exitCode |
| 61 ]); | 75 ]); |
| 76 if (timer != null) timer.cancel(); | |
| 77 | |
| 62 String command = "$executable ${args.join(' ')}"; | 78 String command = "$executable ${args.join(' ')}"; |
| 63 return new AdbCommandResult(command, results[0], results[1], results[2]); | 79 return new AdbCommandResult( |
| 80 command, results[0], results[1], results[2], timedOut); | |
| 64 }); | 81 }); |
| 65 } | 82 } |
| 66 | 83 |
| 67 /** | 84 /** |
| 68 * Helper class to loop through all adb ports. | 85 * Helper class to loop through all adb ports. |
| 69 * | 86 * |
| 70 * The ports come in pairs: | 87 * The ports come in pairs: |
| 71 * - even number: console connection | 88 * - even number: console connection |
| 72 * - odd number: adb connection | 89 * - odd number: adb connection |
| 73 * Note that this code doesn't check if the ports are used. | 90 * Note that this code doesn't check if the ports are used. |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 } | 298 } |
| 282 | 299 |
| 283 /** | 300 /** |
| 284 * Kill all background processes. | 301 * Kill all background processes. |
| 285 */ | 302 */ |
| 286 Future killAll() { | 303 Future killAll() { |
| 287 var arguments = ['shell', 'am', 'kill-all']; | 304 var arguments = ['shell', 'am', 'kill-all']; |
| 288 return _adbCommand(arguments); | 305 return _adbCommand(arguments); |
| 289 } | 306 } |
| 290 | 307 |
| 291 Future<AdbCommandResult> runAdbCommand(List<String> adbArgs) { | 308 Future<AdbCommandResult> runAdbCommand(List<String> adbArgs, |
| 292 return _executeCommand("adb", _deviceSpecificArgs(adbArgs)); | 309 {Duration timeout}) { |
| 310 return _executeCommand("adb", _deviceSpecificArgs(adbArgs), '', timeout); | |
| 293 } | 311 } |
| 294 | 312 |
| 295 Future<AdbCommandResult> runAdbShellCommand(List<String> shellArgs) async { | 313 Future<AdbCommandResult> runAdbShellCommand(List<String> shellArgs, |
| 314 {Duration timeout}) async { | |
| 296 const MARKER = 'AdbShellExitCode: '; | 315 const MARKER = 'AdbShellExitCode: '; |
| 297 | 316 |
| 298 // The exitcode of 'adb shell ...' can be 0 even though the command failed | 317 // 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 | 318 // with a non-zero exit code. We therefore explicitly print it to stdout and |
| 300 // search for it. | 319 // search for it. |
| 301 | 320 |
| 302 var args = ['shell', | 321 var args = ['shell', |
| 303 "${shellArgs.join(' ')} ; echo $MARKER \$?"]; | 322 "${shellArgs.join(' ')} ; echo $MARKER \$?"]; |
| 304 AdbCommandResult result = await _executeCommand( | 323 AdbCommandResult result = await _executeCommand( |
| 305 "adb", _deviceSpecificArgs(args)); | 324 "adb", _deviceSpecificArgs(args), '', timeout); |
| 306 int exitCode = result.exitCode; | 325 int exitCode = result.exitCode; |
| 307 var lines = result | 326 var lines = result |
| 308 .stdout.split('\n') | 327 .stdout.split('\n') |
| 309 .where((line) => line.trim().length > 0) | 328 .where((line) => line.trim().length > 0) |
| 310 .toList(); | 329 .toList(); |
| 311 if (lines.length > 0) { | 330 if (lines.length > 0) { |
| 312 int index = lines.last.indexOf(MARKER); | 331 int index = lines.last.indexOf(MARKER); |
| 313 assert(index >= 0); | 332 if (index >= 0) { |
| 314 exitCode = int.parse(lines.last.substring(index + MARKER.length).trim()); | 333 exitCode = int.parse( |
| 334 lines.last.substring(index + MARKER.length).trim()); | |
| 335 } else { | |
| 336 // In case of timeouts, for example, we won't get the exitcode marker. | |
| 337 assert(result.exitCode != 0); | |
| 338 } | |
| 315 } | 339 } |
| 316 return new AdbCommandResult( | 340 return new AdbCommandResult( |
| 317 result.command, result.stdout, result.stderr, exitCode); | 341 result.command, result.stdout, result.stderr, exitCode, |
| 342 result.timedOut); | |
| 318 } | 343 } |
| 319 | 344 |
| 320 Future<AdbCommandResult> _adbCommand(List<String> adbArgs) async { | 345 Future<AdbCommandResult> _adbCommand(List<String> adbArgs) async { |
| 321 var result = await _executeCommand("adb", _deviceSpecificArgs(adbArgs)); | 346 var result = await _executeCommand("adb", _deviceSpecificArgs(adbArgs)); |
| 322 result.throwIfFailed(); | 347 result.throwIfFailed(); |
| 323 return result; | 348 return result; |
| 324 } | 349 } |
| 325 | 350 |
| 326 List<String> _deviceSpecificArgs(List<String> adbArgs) { | 351 List<String> _deviceSpecificArgs(List<String> adbArgs) { |
| 327 if (_deviceId != null) { | 352 if (_deviceId != null) { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 400 | 425 |
| 401 void releaseDevice(AdbDevice device) { | 426 void releaseDevice(AdbDevice device) { |
| 402 if (_waiter.length > 0) { | 427 if (_waiter.length > 0) { |
| 403 Completer completer = _waiter.removeFirst(); | 428 Completer completer = _waiter.removeFirst(); |
| 404 completer.complete(device); | 429 completer.complete(device); |
| 405 } else { | 430 } else { |
| 406 _idleDevices.add(device); | 431 _idleDevices.add(device); |
| 407 } | 432 } |
| 408 } | 433 } |
| 409 } | 434 } |
| OLD | NEW |