[dart-sdk] Add connectToService, wrapping fdio_ns_connect.

Use fdio_ns_connect to connect to services in a namespace. For pure
persistant fidl services the old path of creating a file descriptor and
then opening a channel to that file descriptor doesn't work.

We should provide a way to directly connect to a service without first
treating it as a file.

Test:
* workstation.frank, reboot button on main menu works.
* astro, device_settings "erase user data" reboot works.

Change-Id: I725ba9350547309bebb5530aa44236f841d88f99
diff --git a/bin/device_settings/BUILD.gn b/bin/device_settings/BUILD.gn
index 00b6d93..0787e8c 100644
--- a/bin/device_settings/BUILD.gn
+++ b/bin/device_settings/BUILD.gn
@@ -29,5 +29,6 @@
     "//topaz/public/dart/fuchsia_logger",
     "//topaz/public/dart/fuchsia_services",
     "//topaz/public/dart/widgets:lib.widgets",
+    "//zircon/public/fidl/fuchsia-device-manager",
   ]
 }
diff --git a/bin/device_settings/lib/src/model.dart b/bin/device_settings/lib/src/model.dart
index d18a41d..5f65f0d 100644
--- a/bin/device_settings/lib/src/model.dart
+++ b/bin/device_settings/lib/src/model.dart
@@ -4,7 +4,9 @@
 
 import 'dart:async';
 
+import 'package:fidl/fidl.dart';
 import 'package:fidl_fuchsia_amber/fidl_async.dart' as amber;
+import 'package:fidl_fuchsia_device_manager/fidl_async.dart' as devmgr;
 import 'package:flutter/foundation.dart';
 import 'package:fuchsia_logger/logger.dart';
 import 'package:fuchsia_services/services.dart';
@@ -123,10 +125,30 @@
       final flagSet = await DeviceInfo.setFactoryResetFlag(shouldReset: true);
       log.severe('Factory Reset flag set successfully: $flagSet');
 
-      int status = System.reboot();
-      if (status != 0 ) {
-        log.severe('Unable to reboot system: $status');
+      final ChannelPair channels = ChannelPair();
+      if (channels.status != 0) {
+        log.severe('Unable to create channels: $channels.status');
+        return;
       }
+
+      int status = System.connectToService(
+        '/svc/${devmgr.Administrator.$serviceName}',
+        channels.second.passHandle());
+      if (status != 0 ) {
+        channels.first.close();
+        log.severe('Unable to connect to device administrator service: $status');
+        return;
+      }
+
+      final devmgr.AdministratorProxy admin = devmgr.AdministratorProxy();
+      admin.ctrl.bind(InterfaceHandle<devmgr.Administrator>(channels.first));
+
+      status = await admin.suspend(devmgr.suspendFlagReboot);
+      if (status != 0) {
+        log.severe('Reboot call failed with status: $status');
+      }
+
+      admin.ctrl.close();
     } else {
       _showResetConfirmation = true;
       notifyListeners();
diff --git a/bin/userpicker_base_shell/BUILD.gn b/bin/userpicker_base_shell/BUILD.gn
index 71ab93a..8da86f2 100644
--- a/bin/userpicker_base_shell/BUILD.gn
+++ b/bin/userpicker_base_shell/BUILD.gn
@@ -45,5 +45,6 @@
     "//topaz/public/dart/fuchsia_scenic_flutter",
     "//topaz/public/dart/widgets:lib.widgets",
     "//topaz/public/lib/device/dart",
+    "//zircon/public/fidl/fuchsia-device-manager",
   ]
 }
diff --git a/bin/userpicker_base_shell/lib/user_picker_base_shell_model.dart b/bin/userpicker_base_shell/lib/user_picker_base_shell_model.dart
index 4507601..3fe0d69 100644
--- a/bin/userpicker_base_shell/lib/user_picker_base_shell_model.dart
+++ b/bin/userpicker_base_shell/lib/user_picker_base_shell_model.dart
@@ -4,6 +4,9 @@
 
 import 'dart:async';
 
