[flutter,dart] Remove dependence on system-temp

Needs https://github.com/flutter/flutter/commit/b18a2b1794606a6cddb6d7f3486557e473e3bfbb
to roll in from flutter/flutter.

TEST=run_vmservice_object_tests.sh,manual,CQ

Change-Id: Ifb7b42e9e38ed5757a7a11aeadfd579943cf8d56
diff --git a/examples/test/driver_example_mod/meta/driver_example_mod_target_tests.cmx b/examples/test/driver_example_mod/meta/driver_example_mod_target_tests.cmx
index 2b78faf..7459634 100644
--- a/examples/test/driver_example_mod/meta/driver_example_mod_target_tests.cmx
+++ b/examples/test/driver_example_mod/meta/driver_example_mod_target_tests.cmx
@@ -8,7 +8,10 @@
             "system-temp"
         ],
         "services": [
+            "fuchsia.process.Resolver",
             "fuchsia.sys.Environment"
-        ]
+        ],
+        "pkgfs": [ "packages" ],
+        "system": [ "bin" ]
     }
 }
diff --git a/packages/tests/dart_target_unittests b/packages/tests/dart_target_unittests
index ae3545a..44cdb69 100644
--- a/packages/tests/dart_target_unittests
+++ b/packages/tests/dart_target_unittests
@@ -3,6 +3,7 @@
         "//topaz/public/dart-pkg/zircon:dart_zircon_test",
         "//topaz/public/dart/fuchsia_modular:fuchsia_modular_package_integration_tests",
         "//topaz/public/dart/fuchsia_services:fuchsia_services_package_integration_tests",
-        "//topaz/public/dart/fuchsia_vfs:fuchsia_vfs_package_unittests"
+        "//topaz/public/dart/fuchsia_vfs:fuchsia_vfs_package_unittests",
+        "//topaz/runtime/dart/utils:run_vmservice_object_tests"
     ]
 }
diff --git a/public/lib/fuchsia_driver/lib/fuchsia_driver.dart b/public/lib/fuchsia_driver/lib/fuchsia_driver.dart
index 56a4a5e..88f9b90 100644
--- a/public/lib/fuchsia_driver/lib/fuchsia_driver.dart
+++ b/public/lib/fuchsia_driver/lib/fuchsia_driver.dart
@@ -15,9 +15,6 @@
 import 'package:flutter_driver/flutter_driver.dart';
 import 'package:fuchsia_remote_debug_protocol/fuchsia_remote_debug_protocol.dart';
 
-// TODO(DX-291): Update this to use the hub.
-final Directory _kDartPortDir = new Directory('/tmp/dart.services');
-
 /// Convenience method for driving an `Isolate` by pattern.
 ///
 /// Accepts a [FuchsiaRemoteConnection] that will be used to search for the
@@ -89,14 +86,18 @@
 
   @override
   Future<List<String>> run(String command) async {
+    if (command.contains('"') || command.contains("'")) {
+      log.warning("The command runner does not support quotes: '$command'");
+      return <String>[];
+    }
     try {
-      return new List<String>.of(_kDartPortDir
-          .listSync(recursive: false, followLinks: false)
-          .map((FileSystemEntity entity) => entity.path
-              .replaceAll(entity.parent.path, '')
-              .replaceFirst(Platform.pathSeparator, '')));
-    } on FileSystemException catch (e) {
-      log.warning('Error listing directory: $e');
+      final List<String> splitCommand = command.split(' ');
+      final String exe = splitCommand[0];
+      final List<String> args = splitCommand.skip(1).toList();
+      final ProcessResult r = Process.runSync(exe, args);
+      return r.stdout.split('\n');
+    } on ProcessException catch (e) {
+      log.warning("Error running '$command': $e");
     }
     return <String>[];
   }
