Dart: Lazy observatory asset loading. Option to disable the observatory.

Also adds a benchmark to track the startup cost of loading the http
server for the observatory.

R=jamesr@chromium.org

Review URL: https://codereview.chromium.org/1480243004 .
diff --git a/mojo/dart/embedder/dart_controller.cc b/mojo/dart/embedder/dart_controller.cc
index f084120..0b38ef3 100644
--- a/mojo/dart/embedder/dart_controller.cc
+++ b/mojo/dart/embedder/dart_controller.cc
@@ -352,7 +352,8 @@
     // The VM is creating the service isolate.
     if (Dart_IsServiceIsolate(isolate)) {
       service_isolate_spawned_ = true;
-      const intptr_t port = SupportDartMojoIo() ? 0 : -1;
+      const intptr_t port =
+          (SupportDartMojoIo() && observatory_enabled_) ? 0 : -1;
       InitializeDartMojoIo();
       if (!VmService::Setup("127.0.0.1", port)) {
         *error = strdup(VmService::GetErrorMessage());
@@ -504,6 +505,7 @@
 bool DartController::service_isolate_running_ = false;
 bool DartController::service_isolate_spawned_ = false;
 bool DartController::strict_compilation_ = false;
+bool DartController::observatory_enabled_ = true;
 DartControllerServiceConnector* DartController::service_connector_ = nullptr;
 base::Lock DartController::lock_;
 
@@ -709,9 +711,11 @@
 bool DartController::Initialize(
     DartControllerServiceConnector* service_connector,
     bool strict_compilation,
+    bool observatory_enabled,
     const char** extra_args,
     int extra_args_count) {
   service_connector_ = service_connector;
+  observatory_enabled_ = observatory_enabled;
   strict_compilation_ = strict_compilation;
   InitVmIfNeeded(generateEntropy, extra_args, extra_args_count);
   return true;
diff --git a/mojo/dart/embedder/dart_controller.h b/mojo/dart/embedder/dart_controller.h
index 510d14d..8316f08 100644
--- a/mojo/dart/embedder/dart_controller.h
+++ b/mojo/dart/embedder/dart_controller.h
@@ -107,6 +107,7 @@
   // type checking enabled.
   static bool Initialize(DartControllerServiceConnector* service_connector,
                          bool strict_compilation,
+                         bool observatory_enabled,
                          const char** extra_args,
                          int extra_args_count);
 
@@ -166,6 +167,7 @@
   static MojoHandle handle_watcher_producer_handle_;
   static bool initialized_;
   static bool strict_compilation_;
+  static bool observatory_enabled_;
   static bool service_isolate_running_;
   static bool service_isolate_spawned_;
   static DartControllerServiceConnector* service_connector_;
diff --git a/mojo/dart/embedder/vmservice/main.dart b/mojo/dart/embedder/vmservice/main.dart
index 1e360d7..608d34c 100644
--- a/mojo/dart/embedder/vmservice/main.dart
+++ b/mojo/dart/embedder/vmservice/main.dart
@@ -21,7 +21,17 @@
 
 // HTTP server.
 Server server;
-Map<String, Asset> assets;
+Map<String, Asset> _assets;
+Map<String, Asset> get assets {
+  if (_assets == null) {
+    try {
+      _assets = Asset.request();
+    } catch (e) {
+      print('Could not load Observatory assets: $e');
+    }
+  }
+  return _assets;
+}
 
 _onShutdown() {
   if (server != null) {
@@ -34,11 +44,6 @@
 }
 
 void _bootServer() {
-  try {
-    assets = Asset.request();
-  } catch (e) {
-    print('Could not load Observatory assets: $e');
-  }
   // Lazily create service.
   var service = new VMService();
   service.onShutdown = _onShutdown;
@@ -52,11 +57,11 @@
     if (server != null) {
       server.startup();
     }
+    // It's just here to push an event on the event loop so that we invoke the
+    // scheduled microtasks.
+    Timer.run(() {});
   }
   scriptLoadPort.handler = _processLoadRequest;
-  // It's just here to push an event on the event loop so that we invoke the
-  // scheduled microtasks.
-  Timer.run(() {});
   return scriptLoadPort;
 }
 
diff --git a/mojo/tools/data/benchmarks b/mojo/tools/data/benchmarks
index b3fe877..bffe738 100644
--- a/mojo/tools/data/benchmarks
+++ b/mojo/tools/data/benchmarks
@@ -29,6 +29,24 @@
     ]
   },
   {
+    'name': 'dart init no observatory',
+    'app': 'https://core.mojoapps.io/dart_startup.mojo',
+    'duration': 10,
+    'measurements': [
+      {
+        'name': 'initialize',
+        'spec': 'time_until/Dart/initialized'
+      },
+      {
+        'name': 'accept connection',
+        'spec': 'time_between/Dart/initialized/Dart/connected',
+      }
+    ],
+    'shell-args': [
+      '--args-for=mojo:dart_content_handler --disable-observatory',
+    ]
+  },
+  {
     'name': 'cpp init',
     'app': 'https://core.mojoapps.io/trace_me.mojo',
     'duration': 10,
diff --git a/services/dart/content_handler_main.cc b/services/dart/content_handler_main.cc
index e44a0fc..de7a8ac 100644
--- a/services/dart/content_handler_main.cc
+++ b/services/dart/content_handler_main.cc
@@ -29,6 +29,7 @@
 
 const char kCompleteTimeline[] = "--complete-timeline";
 const char kEnableStrictMode[] = "--enable-strict-mode";
+const char kDisableObservatory[] = "--disable-observatory";
 const char kTraceStartup[] = "--trace-startup";
 
 static bool IsDartZip(std::string url) {
@@ -122,8 +123,17 @@
       timeline_arg = kCompleteTimeline;
       timeline_arg_count = 1;
     }
+
+    bool observatory_enabled = true;
+    if (app->HasArg(kDisableObservatory)) {
+      observatory_enabled = false;
+    }
     bool success = mojo::dart::DartController::Initialize(
-        service_connector_, default_strict_, &timeline_arg, timeline_arg_count);
+        service_connector_,
+        default_strict_,
+        observatory_enabled,
+        &timeline_arg,
+        timeline_arg_count);
 
     if (app->HasArg(kTraceStartup)) {
       DartTimelineController::EnableAll();