+import 'package:fidl/fidl.dart';
+import 'package:fidl_fuchsia_cobalt/fidl_async.dart' as cobalt;
+import 'package:fidl_fuchsia_device_manager/fidl_async.dart' as devmgr;
 import 'package:fidl_fuchsia_modular_auth/fidl_async.dart';
 import 'package:fidl_fuchsia_sys/fidl_async.dart';
 import 'package:fidl_fuchsia_ui_policy/fidl_async.dart';
@@ -49,7 +52,8 @@
     this.onBaseShellStopped,
     this.onWifiTapped,
     this.onLogin,
-  });
+    cobalt.Logger logger,
+  }) : super(logger);
 
   @override
   void onStop() {
@@ -74,11 +78,31 @@
   }
 
   /// Call when reset is tapped.
-  void resetTapped() {
-    int status = System.reboot();
-    if (status != 0) {
-      log.severe('Unable to reboot system: $status');
-    }
+  void resetTapped() async {
+      final ChannelPair channels = ChannelPair();
+      if (channels.status != 0) {
+        log.severe('Unable to create channels: $channels.status');
+        return;
+      }
+
+      int status = System.connectToService(
+        '/svc/${devmgr.Administrator.$serviceName}',
+        channels.second.passHandle());
+      if (status != 0 ) {
+        channels.first.close();
+        log.severe('Unable to connect to device administrator service: $status');
+        return;
+      }
+
+      final devmgr.AdministratorProxy admin = devmgr.AdministratorProxy();
+      admin.ctrl.bind(InterfaceHandle<devmgr.Administrator>(channels.first));
+
+      status = await admin.suspend(devmgr.suspendFlagReboot);
+      if (status != 0) {
+        log.severe('Reboot call failed with status: $status');
+      }
+
+      admin.ctrl.close();
   }
 
   /// Create a new user and login with that user
diff --git a/bin/userpicker_base_shell/meta/userpicker_base_shell.cmx b/bin/userpicker_base_shell/meta/userpicker_base_shell.cmx
index 5b1e7b8..18b7ca4 100644
--- a/bin/userpicker_base_shell/meta/userpicker_base_shell.cmx
+++ b/bin/userpicker_base_shell/meta/userpicker_base_shell.cmx
@@ -8,14 +8,15 @@
         ],
         "services": [
             "fuchsia.cobalt.LoggerFactory",
+            "fuchsia.device.manager.Administrator",
             "fuchsia.fonts.Provider",
             "fuchsia.logger.LogSink",
             "fuchsia.modular.Clipboard",
             "fuchsia.modular.ContextWriter",
             "fuchsia.net.Connectivity",
             "fuchsia.netstack.Netstack",
-            "fuchsia.sys.Launcher",
             "fuchsia.sys.Environment",
+            "fuchsia.sys.Launcher",
             "fuchsia.ui.input.ImeService",
             "fuchsia.ui.policy.Presenter",
             "fuchsia.ui.scenic.Scenic"
diff --git a/public/dart-pkg/zircon/BUILD.gn b/public/dart-pkg/zircon/BUILD.gn
index ce67b3b..af6f6ce 100644
--- a/public/dart-pkg/zircon/BUILD.gn
+++ b/public/dart-pkg/zircon/BUILD.gn
@@ -36,6 +36,7 @@
     "//zircon/public/fidl/fuchsia-device-manager",
     "//zircon/public/lib/async-default",
     "//zircon/public/lib/ddk",
+    "//zircon/public/lib/fs",
     "//zircon/public/lib/zx",
   ]
 
diff --git a/public/dart-pkg/zircon/lib/src/system.dart b/public/dart-pkg/zircon/lib/src/system.dart
index 739da7d..4d8ad5e 100644
--- a/public/dart-pkg/zircon/lib/src/system.dart
+++ b/public/dart-pkg/zircon/lib/src/system.dart
@@ -125,8 +125,8 @@
       native 'System_ChannelCreate';
   static HandleResult channelFromFile(String path)
       native 'System_ChannelFromFile';