diff --git a/runtime/dart/utils/BUILD.gn b/runtime/dart/utils/BUILD.gn
index 48ee3f4..7d17da3 100644
--- a/runtime/dart/utils/BUILD.gn
+++ b/runtime/dart/utils/BUILD.gn
@@ -2,10 +2,16 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/package.gni")
+
 source_set("utils") {
   sources = [
     "handle_exception.cc",
     "handle_exception.h",
+    "tempfs.cc",
+    "tempfs.h",
+    "vmservice_object.cc",
+    "vmservice_object.h",
   ]
 
   public_deps = [
@@ -17,7 +23,25 @@
     "//garnet/public/lib/fsl",
     "//garnet/public/lib/fxl",
     "//third_party/tonic",
+    "//topaz/lib/deprecated_loop",
     "//zircon/public/fidl/fuchsia-crash",
     "//zircon/public/fidl/fuchsia-mem",
+    "//zircon/public/lib/memfs",
+  ]
+}
+
+package("run_vmservice_object_tests") {
+  testonly = true
+
+  deps = [
+    "../../dart_runner:dart_jit_runner",
+    "../../dart_runner/examples/hello_dart:hello_dart_jit",
+  ]
+
+  tests = [
+    {
+      name = rebase_path("run_vmservice_object_tests.sh")
+      dest = "run_vmservice_object_tests.sh"
+    },
   ]
 }
