introduce globals scoped to the app's context
diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart
index e92e058..b6ff950 100644
--- a/packages/flutter_tools/lib/executable.dart
+++ b/packages/flutter_tools/lib/executable.dart
@@ -8,6 +8,8 @@
 import 'package:args/command_runner.dart';
 import 'package:stack_trace/stack_trace.dart';
 
+import 'src/base/context.dart';
+import 'src/base/logger.dart';
 import 'src/base/process.dart';
 import 'src/commands/analyze.dart';
 import 'src/commands/apk.dart';
@@ -27,6 +29,7 @@
 import 'src/commands/test.dart';
 import 'src/commands/trace.dart';
 import 'src/commands/upgrade.dart';
+import 'src/device.dart';
 import 'src/runner/flutter_command_runner.dart';
 
 /// Main entry point for commands.
@@ -62,7 +65,12 @@
     if (args.isNotEmpty && args[0] == 'init')
       args[0] = 'create';
 
+    // Initialize globals.
+    context[Logger] = new StdoutLogger();
+    context[DeviceManager] = new DeviceManager();
+
     dynamic result = await runner.run(args);
+
     if (result is int)
       exit(result);
   }, onError: (error, Chain chain) {
diff --git a/packages/flutter_tools/lib/src/android/adb.dart b/packages/flutter_tools/lib/src/android/adb.dart
index aad03e3..e8b0f94 100644
--- a/packages/flutter_tools/lib/src/android/adb.dart
+++ b/packages/flutter_tools/lib/src/android/adb.dart
@@ -5,7 +5,7 @@
 import 'dart:async';
 import 'dart:io';
 
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 
 // https://android.googlesource.com/platform/system/core/+/android-4.4_r1/adb/OVERVIEW.TXT
diff --git a/packages/flutter_tools/lib/src/android/device_android.dart b/packages/flutter_tools/lib/src/android/device_android.dart
index e0eadf9..c55e0d4 100644
--- a/packages/flutter_tools/lib/src/android/device_android.dart
+++ b/packages/flutter_tools/lib/src/android/device_android.dart
@@ -10,7 +10,7 @@
 
 import '../application_package.dart';
 import '../base/common.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/os.dart';
 import '../base/process.dart';
 import '../build_configuration.dart';
diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart
index 123b752..4d304ed 100644
--- a/packages/flutter_tools/lib/src/artifacts.dart
+++ b/packages/flutter_tools/lib/src/artifacts.dart
@@ -8,7 +8,7 @@
 import 'package:archive/archive.dart';
 import 'package:path/path.dart' as path;
 
-import 'base/context.dart';
+import 'base/globals.dart';
 import 'base/os.dart';
 import 'base/process.dart';
 import 'build_configuration.dart';
diff --git a/packages/flutter_tools/lib/src/base/context.dart b/packages/flutter_tools/lib/src/base/context.dart
index 21054a4..8c1f54d 100644
--- a/packages/flutter_tools/lib/src/base/context.dart
+++ b/packages/flutter_tools/lib/src/base/context.dart
@@ -3,9 +3,8 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:io';
 
-final AppContext _defaultContext = new _DefaultAppContext();
+final AppContext _defaultContext = new AppContext();
 
 /// A singleton for application functionality. This singleton can be different
 /// on a per-Zone basis.
@@ -14,57 +13,42 @@
   return currentContext == null ? _defaultContext : currentContext;
 }
 