-  static int reboot()
-      native 'System_Reboot';
+  static int connectToService(String path, Handle channel)
+      native 'System_ConnectToService';
   static int channelWrite(Handle channel, ByteData data, List<Handle> handles)
       native 'System_ChannelWrite';
   static ReadResult channelQueryAndRead(Handle channel)
@@ -158,4 +158,7 @@
 
   // Time operations.
   static int clockGet(int clockId) native 'System_ClockGet';
+
+  // TODO(edcoyne): Remove this, it is required to safely do an API transition across repos.
+  static int reboot() { return -2; /*ZX_ERR_NOT_SUPPORTED*/ }
 }
diff --git a/public/dart-pkg/zircon/sdk_ext/system.cc b/public/dart-pkg/zircon/sdk_ext/system.cc
index bf81ce5..854295a 100644
--- a/public/dart-pkg/zircon/sdk_ext/system.cc
+++ b/public/dart-pkg/zircon/sdk_ext/system.cc
@@ -8,6 +8,7 @@
 
 #include <ddk/device.h>
 #include <fcntl.h>
+#include <fs/vfs.h>
 #include <fuchsia/device/manager/cpp/fidl.h>
 #include <lib/fdio/directory.h>
 #include <lib/fdio/io.h>
@@ -128,7 +129,7 @@
   return object;
 }
 
-fxl::UniqueFD FdFromPath(std::string path) {
+fdio_ns_t* GetNamespace() {
   // Grab the fdio_ns_t* out of the isolate.
   Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon"));
   FXL_DCHECK(!tonic::LogIfError(zircon_lib));
@@ -142,9 +143,12 @@
   Dart_Handle result = Dart_IntegerToUint64(namespace_field, &fdio_ns_ptr);
   FXL_DCHECK(!tonic::LogIfError(result));
 
+  return reinterpret_cast<fdio_ns_t*>(fdio_ns_ptr);
+}
+
+fxl::UniqueFD FdFromPath(std::string path) {
   // Get a VMO for the file.
-  fdio_ns_t* ns = reinterpret_cast<fdio_ns_t*>(fdio_ns_ptr);
-  fxl::UniqueFD dirfd(fdio_ns_opendir(ns));
+  fxl::UniqueFD dirfd(fdio_ns_opendir(GetNamespace()));
   if (!dirfd.is_valid())
     return fxl::UniqueFD();
 
@@ -170,29 +174,11 @@
   }
 }
 