diff --git a/runtime/dart/utils/run_vmservice_object_tests.sh b/runtime/dart/utils/run_vmservice_object_tests.sh
new file mode 100644
index 0000000..5a8316c
--- /dev/null
+++ b/runtime/dart/utils/run_vmservice_object_tests.sh
@@ -0,0 +1,30 @@
+#!/boot/bin/sh
+
+set -x
+
+# Kill any existing dart runners.
+killall dart* || true
+
+# Start up a dart runner app that is guaranteed to be JIT, non-product, and
+# won't terminate.
+run hello_dart_jit &
+
+# Wait for it to come up.
+sleep 2
+
+# Find the path to its vm service port.
+# NB: This is the command used by the Flutter host-side command line tools.
+# If the use of 'find' here breaks, the Flutter host-side command line tools
+# will also be broken. If this is intentional, then craft and land a Flutter PR.
+# See: https://github.com/flutter/flutter/commit/b18a2b1794606a6cddb6d7f3486557e473e3bfbb
+# Then, land a hard transition to GI that updates Flutter and this test.
+FIND_RESULT=`find /hub -name vmservice-port | grep dart_jit_runner`
+
+echo "find result:\n${FIND_RESULT}"
+
+killall dart* || true
+if [ -z "${FIND_RESULT}" ]; then
+  echo "FAILURE: Dart VM service not found in the Hub!"
+  exit 1
+fi
+exit 0
diff --git a/runtime/dart/utils/tempfs.cc b/runtime/dart/utils/tempfs.cc
new file mode 100644
index 0000000..a67c60c
--- /dev/null
+++ b/runtime/dart/utils/tempfs.cc
@@ -0,0 +1,83 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tempfs.h"
+
+#include <string>
+#include <thread>
+
+#include <lib/fdio/namespace.h>
+#include <lib/fxl/logging.h>
+#include <lib/memfs/memfs.h>
+#include <zircon/errors.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+
+#include "topaz/lib/deprecated_loop/message_loop.h"
+
+namespace {
+
+constexpr char kTmpPath[] = "/tmp";
+constexpr size_t kMaxTmpPages = 1024;
+
+void DispatchTempMemFS() {
+  deprecated_loop::MessageLoop loop;
+  zx_status_t status = memfs_install_at_with_page_limit(
+      loop.dispatcher(), kMaxTmpPages, kTmpPath);
+  if (status != ZX_OK) {
+    FXL_LOG(ERROR) << "Failed to install a /tmp memfs: "
+                   << zx_status_get_string(status);
+    return;
+  }
+  loop.Run();
+}
+
+}  // namespace
+
+namespace fuchsia {
+namespace dart {
+
+// Set up a memfs bound to /tmp in the process-wide namespace that has the
+// lifetime of the process.
+void SetupRunnerTemp() {
+  std::thread thread(DispatchTempMemFS);
+  thread.detach();
+}
+
+void SetupComponentTemp(fdio_ns_t* ns) {
+  // TODO(zra): Should isolates share a /tmp file system within a process, or
+  // should isolates each get their own private memfs for /tmp? For now,
+  // sharing the process-wide /tmp simplifies hot reload since the hot reload
+  // devfs requires sharing between the service isolate and the app isolates.
+  zx_status_t status;
+  fdio_flat_namespace_t* rootns;
+  status = fdio_ns_export_root(&rootns);
+  if (status != ZX_OK) {
+    FXL_LOG(ERROR) << "Failed to export root ns: "
+                   << zx_status_get_string(status);
+    return;
+  }
+
+  zx_handle_t tmp_dir_handle;
+  for (size_t i = 0; i < rootns->count; i++) {
+    if (strcmp(rootns->path[i], kTmpPath) == 0) {
+      tmp_dir_handle = rootns->handle[i];
+    } else {
+      zx_handle_close(rootns->handle[i]);
+      rootns->handle[i] = ZX_HANDLE_INVALID;
+    }
+  }
+  free(rootns);
+  rootns = nullptr;
+
+  status = fdio_ns_bind(ns, kTmpPath, tmp_dir_handle);
+  if (status != ZX_OK) {
+    zx_handle_close(tmp_dir_handle);
+    FXL_LOG(ERROR) << "Failed to bind /tmp directory into isolate namespace: "
+                   << zx_status_get_string(status);
+  }
+}
+
+}  // namespace dart
+}  // namespace fuchsia
diff --git a/runtime/dart/utils/tempfs.h b/runtime/dart/utils/tempfs.h
new file mode 100644
index 0000000..1e1f154
--- /dev/null
+++ b/runtime/dart/utils/tempfs.h
@@ -0,0 +1,26 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOPAZ_RUNTIME_DART_UTILS_TEMPFS_H_
+#define TOPAZ_RUNTIME_DART_UTILS_TEMPFS_H_
+
+#include <lib/fdio/namespace.h>
+
+// Utility functions that set up /tmp for the dart_runner and flutter_runner.
+
+namespace fuchsia {
+namespace dart {
+
+// Set up a memfs bound to /tmp in the process-wide namespace that has the
+// lifetime of the process.
+void SetupRunnerTemp();
+
+// Take the memfs mapped into the process-wide namespace for /tmp, and map it to
+// /tmp in the given namespace.
+void SetupComponentTemp(fdio_ns_t* ns);
+
+}  // namespace dart
+}  // namespace fuchsia
+
+#endif  // TOPAZ_RUNTIME_DART_UTILS_TEMPFS_H_
diff --git a/runtime/dart/utils/vmservice_object.cc b/runtime/dart/utils/vmservice_object.cc
new file mode 100644
index 0000000..2c1fd21
--- /dev/null
+++ b/runtime/dart/utils/vmservice_object.cc
@@ -0,0 +1,48 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "topaz/runtime/dart/utils/vmservice_object.h"
+
+#include <errno.h>
+#include <zircon/status.h>
+
+#include "lib/component/cpp/exposed_object.h"
+#include "lib/fxl/files/directory.h"
+#include "lib/fxl/files/file.h"
+
+namespace fuchsia {
+namespace dart {
+
+VMServiceObject::VMServiceObject() : ExposedObject(kDirName) {
+  // This code exposes the contents of /${kPortDir} in the hub for the
+  // dart_runner at /hub/.../out/objects/${kDirName}/${kPortDirName}.
+  object_dir().set_children_callback(component::ObjectPath{kPortDirName},
+      [](component::Object::ObjectVector* out_children){
+    // List /tmp/dart.services if it exists, and push its contents as
+    // component::Objects onto out_children.
+    std::vector<std::string> files;
+    if (!files::ReadDirContents(kPortDir, &files)) {
+      FXL_LOG(ERROR) << "Failed to read Dart VM Service port directory '"
+                     << kPortDir << "':"
+                     << strerror(errno);
+      return;
+    }
+    for (const auto& file : files) {
+      if ((file == ".") || (file == "..")) {
+        continue;
+      }
+      out_children->push_back(component::ObjectDir::Make(file).object());
+    }
+  });
+}
+
+std::unique_ptr<VMServiceObject> VMServiceObject::Create(
+    component::ObjectDir* object_dir) {
+  auto vmservice = std::make_unique<VMServiceObject>();
+  vmservice->set_parent(*object_dir);
+  return vmservice;
+}
+
+}  // namespace dart
+}  // namespace fuchsia
diff --git a/runtime/dart/utils/vmservice_object.h b/runtime/dart/utils/vmservice_object.h
new file mode 100644
index 0000000..68c3124
--- /dev/null
+++ b/runtime/dart/utils/vmservice_object.h
@@ -0,0 +1,28 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOPAZ_RUNTIME_DART_UTILS_VMSERVICE_OBJECT_H_
+#define TOPAZ_RUNTIME_DART_UTILS_VMSERVICE_OBJECT_H_
+
+#include "lib/component/cpp/exposed_object.h"
+
+namespace fuchsia {
+namespace dart {
+
+class VMServiceObject : public component::ExposedObject {
+ public:
+  static constexpr const char* kDirName = "DartVM";
+  static constexpr const char* kPortDirName = "vmservice-port";
+  static constexpr const char* kPortDir = "/tmp/dart.services";
+
+  VMServiceObject();
+
+  static std::unique_ptr<VMServiceObject> Create(
+      component::ObjectDir* object_dir);
+};
+
+}  // namespace dart
+}  // namespace fuchsia
+
+#endif  // TOPAZ_RUNTIME_UTILS_VMSERVICE_OBJECT_H_
diff --git a/runtime/dart_runner/BUILD.gn b/runtime/dart_runner/BUILD.gn
index a376230..f76ecbe 100644
--- a/runtime/dart_runner/BUILD.gn
+++ b/runtime/dart_runner/BUILD.gn
@@ -50,6 +50,7 @@
              "//topaz/lib/deprecated_loop",
              "//topaz/runtime/dart/utils",
              "//third_party/tonic",