-/// Display an error level message to the user. Commands should use this if they
-/// fail in some way.
-void printError(String message, [StackTrace stackTrace]) => context.printError(message, stackTrace);
+class AppContext {
+  Map<Type, dynamic> _instances = <Type, dynamic>{};
 
-/// Display normal output of the command. This should be used for things like
-/// progress messages, success messages, or just normal command output.
-void printStatus(String message) => context.printStatus(message);
+  dynamic getVariable(Type type) {
+    if (_instances.containsKey(type))
+      return _instances[type];
 
-/// Use this for verbose tracing output. Users can turn this output on in order
-/// to help diagnose issues with the toolchain or with their setup.
-void printTrace(String message) => context.printTrace(message);
-
-abstract class AppContext {
-  bool get verbose;
-  set verbose(bool value);
-
-  void printError(String message, [StackTrace stackTrace]);
-  void printStatus(String message);
-  void printTrace(String message);
-}
-
-class _DefaultAppContext implements AppContext {
-  DateTime _startTime = new DateTime.now();
-
-  bool _verbose = false;
-
-  bool get verbose => _verbose;
-
-  set verbose(bool value) {
-    _verbose = value;
+    AppContext parent = _calcParent(Zone.current);
+    return parent?.getVariable(type);
   }
 
-  void printError(String message, [StackTrace stackTrace]) {
-    stderr.writeln(_prefix + message);
-    if (stackTrace != null)
-      stderr.writeln(stackTrace);
+  void setVariable(Type type, dynamic instance) {
+    _instances[type] = instance;
   }
 
-  void printStatus(String message) {
-    print(_prefix + message);
+  dynamic operator[](Type type) => getVariable(type);
+
+  void operator[]=(Type type, dynamic instance) => setVariable(type, instance);
+
+  AppContext _calcParent(Zone zone) {
+    if (this == _defaultContext)
+      return null;
+
+    Zone parentZone = zone.parent;
+    if (parentZone == null)
+      return _defaultContext;
+
+    AppContext deps = parentZone['context'];
+    if (deps == this) {
+      return _calcParent(parentZone);
+    } else {
+      return deps != null ? deps : _defaultContext;
+    }
   }
 
-  void printTrace(String message) {
-    if (_verbose)
-      print('$_prefix- $message');
-  }
-
-  String get _prefix {
-    if (!_verbose)
-      return '';
-    Duration elapsed = new DateTime.now().difference(_startTime);
-    return '[${elapsed.inMilliseconds.toString().padLeft(4)} ms] ';
+  dynamic runInZone(dynamic method()) {
+    return runZoned(method, zoneValues: {'context': this});
   }
 }
diff --git a/packages/flutter_tools/lib/src/base/globals.dart b/packages/flutter_tools/lib/src/base/globals.dart
new file mode 100644
index 0000000..5c86fb2
--- /dev/null
+++ b/packages/flutter_tools/lib/src/base/globals.dart
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import '../device.dart';
+import 'context.dart';
+import 'logger.dart';
+
+DeviceManager get deviceManager => context[DeviceManager];
+Logger get logger => context[Logger];
+
+/// Display an error level message to the user. Commands should use this if they
+/// fail in some way.
+void printError(String message, [StackTrace stackTrace]) => logger.printError(message, stackTrace);
+
+/// Display normal output of the command. This should be used for things like
+/// progress messages, success messages, or just normal command output.
+void printStatus(String message) => logger.printStatus(message);
+
+/// Use this for verbose tracing output. Users can turn this output on in order
+/// to help diagnose issues with the toolchain or with their setup.
+void printTrace(String message) => logger.printTrace(message);
diff --git a/packages/flutter_tools/lib/src/base/logger.dart b/packages/flutter_tools/lib/src/base/logger.dart
new file mode 100644
index 0000000..0489279
--- /dev/null
+++ b/packages/flutter_tools/lib/src/base/logger.dart
@@ -0,0 +1,65 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:io';
+
+abstract class Logger {
+  bool verbose = false;
+
+  /// Display an error level message to the user. Commands should use this if they
+  /// fail in some way.
+  void printError(String message, [StackTrace stackTrace]);
+
+  /// Display normal output of the command. This should be used for things like
+  /// progress messages, success messages, or just normal command output.
+  void printStatus(String message);
+
+  /// Use this for verbose tracing output. Users can turn this output on in order
+  /// to help diagnose issues with the toolchain or with their setup.
+  void printTrace(String message);
+}
+
+class StdoutLogger implements Logger {
+  DateTime _startTime = new DateTime.now();
+
+  bool verbose = false;
+
+  void printError(String message, [StackTrace stackTrace]) {
+    stderr.writeln(_prefix + message);
+    if (stackTrace != null)
+      stderr.writeln(stackTrace);
+  }
+
+  void printStatus(String message) {
+    print(_prefix + message);
+  }
+
+  void printTrace(String message) {
+    if (verbose)
+      print('$_prefix- $message');
+  }
+
+  String get _prefix {
+    if (!verbose)
+      return '';
+    Duration elapsed = new DateTime.now().difference(_startTime);
+    return '[${elapsed.inMilliseconds.toString().padLeft(4)} ms] ';
+  }
+}
+
+class BufferLogger implements Logger {
+  StringBuffer _error = new StringBuffer();
+  StringBuffer _status = new StringBuffer();
+  StringBuffer _trace = new StringBuffer();
+
+  bool verbose = false;
+
+  String get errorText => _error.toString();
+  String get statusText => _status.toString();
+  String get traceText => _trace.toString();
+
+  void printError(String message, [StackTrace stackTrace]) => _error.writeln(message);
+  void printStatus(String message) => _status.writeln(message);
+  void printTrace(String message) => _trace.writeln(message);
+}
diff --git a/packages/flutter_tools/lib/src/base/process.dart b/packages/flutter_tools/lib/src/base/process.dart
index 7da7699..cac6702 100644
--- a/packages/flutter_tools/lib/src/base/process.dart
+++ b/packages/flutter_tools/lib/src/base/process.dart
@@ -6,7 +6,7 @@
 import 'dart:convert';
 import 'dart:io';
 
-import 'context.dart';
+import 'globals.dart';
 
 typedef String StringConverter(String string);
 
diff --git a/packages/flutter_tools/lib/src/build_configuration.dart b/packages/flutter_tools/lib/src/build_configuration.dart
index 82a5bbb..160334b 100644
--- a/packages/flutter_tools/lib/src/build_configuration.dart
+++ b/packages/flutter_tools/lib/src/build_configuration.dart
@@ -6,7 +6,7 @@
 
 import 'package:path/path.dart' as path;
 
-import 'base/context.dart';
+import 'base/globals.dart';
 
 enum BuildType {
   prebuilt,
diff --git a/packages/flutter_tools/lib/src/commands/analyze.dart b/packages/flutter_tools/lib/src/commands/analyze.dart
index 7d6742f..b50b90e 100644
--- a/packages/flutter_tools/lib/src/commands/analyze.dart
+++ b/packages/flutter_tools/lib/src/commands/analyze.dart
@@ -11,7 +11,7 @@
 import 'package:path/path.dart' as path;
 
 import '../artifacts.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 import '../build_configuration.dart';
 import '../runner/flutter_command.dart';
diff --git a/packages/flutter_tools/lib/src/commands/apk.dart b/packages/flutter_tools/lib/src/commands/apk.dart
index 14070c9..f0f728f 100644
--- a/packages/flutter_tools/lib/src/commands/apk.dart
+++ b/packages/flutter_tools/lib/src/commands/apk.dart
@@ -12,8 +12,8 @@
 import '../android/device_android.dart';
 import '../application_package.dart';
 import '../artifacts.dart';
-import '../base/context.dart';
 import '../base/file_system.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 import '../build_configuration.dart';
 import '../device.dart';
diff --git a/packages/flutter_tools/lib/src/commands/build.dart b/packages/flutter_tools/lib/src/commands/build.dart
index 1cfa1b0..5e1f763 100644
--- a/packages/flutter_tools/lib/src/commands/build.dart
+++ b/packages/flutter_tools/lib/src/commands/build.dart
@@ -4,7 +4,7 @@
 
 import 'dart:async';
 
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../flx.dart';
 import '../runner/flutter_command.dart';
 import '../toolchain.dart';
diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart
index 60da5e5..f58bc77 100644
--- a/packages/flutter_tools/lib/src/commands/create.dart
+++ b/packages/flutter_tools/lib/src/commands/create.dart
@@ -11,7 +11,7 @@
 
 import '../android/android.dart' as android;
 import '../artifacts.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 
 class CreateCommand extends Command {
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index 1656d8e..0dee7cc 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -9,6 +9,8 @@
 import '../android/adb.dart';
 import '../android/device_android.dart';
 import '../base/context.dart';
+import '../base/globals.dart';
+import '../base/logger.dart';
 import '../device.dart';
 import '../ios/device_ios.dart';
 import '../ios/simulator.dart';
@@ -33,9 +35,11 @@
   Future<int> runInProject() {
     printStatus('Starting device daemon...');
 
-    NotifyingAppContext appContext = new NotifyingAppContext();
+    AppContext appContext = new AppContext();
+    NotifyingLogger notifyingLogger = new NotifyingLogger();
+    appContext[Logger] = notifyingLogger;
 
-    return runZoned(() {
+    return appContext.runInZone(() {
       Stream<Map<String, dynamic>> commandStream = stdin
         .transform(UTF8.decoder)
         .transform(const LineSplitter())
@@ -47,10 +51,10 @@
 
       Daemon daemon = new Daemon(commandStream, (Map command) {
         stdout.writeln('[${JSON.encode(command, toEncodable: _jsonEncodeObject)}]');
-      }, daemonCommand: this, appContext: appContext);
+      }, daemonCommand: this, notifyingLogger: notifyingLogger);
 
       return daemon.onExit;
-    }, zoneValues: {'context': appContext});
+    });
   }
 
   dynamic _jsonEncodeObject(dynamic object) {
@@ -67,7 +71,7 @@
 class Daemon {
   Daemon(Stream<Map> commandStream, this.sendCommand, {
     this.daemonCommand,
-    this.appContext
+    this.notifyingLogger
   }) {
     // Set up domains.
     _registerDomain(new DaemonDomain(this));
@@ -83,7 +87,7 @@
 
   final DispatchComand sendCommand;
   final DaemonCommand daemonCommand;
-  final NotifyingAppContext appContext;
+  final NotifyingLogger notifyingLogger;
 
   final Completer<int> _onExitCompleter = new Completer<int>();
   final Map<String, Domain> _domainMap = <String, Domain>{};
@@ -185,7 +189,7 @@
     registerHandler('version', version);
     registerHandler('shutdown', shutdown);
 
-    _subscription = daemon.appContext.onMessage.listen((LogMessage message) {
+    _subscription = daemon.notifyingLogger.onMessage.listen((LogMessage message) {
       if (message.stackTrace != null) {
         sendEvent('daemon.logMessage', {
           'level': message.level,
@@ -467,13 +471,11 @@
   return '$obj';
 }
 
-class NotifyingAppContext implements AppContext {
+class NotifyingLogger extends Logger {
   StreamController<LogMessage> _messageController = new StreamController<LogMessage>.broadcast();
 
   Stream<LogMessage> get onMessage => _messageController.stream;
 
-  bool verbose = false;
-
   void printError(String message, [StackTrace stackTrace]) {
     _messageController.add(new LogMessage('error', message, stackTrace));
   }
diff --git a/packages/flutter_tools/lib/src/commands/ios.dart b/packages/flutter_tools/lib/src/commands/ios.dart
index b424981..96f110a 100644
--- a/packages/flutter_tools/lib/src/commands/ios.dart
+++ b/packages/flutter_tools/lib/src/commands/ios.dart
@@ -8,7 +8,7 @@
 import "package:path/path.dart" as path;
 
 import "../artifacts.dart";
-import "../base/context.dart";
+import "../base/globals.dart";
 import "../base/process.dart";
 import "../runner/flutter_command.dart";
 import "../runner/flutter_command_runner.dart";
diff --git a/packages/flutter_tools/lib/src/commands/list.dart b/packages/flutter_tools/lib/src/commands/list.dart
index 885ba15..2eb0437 100644
--- a/packages/flutter_tools/lib/src/commands/list.dart
+++ b/packages/flutter_tools/lib/src/commands/list.dart
@@ -4,7 +4,7 @@
 
 import 'dart:async';
 
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../device.dart';
 import '../runner/flutter_command.dart';
 
@@ -15,9 +15,7 @@
   bool get requiresProjectRoot => false;
 
   Future<int> runInProject() async {
-    DeviceManager deviceManager = new DeviceManager();
-
-    List<Device> devices = await deviceManager.getDevices();
+    List<Device> devices = await deviceManager.getAllConnectedDevices();
 
     if (devices.isEmpty) {
       printStatus('No connected devices.');
diff --git a/packages/flutter_tools/lib/src/commands/listen.dart b/packages/flutter_tools/lib/src/commands/listen.dart
index b139355..4fd76de 100644
--- a/packages/flutter_tools/lib/src/commands/listen.dart
+++ b/packages/flutter_tools/lib/src/commands/listen.dart
@@ -5,7 +5,7 @@
 import 'dart:async';
 import 'dart:io';
 
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 import 'start.dart';
 
diff --git a/packages/flutter_tools/lib/src/commands/logs.dart b/packages/flutter_tools/lib/src/commands/logs.dart
index 0b274d3..3766de2 100644
--- a/packages/flutter_tools/lib/src/commands/logs.dart
+++ b/packages/flutter_tools/lib/src/commands/logs.dart
@@ -4,7 +4,7 @@
 
 import 'dart:async';
 
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../device.dart';
 import '../runner/flutter_command.dart';
 
@@ -24,21 +24,14 @@
 
   Future<int> runInProject() async {
     DeviceManager deviceManager = new DeviceManager();
-    List<Device> devices;
+    deviceManager.specifiedDeviceId = globalResults['device-id'];
 
-    String deviceId = globalResults['device-id'];
-    if (deviceId != null) {
-      Device device = await deviceManager.getDeviceById(deviceId);
-      if (device == null) {
-        printError("No device found with id '$deviceId'.");
-        return 1;
-      }
-      devices = <Device>[device];
-    } else {
-      devices = await deviceManager.getDevices();
-    }
+    List<Device> devices = await deviceManager.getDevices();
 
-    if (devices.isEmpty) {
+    if (devices.isEmpty && deviceManager.hasSpecifiedDeviceId) {
+      printError("No device found with id '${deviceManager.specifiedDeviceId}'.");
+      return 1;
+    } else if (devices.isEmpty) {
       printStatus('No connected devices.');
       return 0;
     }
diff --git a/packages/flutter_tools/lib/src/commands/refresh.dart b/packages/flutter_tools/lib/src/commands/refresh.dart
index 02bb4d5..35ff972 100644
--- a/packages/flutter_tools/lib/src/commands/refresh.dart
+++ b/packages/flutter_tools/lib/src/commands/refresh.dart
@@ -7,7 +7,7 @@
 
 import 'package:path/path.dart' as path;
 
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../flx.dart';
 import '../runner/flutter_command.dart';
 
diff --git a/packages/flutter_tools/lib/src/commands/run_mojo.dart b/packages/flutter_tools/lib/src/commands/run_mojo.dart
index 9acffbc..77dc2a1 100644
--- a/packages/flutter_tools/lib/src/commands/run_mojo.dart
+++ b/packages/flutter_tools/lib/src/commands/run_mojo.dart
@@ -8,7 +8,7 @@
 import 'package:path/path.dart' as path;
 
 import '../artifacts.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 import '../build_configuration.dart';
 import '../flx.dart' as flx;
@@ -118,7 +118,7 @@
     if (useDevtools) {
       final String buildFlag = argResults['mojo-debug'] ? '--debug' : '--release';
       args.add(buildFlag);
-      if (context.verbose)
+      if (logger.verbose)
         args.add('--verbose');
     }
 
diff --git a/packages/flutter_tools/lib/src/commands/start.dart b/packages/flutter_tools/lib/src/commands/start.dart
index ba653b0..9b9259e 100644
--- a/packages/flutter_tools/lib/src/commands/start.dart
+++ b/packages/flutter_tools/lib/src/commands/start.dart
@@ -9,7 +9,7 @@
 
 import '../application_package.dart';
 import '../base/common.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../build_configuration.dart';
 import '../device.dart';
 import '../flx.dart';
diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart
index 127391b..e7ebac2 100644
--- a/packages/flutter_tools/lib/src/commands/test.dart
+++ b/packages/flutter_tools/lib/src/commands/test.dart
@@ -9,7 +9,7 @@
 import 'package:test/src/executable.dart' as executable;
 
 import '../artifacts.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../build_configuration.dart';
 import '../runner/flutter_command.dart';
 import '../test/loader.dart' as loader;
diff --git a/packages/flutter_tools/lib/src/commands/trace.dart b/packages/flutter_tools/lib/src/commands/trace.dart
index d66b741..a40af6d 100644
--- a/packages/flutter_tools/lib/src/commands/trace.dart
+++ b/packages/flutter_tools/lib/src/commands/trace.dart
@@ -6,7 +6,7 @@
 
 import '../android/device_android.dart';
 import '../application_package.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../runner/flutter_command.dart';
 
 class TraceCommand extends FlutterCommand {
diff --git a/packages/flutter_tools/lib/src/commands/upgrade.dart b/packages/flutter_tools/lib/src/commands/upgrade.dart
index b9d249c..5e2a124 100644
--- a/packages/flutter_tools/lib/src/commands/upgrade.dart
+++ b/packages/flutter_tools/lib/src/commands/upgrade.dart
@@ -5,7 +5,7 @@
 import 'dart:async';
 
 import '../artifacts.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 import '../runner/flutter_command.dart';
 import '../runner/version.dart';
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 460ade4..7c865b3 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -7,33 +7,48 @@
 import 'android/device_android.dart';
 import 'application_package.dart';
 import 'base/common.dart';
-import 'base/context.dart';
+import 'base/globals.dart';
 import 'build_configuration.dart';
 import 'ios/device_ios.dart';
 import 'toolchain.dart';
 
 /// A class to get all available devices.
 class DeviceManager {
+  /// Constructing DeviceManagers is cheap; they only do expensive work if some
+  /// of their methods are invoked.
   DeviceManager() {
-    // Init the known discoverers.
+    // Register the known discoverers.
     _deviceDiscoverers.add(new AndroidDeviceDiscovery());
     _deviceDiscoverers.add(new IOSDeviceDiscovery());
     _deviceDiscoverers.add(new IOSSimulatorDiscovery());
+  }
 
-    Future.forEach(_deviceDiscoverers, (DeviceDiscovery discoverer) {
-      if (!discoverer.supportsPlatform)
-        return null;
-      return discoverer.init();
-    }).then((_) {
-      _initedCompleter.complete();
-    }).catchError((error, stackTrace) {
-      _initedCompleter.completeError(error, stackTrace);
-    });
+  Future _init() {
+    if (_initedCompleter == null) {
+      _initedCompleter = new Completer();
+
+      Future.forEach(_deviceDiscoverers, (DeviceDiscovery discoverer) {
+        if (!discoverer.supportsPlatform)
+          return null;
+        return discoverer.init();
+      }).then((_) {
+        _initedCompleter.complete();
+      }).catchError((error, stackTrace) {
+        _initedCompleter.completeError(error, stackTrace);
+      });
+    }
+
+    return _initedCompleter.future;
   }
 
   List<DeviceDiscovery> _deviceDiscoverers = <DeviceDiscovery>[];
 
-  Completer _initedCompleter = new Completer();
+  /// A user-specified device ID.
+  String specifiedDeviceId;
+
+  Completer _initedCompleter;
+
+  bool get hasSpecifiedDeviceId => specifiedDeviceId != null;
 
   /// Return the device with the matching ID; else, complete the Future with
   /// `null`.
@@ -41,15 +56,26 @@
   /// This does a case insentitive compare with `deviceId`.
   Future<Device> getDeviceById(String deviceId) async {
     deviceId = deviceId.toLowerCase();
-    List<Device> devices = await getDevices();
+    List<Device> devices = await getAllConnectedDevices();
     return devices.firstWhere(
       (Device device) => device.id.toLowerCase() == deviceId,
       orElse: () => null
     );
   }
 
+  /// Return the list of connected devices, filtered by any user-specified device id.
   Future<List<Device>> getDevices() async {
-    await _initedCompleter.future;
+    if (specifiedDeviceId == null) {
+      return getAllConnectedDevices();
+    } else {
+      Device device = await getDeviceById(specifiedDeviceId);
+      return device == null ? <Device>[] : <Device>[device];
+    }
+  }
+
+  /// Return the list of all connected devices.
+  Future<List<Device>> getAllConnectedDevices() async {
+    await _init();
 
     return _deviceDiscoverers
       .where((DeviceDiscovery discoverer) => discoverer.supportsPlatform)
diff --git a/packages/flutter_tools/lib/src/flx.dart b/packages/flutter_tools/lib/src/flx.dart
index 2fb6efc..00973bc 100644
--- a/packages/flutter_tools/lib/src/flx.dart
+++ b/packages/flutter_tools/lib/src/flx.dart
@@ -13,7 +13,7 @@
 import 'package:path/path.dart' as path;
 import 'package:yaml/yaml.dart';
 
-import 'base/context.dart';
+import 'base/globals.dart';
 import 'base/file_system.dart';
 import 'toolchain.dart';
 
diff --git a/packages/flutter_tools/lib/src/ios/device_ios.dart b/packages/flutter_tools/lib/src/ios/device_ios.dart
index 321ef61..6ce1789 100644
--- a/packages/flutter_tools/lib/src/ios/device_ios.dart
+++ b/packages/flutter_tools/lib/src/ios/device_ios.dart
@@ -9,7 +9,7 @@
 
 import '../application_package.dart';
 import '../base/common.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 import '../build_configuration.dart';
 import '../device.dart';
diff --git a/packages/flutter_tools/lib/src/ios/simulator.dart b/packages/flutter_tools/lib/src/ios/simulator.dart
index eecd1af..f776382 100644
--- a/packages/flutter_tools/lib/src/ios/simulator.dart
+++ b/packages/flutter_tools/lib/src/ios/simulator.dart
@@ -6,7 +6,7 @@
 import 'dart:convert' show JSON;
 import 'dart:io';
 
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 
 const String _xcrunPath = '/usr/bin/xcrun';
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index 4df0131..2e94cbc 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -8,9 +8,9 @@
 import 'package:args/command_runner.dart';
 
 import '../application_package.dart';
-import '../base/context.dart';
-import '../build_configuration.dart';
 import '../artifacts.dart';
+import '../base/globals.dart';
+import '../build_configuration.dart';
 import '../device.dart';
 import '../toolchain.dart';
 import 'flutter_command_runner.dart';
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
index 65da945..a01c21f 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
@@ -10,7 +10,7 @@
 import 'package:path/path.dart' as path;
 
 import '../artifacts.dart';
-import '../base/context.dart';
+import '../base/globals.dart';
 import '../base/process.dart';
 import '../build_configuration.dart';
 import 'version.dart';
@@ -158,10 +158,15 @@
   }
 
   Future<int> runCommand(ArgResults globalResults) {
-    if (globalResults['verbose'])
-      context.verbose = true;
-
     _globalResults = globalResults;
+
+    // Check for verbose.
+    if (globalResults['verbose'])
+      logger.verbose = true;
+
+    // See if the user specified a specific device.
+    deviceManager.specifiedDeviceId = globalResults['device-id'];
+
     ArtifactStore.flutterRoot = path.normalize(path.absolute(globalResults['flutter-root']));
     if (globalResults.wasParsed('package-root'))
       ArtifactStore.packageRoot = path.normalize(path.absolute(globalResults['package-root']));
diff --git a/packages/flutter_tools/test/android_device_test.dart b/packages/flutter_tools/test/android_device_test.dart
index 13122c3..1d34f1e 100644
--- a/packages/flutter_tools/test/android_device_test.dart
+++ b/packages/flutter_tools/test/android_device_test.dart
@@ -5,11 +5,13 @@
 import 'package:flutter_tools/src/android/device_android.dart';
 import 'package:test/test.dart';
 
+import 'src/test_context.dart';
+
 main() => defineTests();
 
 defineTests() {
   group('android_device', () {
-    test('stores the requested id', () {
+    testUsingContext('stores the requested id', () {
       String deviceId = '1234';
       AndroidDevice device = new AndroidDevice(deviceId);
       expect(device.id, equals(deviceId));
diff --git a/packages/flutter_tools/test/context_test.dart b/packages/flutter_tools/test/context_test.dart
index c7d81e2..74ecb0c 100644
--- a/packages/flutter_tools/test/context_test.dart
+++ b/packages/flutter_tools/test/context_test.dart
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:async';
-
-import 'package:flutter_tools/src/base/context.dart';
+import 'package:flutter_tools/src/base/context.dart' hide context;
+import 'package:flutter_tools/src/base/globals.dart';
+import 'package:flutter_tools/src/base/logger.dart';
 import 'package:test/test.dart';
 
 main() => defineTests();
@@ -12,55 +12,45 @@
 defineTests() {
   group('DeviceManager', () {
     test('error', () async {
-      MockContext mockContext = new MockContext();
+      AppContext context = new AppContext();
+      BufferLogger mockLogger = new BufferLogger();
+      context[Logger] = mockLogger;
 
-      runZoned(() {
+      context.runInZone(() {
         printError('foo bar');
-      }, zoneValues: {'context': mockContext});
+      });
 
-      expect(mockContext.errorText, 'foo bar\n');
-      expect(mockContext.statusText, '');
-      expect(mockContext.traceText, '');
+      expect(mockLogger.errorText, 'foo bar\n');
+      expect(mockLogger.statusText, '');
+      expect(mockLogger.traceText, '');
     });
 
     test('status', () async {
-      MockContext mockContext = new MockContext();
+      AppContext context = new AppContext();
+      BufferLogger mockLogger = new BufferLogger();
+      context[Logger] = mockLogger;
 
-      runZoned(() {
+      context.runInZone(() {
         printStatus('foo bar');
-      }, zoneValues: {'context': mockContext});
+      });
 
-      expect(mockContext.errorText, '');
-      expect(mockContext.statusText, 'foo bar\n');
-      expect(mockContext.traceText, '');
+      expect(mockLogger.errorText, '');
+      expect(mockLogger.statusText, 'foo bar\n');
+      expect(mockLogger.traceText, '');
     });
 
     test('trace', () async {
-      MockContext mockContext = new MockContext();
+      AppContext context = new AppContext();
+      BufferLogger mockLogger = new BufferLogger();
+      context[Logger] = mockLogger;
 
-      runZoned(() {
+      context.runInZone(() {
         printTrace('foo bar');
-      }, zoneValues: {'context': mockContext});
+      });
 
-      expect(mockContext.errorText, '');
-      expect(mockContext.statusText, '');
-      expect(mockContext.traceText, 'foo bar\n');
+      expect(mockLogger.errorText, '');
+      expect(mockLogger.statusText, '');
+      expect(mockLogger.traceText, 'foo bar\n');
     });
   });
 }
-
-class MockContext implements AppContext {
-  bool verbose = false;
-
-  StringBuffer _error = new StringBuffer();
-  StringBuffer _status = new StringBuffer();
-  StringBuffer _trace = new StringBuffer();
-
-  String get errorText => _error.toString();
-  String get statusText => _status.toString();
-  String get traceText => _trace.toString();
-
-  void printError(String message, [StackTrace stackTrace]) => _error.writeln(message);
-  void printStatus(String message) => _status.writeln(message);
-  void printTrace(String message) => _trace.writeln(message);
-}
diff --git a/packages/flutter_tools/test/create_test.dart b/packages/flutter_tools/test/create_test.dart
index 69939aa..4e736d9 100644
--- a/packages/flutter_tools/test/create_test.dart
+++ b/packages/flutter_tools/test/create_test.dart
@@ -11,6 +11,8 @@
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 
+import 'src/test_context.dart';
+
 main() => defineTests();
 
 defineTests() {
@@ -31,7 +33,7 @@
     // TODO(devoncarew): https://github.com/flutter/flutter/issues/1709
     if (Platform.isLinux) {
       // Verify that we create a project that is well-formed.
-      test('flutter-simple', () async {
+      testUsingContext('flutter-simple', () async {
         ArtifactStore.flutterRoot = '../..';
         CreateCommand command = new CreateCommand();
         CommandRunner runner = new CommandRunner('test_flutter', '')
diff --git a/packages/flutter_tools/test/daemon_test.dart b/packages/flutter_tools/test/daemon_test.dart
index d7a771f..7ad73a1 100644
--- a/packages/flutter_tools/test/daemon_test.dart
+++ b/packages/flutter_tools/test/daemon_test.dart
@@ -5,6 +5,8 @@
 import 'dart:async';
 
 import 'package:flutter_tools/src/base/context.dart';
+import 'package:flutter_tools/src/base/globals.dart';
+import 'package:flutter_tools/src/base/logger.dart';
 import 'package:flutter_tools/src/commands/daemon.dart';
 import 'package:mockito/mockito.dart';
 import 'package:test/test.dart';
@@ -16,10 +18,13 @@
 defineTests() {
   group('daemon', () {
     Daemon daemon;
-    NotifyingAppContext appContext;
+    AppContext appContext;
+    NotifyingLogger notifyingLogger;
 
     setUp(() {
-      appContext = new NotifyingAppContext();
+      appContext = new AppContext();
+      notifyingLogger = new NotifyingLogger();
+      appContext[Logger] = notifyingLogger;
     });
 
     tearDown(() {
@@ -33,7 +38,7 @@
       daemon = new Daemon(
         commands.stream,
         (Map<String, dynamic> result) => responses.add(result),
-        appContext: appContext
+        notifyingLogger: notifyingLogger
       );
       commands.add({'id': 0, 'method': 'daemon.version'});
       Map response = await responses.stream.where(_notEvent).first;
@@ -43,13 +48,13 @@
     });
 
     test('daemon.logMessage', () {
-      return runZoned(() async {
+      return appContext.runInZone(() async {
         StreamController<Map<String, dynamic>> commands = new StreamController();
         StreamController<Map<String, dynamic>> responses = new StreamController();
         daemon = new Daemon(
           commands.stream,
           (Map<String, dynamic> result) => responses.add(result),
-          appContext: appContext
+          notifyingLogger: notifyingLogger
         );
         printError('daemon.logMessage test');
         Map<String, dynamic> response = await responses.stream.where((Map<String, dynamic> map) {
@@ -60,7 +65,7 @@
         Map<String, String> logMessage = response['params'];
         expect(logMessage['level'], 'error');
         expect(logMessage['message'], 'daemon.logMessage test');
-      }, zoneValues: {'context': appContext});
+      });
     });
 
     test('daemon.shutdown', () async {
@@ -69,7 +74,7 @@
       daemon = new Daemon(
         commands.stream,
         (Map<String, dynamic> result) => responses.add(result),
-        appContext: appContext
+        notifyingLogger: notifyingLogger
       );
       commands.add({'id': 0, 'method': 'daemon.shutdown'});
       return daemon.onExit.then((int code) {
@@ -87,7 +92,7 @@
         commands.stream,
         (Map<String, dynamic> result) => responses.add(result),
         daemonCommand: command,
-        appContext: appContext
+        notifyingLogger: notifyingLogger
       );
 
       MockDeviceStore mockDevices = command.devices;
@@ -113,7 +118,7 @@
       daemon = new Daemon(
         commands.stream,
         (Map<String, dynamic> result) => responses.add(result),
-        appContext: appContext
+        notifyingLogger: notifyingLogger
       );
       commands.add({'id': 0, 'method': 'device.getDevices'});
       Map response = await responses.stream.where(_notEvent).first;
diff --git a/packages/flutter_tools/test/device_test.dart b/packages/flutter_tools/test/device_test.dart
index 62903bd..dd9b5c6 100644
--- a/packages/flutter_tools/test/device_test.dart
+++ b/packages/flutter_tools/test/device_test.dart
@@ -5,11 +5,13 @@
 import 'package:flutter_tools/src/device.dart';
 import 'package:test/test.dart';
 
+import 'src/test_context.dart';
+
 main() => defineTests();
 
 defineTests() {
   group('DeviceManager', () {
-    test('getDevices', () async {
+    testUsingContext('getDevices', () async {
       // Test that DeviceManager.getDevices() doesn't throw.
       DeviceManager deviceManager = new DeviceManager();
       List<Device> devices = await deviceManager.getDevices();
diff --git a/packages/flutter_tools/test/install_test.dart b/packages/flutter_tools/test/install_test.dart
index c5c8776..f876456 100644
--- a/packages/flutter_tools/test/install_test.dart
+++ b/packages/flutter_tools/test/install_test.dart
@@ -33,7 +33,7 @@
 
       CommandRunner runner = new CommandRunner('test_flutter', '')
         ..addCommand(command);
-      runner.run(['install']).then((int code) => expect(code, equals(0)));
+      return runner.run(['install']).then((int code) => expect(code, equals(0)));
     });
 
     test('returns 0 when iOS is connected and ready for an install', () {
@@ -55,7 +55,7 @@
 
       CommandRunner runner = new CommandRunner('test_flutter', '')
         ..addCommand(command);
-      runner.run(['install']).then((int code) => expect(code, equals(0)));
+      return runner.run(['install']).then((int code) => expect(code, equals(0)));
     });
   });
 }
diff --git a/packages/flutter_tools/test/list_test.dart b/packages/flutter_tools/test/list_test.dart
index 91c05b7..f01949c 100644
--- a/packages/flutter_tools/test/list_test.dart
+++ b/packages/flutter_tools/test/list_test.dart
@@ -10,12 +10,13 @@
 import 'package:test/test.dart';
 
 import 'src/mocks.dart';
+import 'src/test_context.dart';
 
 main() => defineTests();
 
 defineTests() {
   group('list', () {
-    test('returns 0 when called', () {
+    testUsingContext('returns 0 when called', () {
       final String mockCommand = Platform.isWindows ? 'cmd /c echo' : 'echo';
 
       ListCommand command = new ListCommand();
@@ -36,9 +37,8 @@
       // Instead, cause the test to run the echo command.
       when(mockDevices.iOSSimulator.xcrunPath).thenReturn(mockCommand);
 
-      CommandRunner runner = new CommandRunner('test_flutter', '')
-        ..addCommand(command);
-      runner.run(['list']).then((int code) => expect(code, equals(0)));
+      CommandRunner runner = new CommandRunner('test_flutter', '')..addCommand(command);
+      return runner.run(['list']).then((int code) => expect(code, equals(0)));
     });
   });
 }
diff --git a/packages/flutter_tools/test/listen_test.dart b/packages/flutter_tools/test/listen_test.dart
index 18170bb..dcbf122 100644
--- a/packages/flutter_tools/test/listen_test.dart
+++ b/packages/flutter_tools/test/listen_test.dart
@@ -9,12 +9,13 @@
 import 'package:test/test.dart';
 
 import 'src/mocks.dart';
+import 'src/test_context.dart';
 
 main() => defineTests();
 
 defineTests() {
   group('listen', () {
-    test('returns 0 when no device is connected', () {
+    testUsingContext('returns 0 when no device is connected', () {
       ListenCommand command = new ListenCommand(singleRun: true);
       applyMocksToCommand(command);
       MockDeviceStore mockDevices = command.devices;
@@ -24,7 +25,7 @@
       when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
 
       CommandRunner runner = new FlutterCommandRunner()..addCommand(command);
-      runner.run(['listen']).then((int code) => expect(code, equals(0)));
+      return runner.run(['listen']).then((int code) => expect(code, equals(0)));
     });
   });
 }
diff --git a/packages/flutter_tools/test/logs_test.dart b/packages/flutter_tools/test/logs_test.dart
index 1e5590b..2dd67d5 100644
--- a/packages/flutter_tools/test/logs_test.dart
+++ b/packages/flutter_tools/test/logs_test.dart
@@ -8,16 +8,17 @@
 import 'package:test/test.dart';
 
 import 'src/mocks.dart';
+import 'src/test_context.dart';
 
 main() => defineTests();
 
 defineTests() {
   group('logs', () {
-    test('fail with a bad device id', () {
+    testUsingContext('fail with a bad device id', () {
       LogsCommand command = new LogsCommand();
       applyMocksToCommand(command);
       CommandRunner runner = new FlutterCommandRunner()..addCommand(command);
-      runner.run(<String>['-d', 'abc123', 'logs']).then((int code) {
+      return runner.run(<String>['-d', 'abc123', 'logs']).then((int code) {
         expect(code, equals(1));
       });
     });
diff --git a/packages/flutter_tools/test/src/test_context.dart b/packages/flutter_tools/test/src/test_context.dart
new file mode 100644
index 0000000..c5a5d9d
--- /dev/null
+++ b/packages/flutter_tools/test/src/test_context.dart
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:flutter_tools/src/base/context.dart';
+import 'package:flutter_tools/src/base/logger.dart';
+import 'package:flutter_tools/src/device.dart';
+import 'package:test/test.dart';
+
+void testUsingContext(String description, dynamic testMethod(), { Timeout timeout }) {
+  test(description, () {
+    AppContext testContext = new AppContext();
+
+    testContext[Logger] = new BufferLogger();
+    testContext[DeviceManager] = new MockDeviceManager();
+
+    return testContext.runInZone(testMethod);
+  }, timeout: timeout);
+}
+
+class MockDeviceManager implements DeviceManager {
+  String specifiedDeviceId;
+  bool get hasSpecifiedDeviceId => specifiedDeviceId != null;
+
+  Future<List<Device>> getAllConnectedDevices() => new Future.value(<Device>[]);
+  Future<Device> getDeviceById(String deviceId) => new Future.value(null);
+  Future<List<Device>> getDevices() => getAllConnectedDevices();
+}
diff --git a/packages/flutter_tools/test/stop_test.dart b/packages/flutter_tools/test/stop_test.dart
index 40583cd..f700e3b 100644
--- a/packages/flutter_tools/test/stop_test.dart
+++ b/packages/flutter_tools/test/stop_test.dart
@@ -29,7 +29,7 @@
 
       CommandRunner runner = new CommandRunner('test_flutter', '')
         ..addCommand(command);
-      runner.run(['stop']).then((int code) => expect(code, equals(0)));
+      return runner.run(['stop']).then((int code) => expect(code, equals(0)));
     });
 
     test('returns 0 when iOS is connected and ready to be stopped', () {
@@ -48,7 +48,7 @@
 
       CommandRunner runner = new CommandRunner('test_flutter', '')
         ..addCommand(command);
-      runner.run(['stop']).then((int code) => expect(code, equals(0)));
+      return runner.run(['stop']).then((int code) => expect(code, equals(0)));
     });
   });
 }
diff --git a/packages/flutter_tools/test/trace_test.dart b/packages/flutter_tools/test/trace_test.dart
index e55648c..279e7a8 100644
--- a/packages/flutter_tools/test/trace_test.dart
+++ b/packages/flutter_tools/test/trace_test.dart
@@ -8,12 +8,13 @@
 import 'package:test/test.dart';
 
 import 'src/mocks.dart';
+import 'src/test_context.dart';
 
 main() => defineTests();
 
 defineTests() {
   group('trace', () {
-    test('returns 1 when no Android device is connected', () {
+    testUsingContext('returns 1 when no Android device is connected', () {
       TraceCommand command = new TraceCommand();
       applyMocksToCommand(command);
       MockDeviceStore mockDevices = command.devices;
@@ -22,7 +23,7 @@
 
       CommandRunner runner = new CommandRunner('test_flutter', '')
         ..addCommand(command);
-      runner.run(['trace']).then((int code) => expect(code, equals(1)));
+      return runner.run(['trace']).then((int code) => expect(code, equals(1)));
     });
   });
 }