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: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, |
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 ]; |
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 Loading... | |
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', '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.
| |
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) { |
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 Loading... | |
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. | |
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 { | |
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(); | |
428 completer.complete(device); | |
429 } else { | |
430 _idleDevices.add(device); | |
431 } | |
432 } | |
433 } | |
OLD | NEW |