+             "//topaz/lib/deprecated_loop",
              "//topaz/public/dart-pkg/fuchsia",
              "//zircon/public/lib/trace-provider",
            ] + dart_deps + extra_deps
diff --git a/runtime/dart_runner/dart_component_controller.cc b/runtime/dart_runner/dart_component_controller.cc
index eedceaf..1a2a44e 100644
--- a/runtime/dart_runner/dart_component_controller.cc
+++ b/runtime/dart_runner/dart_component_controller.cc
@@ -29,6 +29,7 @@
 #include "third_party/tonic/logging/dart_error.h"
 #include "topaz/lib/deprecated_loop/message_loop.h"
 #include "topaz/runtime/dart/utils/handle_exception.h"
+#include "topaz/runtime/dart/utils/tempfs.h"
 
 #include "builtin_libraries.h"
 
@@ -117,6 +118,7 @@
   return true;
 }
 
+constexpr char kTmpPath[] = "/tmp";
 constexpr char kServiceRootPath[] = "/svc";
 
 bool DartComponentController::SetupNamespace() {
@@ -127,8 +129,12 @@
     return false;
   }
 
+  fuchsia::dart::SetupComponentTemp(namespace_);
+
   for (size_t i = 0; i < flat->paths->size(); ++i) {
-    if (flat->paths->at(i) == kServiceRootPath) {
+    if ((flat->paths->at(i) == kTmpPath) ||
+        (flat->paths->at(i) == kServiceRootPath)) {
+      // /tmp is covered by the local memfs.
       // Ownership of /svc goes to the StartupContext created below.
       continue;
     }
@@ -138,7 +144,7 @@
     status = fdio_ns_bind(namespace_, path, dir_handle);
     if (status != ZX_OK) {
       FXL_LOG(ERROR) << "Failed to bind " << flat->paths->at(i)
-                     << " to namespace";
+                     << " to namespace: " << zx_status_get_string(status);
       zx_handle_close(dir_handle);
       return false;
     }
diff --git a/runtime/dart_runner/dart_runner.cc b/runtime/dart_runner/dart_runner.cc
index 64e146e..feb2655 100644
--- a/runtime/dart_runner/dart_runner.cc
+++ b/runtime/dart_runner/dart_runner.cc
@@ -4,9 +4,11 @@
 
 #include "topaz/runtime/dart_runner/dart_runner.h"
 
+#include <errno.h>
 #include <sys/stat.h>
 #include <thread>
 #include <utility>
+#include <zircon/status.h>
 #include <zircon/syscalls.h>
 
 #include "lib/fxl/arraysize.h"
@@ -16,6 +18,7 @@
 #include "topaz/lib/deprecated_loop/message_loop.h"
 #include "topaz/runtime/dart_runner/dart_component_controller.h"
 #include "topaz/runtime/dart_runner/service_isolate.h"
+#include "topaz/runtime/dart/utils/vmservice_object.h"
 
 #if defined(AOT_RUNTIME)
 extern "C" uint8_t _kDartVmSnapshotData[];
@@ -147,6 +150,15 @@
         bindings_.AddBinding(this, std::move(request));
       });
 