-zx_status_t System::Reboot() {
-  zx::channel local, remote;
-  auto status = zx::channel::create(0, &local, &remote);
-  if (status != ZX_OK) {
-    return status;
-  }
+zx_status_t System::ConnectToService(std::string path, fxl::RefPtr<Handle> channel) {
+  return fdio_ns_connect(GetNamespace(), path.c_str(),
+                         ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE,
+                         channel->ReleaseHandle());
 
-  const std::string service = std::string{"/svc/"} +
-      fuchsia::device::manager::Administrator::Name_;
-  status = fdio_service_connect(service.c_str(), remote.get());
-  if (status != ZX_OK) {
-    printf("failed to connect to service %s: %d\n", service.c_str(), status);
-    return status;
-  }
-
-  zx_status_t call_status;
-  fuchsia::device::manager::Administrator_SyncProxy administrator(std::move(local));
-  status = administrator.Suspend(DEVICE_SUSPEND_FLAG_REBOOT, &call_status);
-  if (status != ZX_OK || call_status != ZX_OK) {
-    printf("Call to %s failed: ret: %d  remote: %d\n", service.c_str(), status, call_status);
-  }
-
-  return status != ZX_OK ? status : call_status;
 }
 
 Dart_Handle System::ChannelFromFile(std::string path) {
@@ -469,7 +455,7 @@
   V(System, ChannelWrite)          \
   V(System, ChannelQueryAndRead)   \
   V(System, EventpairCreate)       \
-  V(System, Reboot)                \
+  V(System, ConnectToService)      \
   V(System, SocketCreate)          \
   V(System, SocketWrite)           \
   V(System, SocketRead)            \
diff --git a/public/dart-pkg/zircon/sdk_ext/system.h b/public/dart-pkg/zircon/sdk_ext/system.h
index 8c96d7c..ffd39d1 100644
--- a/public/dart-pkg/zircon/sdk_ext/system.h
+++ b/public/dart-pkg/zircon/sdk_ext/system.h
@@ -56,7 +56,7 @@
 
   static void RegisterNatives(tonic::DartLibraryNatives* natives);
 
-  static zx_status_t Reboot();
+  static zx_status_t ConnectToService(std::string path, fxl::RefPtr<Handle> channel);
 
  private:
   static void VmoMapFinalizer(void* isolate_callback_data,
diff --git a/public/dart/zircon/lib/src/fakes/system.dart b/public/dart/zircon/lib/src/fakes/system.dart
index dfcb77b..a68e267 100644
--- a/public/dart/zircon/lib/src/fakes/system.dart
+++ b/public/dart/zircon/lib/src/fakes/system.dart
@@ -188,6 +188,12 @@
   }
 
   // System operations.
+  static int connectToService(String path, Handle channel) {
+    throw UnimplementedError(
+        'System.connectToService() is not implemented on this platform.');
+  }
+
+  //TODO(edcoyne): remove after cross-repo transition.
   static int reboot() {
     throw UnimplementedError(
         'System.reboot() is not implemented on this platform.');
diff --git a/runtime/flutter_runner/meta/flutter_aot_product_runner.cmx b/runtime/flutter_runner/meta/flutter_aot_product_runner.cmx
index 6e6a4c9..9795472 100644
--- a/runtime/flutter_runner/meta/flutter_aot_product_runner.cmx
+++ b/runtime/flutter_runner/meta/flutter_aot_product_runner.cmx
@@ -9,7 +9,6 @@
         ],
         "services": [
             "fuchsia.crash.Analyzer",
-            "fuchsia.device.manager.Administrator",
             "fuchsia.fonts.Provider",
             "fuchsia.net.SocketProvider",
             "fuchsia.sysmem.Allocator",
diff --git a/runtime/flutter_runner/meta/flutter_aot_runner.cmx b/runtime/flutter_runner/meta/flutter_aot_runner.cmx
index 6e6a4c9..9795472 100644
--- a/runtime/flutter_runner/meta/flutter_aot_runner.cmx
+++ b/runtime/flutter_runner/meta/flutter_aot_runner.cmx
@@ -9,7 +9,6 @@
         ],
         "services": [
             "fuchsia.crash.Analyzer",
-            "fuchsia.device.manager.Administrator",
             "fuchsia.fonts.Provider",
             "fuchsia.net.SocketProvider",
             "fuchsia.sysmem.Allocator",
diff --git a/runtime/flutter_runner/meta/flutter_jit_product_runner.cmx b/runtime/flutter_runner/meta/flutter_jit_product_runner.cmx
index 008e385..9795472 100644
--- a/runtime/flutter_runner/meta/flutter_jit_product_runner.cmx
+++ b/runtime/flutter_runner/meta/flutter_jit_product_runner.cmx
@@ -8,7 +8,6 @@
             "vulkan"
         ],
         "services": [
-            "fuchsia.device.manager.Administrator",
             "fuchsia.crash.Analyzer",
             "fuchsia.fonts.Provider",
             "fuchsia.net.SocketProvider",
diff --git a/runtime/flutter_runner/meta/flutter_jit_runner.cmx b/runtime/flutter_runner/meta/flutter_jit_runner.cmx
index 6e6a4c9..9795472 100644
--- a/runtime/flutter_runner/meta/flutter_jit_runner.cmx
+++ b/runtime/flutter_runner/meta/flutter_jit_runner.cmx
@@ -9,7 +9,6 @@
         ],
         "services": [
             "fuchsia.crash.Analyzer",
-            "fuchsia.device.manager.Administrator",
             "fuchsia.fonts.Provider",
             "fuchsia.net.SocketProvider",
             "fuchsia.sysmem.Allocator",