+#if !defined(DART_PRODUCT)
+  // The VM service isolate uses the process-wide namespace. It writes the
+  // vm service protocol port under /tmp. The VMServiceObject exposes that
+  // port number to The Hub.
+  vmservice_object_ = fuchsia::dart::VMServiceObject::Create(
+      context_->outgoing().object_dir());
+
+#endif  // !defined(DART_PRODUCT)
+
   dart::bin::BootstrapDartIo();
 
   char* error = Dart_SetVMFlags(arraysize(kDartVMArgs), kDartVMArgs);
diff --git a/runtime/dart_runner/dart_runner.h b/runtime/dart_runner/dart_runner.h
index 3259d4d..38cbf60 100644
--- a/runtime/dart_runner/dart_runner.h
+++ b/runtime/dart_runner/dart_runner.h
@@ -12,6 +12,7 @@
 #include "lib/fxl/macros.h"
 #include "topaz/lib/deprecated_loop/message_loop.h"
 #include "topaz/runtime/dart_runner/mapped_resource.h"
+#include "topaz/runtime/dart/utils/vmservice_object.h"
 
 namespace dart_runner {
 
@@ -48,6 +49,12 @@
   deprecated_loop::MessageLoop* loop_;
   fidl::BindingSet<fuchsia::sys::Runner> bindings_;
   std::vector<ControllerToken*> controllers_;
+
+#if !defined(DART_PRODUCT)
+  // The connection between the Dart VM service and The Hub.
+  std::unique_ptr<fuchsia::dart::VMServiceObject> vmservice_object_;
+#endif  // !defined(DART_PRODUCT)
+
 #if !defined(AOT_RUNTIME)
   MappedResource vm_snapshot_data_;
   MappedResource vm_snapshot_instructions_;
diff --git a/runtime/dart_runner/main.cc b/runtime/dart_runner/main.cc
index 615def9..5f86029 100644
--- a/runtime/dart_runner/main.cc
+++ b/runtime/dart_runner/main.cc
@@ -6,10 +6,12 @@
 
 #include "topaz/lib/deprecated_loop/message_loop.h"
 #include "topaz/runtime/dart_runner/dart_runner.h"
+#include "topaz/runtime/dart/utils/tempfs.h"
 
 int main(int argc, const char** argv) {
   deprecated_loop::MessageLoop loop;
   trace::TraceProvider provider(loop.dispatcher());
+  fuchsia::dart::SetupRunnerTemp();
   dart_runner::DartRunner runner;
   loop.Run();
   return 0;
diff --git a/runtime/dart_runner/meta/dart_aot_runner.cmx b/runtime/dart_runner/meta/dart_aot_runner.cmx
index 3ae3201..2f4c2ab 100644
--- a/runtime/dart_runner/meta/dart_aot_runner.cmx
+++ b/runtime/dart_runner/meta/dart_aot_runner.cmx
@@ -4,8 +4,7 @@
     },
     "sandbox": {
         "features": [
-            "root-ssl-certificates",
-            "system-temp"
+            "root-ssl-certificates"
         ],
         "services": [
             "fuchsia.net.LegacySocketProvider",
diff --git a/runtime/dart_runner/meta/dart_dbc_runner.cmx b/runtime/dart_runner/meta/dart_dbc_runner.cmx
index 3ae3201..2f4c2ab 100644
--- a/runtime/dart_runner/meta/dart_dbc_runner.cmx
+++ b/runtime/dart_runner/meta/dart_dbc_runner.cmx
@@ -4,8 +4,7 @@
     },
     "sandbox": {
         "features": [
-            "root-ssl-certificates",
-            "system-temp"
+            "root-ssl-certificates"
         ],
         "services": [
             "fuchsia.net.LegacySocketProvider",
diff --git a/runtime/dart_runner/meta/dart_jit_runner.cmx b/runtime/dart_runner/meta/dart_jit_runner.cmx
index 3ae3201..2f4c2ab 100644
--- a/runtime/dart_runner/meta/dart_jit_runner.cmx
+++ b/runtime/dart_runner/meta/dart_jit_runner.cmx
@@ -4,8 +4,7 @@
     },
     "sandbox": {
         "features": [
-            "root-ssl-certificates",
-            "system-temp"
+            "root-ssl-certificates"
         ],
         "services": [
             "fuchsia.net.LegacySocketProvider",
diff --git a/runtime/dart_runner/meta/dart_zircon_test.cmx b/runtime/dart_runner/meta/dart_zircon_test.cmx
index 07e1961..531309e 100644
--- a/runtime/dart_runner/meta/dart_zircon_test.cmx
+++ b/runtime/dart_runner/meta/dart_zircon_test.cmx
@@ -4,8 +4,7 @@
     },
     "sandbox": {
         "features": [
-            "root-ssl-certificates",
-            "system-temp"
+            "root-ssl-certificates"
         ],
         "services": [
             "fuchsia.sys.Environment"
diff --git a/runtime/flutter_runner/BUILD.gn b/runtime/flutter_runner/BUILD.gn
index 1671840..0914505 100644
--- a/runtime/flutter_runner/BUILD.gn
+++ b/runtime/flutter_runner/BUILD.gn
@@ -146,6 +146,7 @@
              "//topaz/lib/deprecated_loop",
              "//topaz/public/dart-pkg/fuchsia",
              "//topaz/public/lib/ui/flutter/sdk_ext",
+             "//topaz/runtime/dart/utils",
              "//zircon/public/lib/trace-provider",
            ] + extra_deps + flutter_deps
 
diff --git a/runtime/flutter_runner/component.cc b/runtime/flutter_runner/component.cc
index 6da152b..53204c3 100644
--- a/runtime/flutter_runner/component.cc
+++ b/runtime/flutter_runner/component.cc
@@ -18,6 +18,7 @@
 #include "lib/fsl/vmo/vector.h"
 #include "lib/fxl/command_line.h"
 #include "task_observers.h"
+#include "topaz/runtime/dart/utils/tempfs.h"
 
 namespace flutter {
 
@@ -104,10 +105,13 @@
     return;
   }
 
+  // Setup /tmp to be mapped to the process-local memfs.
+  fuchsia::dart::SetupComponentTemp(fdio_ns_.get());
+
   // LaunchInfo::flat_namespace optional.
   for (size_t i = 0; i < startup_info.flat_namespace.paths->size(); ++i) {
     const auto& path = startup_info.flat_namespace.paths->at(i);
-    if (path == "/svc") {
+    if (path == "/tmp" || path == "/svc") {
       continue;
     }
 
diff --git a/runtime/flutter_runner/main.cc b/runtime/flutter_runner/main.cc
index e0cb72f..6e67b43 100644
--- a/runtime/flutter_runner/main.cc
+++ b/runtime/flutter_runner/main.cc
@@ -7,6 +7,7 @@
 
 #include "runner.h"
 #include "topaz/lib/deprecated_loop/message_loop.h"
+#include "topaz/runtime/dart/utils/tempfs.h"
 
 int main(int argc, char const* argv[]) {
   deprecated_loop::MessageLoop loop;
@@ -14,6 +15,9 @@
   trace::TraceProvider provider(loop.dispatcher());
   FML_DCHECK(provider.is_valid()) << "Trace provider must be valid.";
 
+  // Set up the process-wide /tmp memfs.
+  fuchsia::dart::SetupRunnerTemp();
+
   FML_DLOG(INFO) << "Flutter application services initialized.";
 
   flutter::Runner runner;
diff --git a/runtime/flutter_runner/meta/flutter_aot_runner.cmx b/runtime/flutter_runner/meta/flutter_aot_runner.cmx
index e0333d5..a2e58c3 100644
--- a/runtime/flutter_runner/meta/flutter_aot_runner.cmx
+++ b/runtime/flutter_runner/meta/flutter_aot_runner.cmx
@@ -5,7 +5,6 @@
     "sandbox": {
         "features": [
             "root-ssl-certificates",
-            "system-temp",
             "vulkan"
         ],
         "services": [
diff --git a/runtime/flutter_runner/meta/flutter_jit_runner.cmx b/runtime/flutter_runner/meta/flutter_jit_runner.cmx
index e0333d5..a2e58c3 100644
--- a/runtime/flutter_runner/meta/flutter_jit_runner.cmx
+++ b/runtime/flutter_runner/meta/flutter_jit_runner.cmx
@@ -5,7 +5,6 @@
     "sandbox": {
         "features": [
             "root-ssl-certificates",
-            "system-temp",
             "vulkan"
         ],
         "services": [
diff --git a/runtime/flutter_runner/runner.cc b/runtime/flutter_runner/runner.cc
index 3a9bd42..f099db4 100644
--- a/runtime/flutter_runner/runner.cc
+++ b/runtime/flutter_runner/runner.cc
@@ -4,6 +4,7 @@
 
 #include "runner.h"
 
+#include <zircon/status.h>
 #include <zircon/types.h>
 
 #include <sstream>
@@ -15,6 +16,7 @@
 #include "lib/icu_data/cpp/icu_data.h"
 #include "third_party/flutter/runtime/dart_vm.h"
 #include "third_party/skia/include/core/SkGraphics.h"
+#include "topaz/runtime/dart/utils/vmservice_object.h"
 
 namespace flutter {
 
@@ -37,6 +39,14 @@
 
 Runner::Runner()
     : host_context_(component::StartupContext::CreateFromStartupInfo()) {
+#if !defined(DART_PRODUCT)
+  // The VM service isolate uses the process-wide namespace. It writes the
+  // vm service protocol port under /tmp. The VMServiceObject exposes that
+  // port number to The Hub.
+  vmservice_object_ = fuchsia::dart::VMServiceObject::Create(
+      host_context_->outgoing().object_dir());
+#endif  // !defined(DART_PRODUCT)
+
   SkGraphics::Init();
 
   SetupICU();
diff --git a/runtime/flutter_runner/runner.h b/runtime/flutter_runner/runner.h
index 819b08d..06813b5 100644
--- a/runtime/flutter_runner/runner.h
+++ b/runtime/flutter_runner/runner.h
@@ -15,6 +15,7 @@
 #include "lib/component/cpp/startup_context.h"
 #include "lib/fidl/cpp/binding_set.h"
 #include "topaz/lib/deprecated_loop/message_loop.h"
+#include "topaz/runtime/dart/utils/vmservice_object.h"
 
 namespace flutter {
 
@@ -44,6 +45,11 @@
   std::unordered_map<const Application*, ActiveApplication>
       active_applications_;
 
+#if !defined(DART_PRODUCT)
+  // The connection between the Dart VM service and The Hub.
+  std::unique_ptr<fuchsia::dart::VMServiceObject> vmservice_object_;
+#endif  // !defined(DART_PRODUCT)
+
   // |fuchsia::sys::Runner|
   void StartComponent(fuchsia::sys::Package package,
                       fuchsia::sys::StartupInfo startup_info,