From 70671addd6a9b36095c7f4e8e185ae08264296e1 Mon Sep 17 00:00:00 2001
From: Suraj Malhotra <surajmalhotra@google.com>
Date: Thu, 9 May 2019 03:24:52 +0000
Subject: [PATCH] [svchost][devmgr][miscsvc] Add miscsvc

Was originally submitted as Id411227e4c3d2b8add49978cf6ce1a76de509a48.

Startup a miscsvc binary, and provide a channel to it's '/svc/
directory to svchost, which will then forward it services.

To start miscsvc only implements the paver service.

ZX-3861

Change-Id: I83a630476c08d15e461d74e3321ad55bb21a3c2f
---
 build/images/zedboot/BUILD.gn                 |   1 +
 .../core/devmgr/devcoordinator/BUILD.gn       |   1 +
 .../core/devmgr/devcoordinator/main.cpp       |  36 ++++++
 zircon/system/core/miscsvc/BUILD.gn           |  17 +++
 zircon/system/core/miscsvc/README.md          |  12 ++
 zircon/system/core/miscsvc/miscsvc.cpp        | 117 ++++++++++++++++++
 zircon/system/core/svchost/BUILD.gn           |   1 +
 zircon/system/core/svchost/svchost.cpp        |   9 ++
 zircon/system/utest/BUILD.gn                  |   1 +
 zircon/system/utest/miscsvc/BUILD.gn          |  15 +++
 zircon/system/utest/miscsvc/main.cpp          |  33 +++++
 11 files changed, 243 insertions(+)
 create mode 100644 zircon/system/core/miscsvc/BUILD.gn
 create mode 100644 zircon/system/core/miscsvc/README.md
 create mode 100644 zircon/system/core/miscsvc/miscsvc.cpp
 create mode 100644 zircon/system/utest/miscsvc/BUILD.gn
 create mode 100644 zircon/system/utest/miscsvc/main.cpp

diff --git a/build/images/zedboot/BUILD.gn b/build/images/zedboot/BUILD.gn
index 702321fe23f..7b4bca6c920 100644
--- a/build/images/zedboot/BUILD.gn
+++ b/build/images/zedboot/BUILD.gn
@@ -40,6 +40,7 @@ zedboot_binary_patterns = [
   "bin/devcoordinator",
   "bin/dlog",
   "bin/fshost",
+  "bin/miscsvc",
   "bin/netsvc",
   "bin/pwrbtn-monitor",
   "bin/svchost",
diff --git a/zircon/system/core/devmgr/devcoordinator/BUILD.gn b/zircon/system/core/devmgr/devcoordinator/BUILD.gn
index 86cc6ea4bc0..dca2bab5c5b 100644
--- a/zircon/system/core/devmgr/devcoordinator/BUILD.gn
+++ b/zircon/system/core/devmgr/devcoordinator/BUILD.gn
@@ -19,6 +19,7 @@ executable("devcoordinator") {
   data_deps = [
     ":internal-drivers",
     "../fshost",
+    "$zx/system/core/miscsvc",
     "$zx/system/core/netsvc",
     "$zx/system/core/svchost",
     "$zx/system/core/virtcon:virtual-console",
diff --git a/zircon/system/core/devmgr/devcoordinator/main.cpp b/zircon/system/core/devmgr/devcoordinator/main.cpp
index dc5c1c05269..9f497836661 100644
--- a/zircon/system/core/devmgr/devcoordinator/main.cpp
+++ b/zircon/system/core/devmgr/devcoordinator/main.cpp
@@ -68,6 +68,12 @@ struct {
     // If appmgr cannot be launched within a timeout, this handle is closed.
     zx::channel appmgr_server;
 
+    // The handle used to transmit messages to miscsvc.
+    zx::channel miscsvc_client;
+
+    // The handle used by miscsvc to serve incoming requests.
+    zx::channel miscsvc_server;
+
     zx::unowned_job root_job;
     zx::job svc_job;
     zx::job fuchsia_job;
@@ -406,6 +412,8 @@ zx_status_t svchost_start(bool require_system, devmgr::Coordinator* coordinator,
     zx::debuglog logger;
     zx::channel appmgr_svc_req;
     zx::channel appmgr_svc;
+    zx::channel miscsvc_svc_req;
+    zx::channel miscsvc_svc;
 
     zx_status_t status = zx::channel::create(0, &dir_request, &svchost_local);
     if (status != ZX_OK) {
@@ -428,6 +436,18 @@ zx_status_t svchost_start(bool require_system, devmgr::Coordinator* coordinator,
         return status;
     }
 
+    status = zx::channel::create(0, &miscsvc_svc_req, &miscsvc_svc);
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    status =
+        fdio_service_connect_at(g_handles.miscsvc_client.get(), "public",
+                                miscsvc_svc_req.release());
+    if (status != ZX_OK) {
+        return status;
+    }
+
     const char* name = "svchost";
     const char* argv[2] = {
         "/boot/bin/svchost",
@@ -518,6 +538,9 @@ zx_status_t svchost_start(bool require_system, devmgr::Coordinator* coordinator,
         launchpad_add_handle(lp, virtcon_client.release(), PA_HND(PA_USER0, 5));
     }
 
+    // Add handle to channel to allow svchost to talk to miscsvc.
+    launchpad_add_handle(lp, miscsvc_svc.release(), PA_HND(PA_USER0, 6));
+
     // Give svchost access to /dev/class/sysmem, to enable svchost to forward sysmem service
     // requests to the sysmem driver.  Create a namespace containing /dev/class/sysmem.
     const char* nametable[1] = {};
@@ -656,6 +679,18 @@ void devmgr_vfs_init(devmgr::Coordinator* coordinator, const devmgr::DevmgrArgs&
 int service_starter(void* arg) {
     auto coordinator = static_cast<devmgr::Coordinator*>(arg);
 
+    // Launch miscsvc binary with access to:
+    // * /dev to talk to hardware
+    // * /boot to dynamically load drivers (zxcrypt)
+    // * /svc to call launch processes (minfs)
+    // * /volume to mount (minfs)
+    const zx_handle_t handles[] = { g_handles.miscsvc_server.release() };
+    const uint32_t types[] = { PA_DIRECTORY_REQUEST };
+    const char* args[] = { "/boot/bin/miscsvc", nullptr };
+
+    devmgr::devmgr_launch(g_handles.svc_job, "miscsvc", args, nullptr, -1, handles,
+                          types, countof(handles), nullptr, FS_BOOT | FS_DEV | FS_SVC | FS_VOLUME);
+
     bool netboot = false;
     bool vruncmd = false;
     fbl::String vcmd;
@@ -978,6 +1013,7 @@ int main(int argc, char** argv) {
     zx::channel fshost_client, fshost_server;
     zx::channel::create(0, &fshost_client, &fshost_server);
     zx::channel::create(0, &g_handles.appmgr_client, &g_handles.appmgr_server);
+    zx::channel::create(0, &g_handles.miscsvc_client, &g_handles.miscsvc_server);
 
     if (devmgr_args.use_system_svchost) {
         zx::channel dir_request;
diff --git a/zircon/system/core/miscsvc/BUILD.gn b/zircon/system/core/miscsvc/BUILD.gn
new file mode 100644
index 00000000000..651e491867b
--- /dev/null
+++ b/zircon/system/core/miscsvc/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2019 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.
+
+executable("miscsvc") {
+  sources = [
+    "miscsvc.cpp",
+  ]
+  deps = [
+    "$zx/system/ulib/async-loop:async-loop-cpp",
+    "$zx/system/ulib/fbl",
+    "$zx/system/ulib/fdio",
+    "$zx/system/ulib/paver",
+    "$zx/system/ulib/svc",
+    "$zx/system/ulib/zircon",
+  ]
+}
diff --git a/zircon/system/core/miscsvc/README.md b/zircon/system/core/miscsvc/README.md
new file mode 100644
index 00000000000..b019e94785a
--- /dev/null
+++ b/zircon/system/core/miscsvc/README.md
@@ -0,0 +1,12 @@
+# Miscellaneous Service
+
+This service provides a tempoary home for services which need to be available
+prior to appmgr being launched, but don't want the tedium of setting up their
+own process. These services previously were hosted by svchost, but has proved
+problematic, so they have been isolated into a separate process.
+
+Services implemented by miscsvc are exposed to svchost, which exposes it out
+further to other parts of the system.
+
+Once component manager lands in bootfs, and adequate build support arrives,
+these services can be rewritten as components.
diff --git a/zircon/system/core/miscsvc/miscsvc.cpp b/zircon/system/core/miscsvc/miscsvc.cpp
new file mode 100644
index 00000000000..98a93e2d349
--- /dev/null
+++ b/zircon/system/core/miscsvc/miscsvc.cpp
@@ -0,0 +1,117 @@
+// Copyright 2019 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 <fbl/algorithm.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/paver/provider.h>
+#include <lib/svc/outgoing.h>
+#include <zircon/status.h>
+
+// An instance of a zx_service_provider_t.
+//
+// Includes the |ctx| pointer for the zx_service_provider_t.
+typedef struct zx_service_provider_instance {
+    // The service provider for which this structure is an instance.
+    const zx_service_provider_t* provider;
+
+    // The |ctx| pointer returned by the provider's |init| function, if any.
+    void* ctx;
+} zx_service_provider_instance_t;
+
+static zx_status_t provider_init(zx_service_provider_instance_t* instance) {
+    if (instance->provider->ops->init) {
+        zx_status_t status = instance->provider->ops->init(&instance->ctx);
+        if (status != ZX_OK)
+            return status;
+    }
+    return ZX_OK;
+}
+
+static zx_status_t provider_publish(zx_service_provider_instance_t* instance,
+                                    async_dispatcher_t* dispatcher,
+                                    const fbl::RefPtr<fs::PseudoDir>& dir) {
+    const zx_service_provider_t* provider = instance->provider;
+
+    if (!provider->services || !provider->ops->connect)
+        return ZX_ERR_INVALID_ARGS;
+
+    for (size_t i = 0; provider->services[i]; ++i) {
+        const char* service_name = provider->services[i];
+        zx_status_t status = dir->AddEntry(
+            service_name,
+            fbl::MakeRefCounted<fs::Service>(
+                [instance, dispatcher, service_name](zx::channel request) {
+                    return instance->provider->ops->connect(instance->ctx, dispatcher, service_name,
+                                                            request.release());
+                }));
+        if (status != ZX_OK) {
+            for (size_t j = 0; j < i; ++j)
+                dir->RemoveEntry(provider->services[j]);
+            return status;
+        }
+    }
+
+    return ZX_OK;
+}
+
+static void provider_release(zx_service_provider_instance_t* instance) {
+    if (instance->provider->ops->release)
+        instance->provider->ops->release(instance->ctx);
+    instance->ctx = nullptr;
+}
+
+static zx_status_t provider_load(zx_service_provider_instance_t* instance,
+                                 async_dispatcher_t* dispatcher,
+                                 const fbl::RefPtr<fs::PseudoDir>& dir) {
+    if (instance->provider->version != SERVICE_PROVIDER_VERSION) {
+        return ZX_ERR_INVALID_ARGS;
+    }
+
+    zx_status_t status = provider_init(instance);
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    status = provider_publish(instance, dispatcher, dir);
+    if (status != ZX_OK) {
+        provider_release(instance);
+        return status;
+    }
+
+    return ZX_OK;
+}
+
+int main(int argc, char** argv) {
+    async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
+    async_dispatcher_t* dispatcher = loop.dispatcher();
+    svc::Outgoing outgoing(dispatcher);
+
+    zx_status_t status = outgoing.ServeFromStartupInfo();
+    if (status != ZX_OK) {
+        fprintf(stderr, "miscsvc: error: Failed to serve outgoing directory: %d (%s).\n",
+                status, zx_status_get_string(status));
+        return 1;
+    }
+
+    zx_service_provider_instance_t service_providers[] = {
+        {.provider = paver_get_service_provider(), .ctx = nullptr},
+    };
+
+    for (size_t i = 0; i < fbl::count_of(service_providers); ++i) {
+        status = provider_load(&service_providers[i], dispatcher, outgoing.public_dir());
+        if (status != ZX_OK) {
+            fprintf(stderr, "miscsvc: error: Failed to load service provider %zu: %d (%s).\n",
+                    i, status, zx_status_get_string(status));
+            return 1;
+        }
+    }
+
+    status = loop.Run();
+
+    for (size_t i = 0; i < fbl::count_of(service_providers); ++i) {
+        provider_release(&service_providers[i]);
+    }
+
+    return status;
+}
diff --git a/zircon/system/core/svchost/BUILD.gn b/zircon/system/core/svchost/BUILD.gn
index cb9f9147f5c..db49f3bfafd 100644
--- a/zircon/system/core/svchost/BUILD.gn
+++ b/zircon/system/core/svchost/BUILD.gn
@@ -16,6 +16,7 @@ executable("svchost") {
     "$zx/system/fidl/fuchsia-logger:c",
     "$zx/system/fidl/fuchsia-mem:c",
     "$zx/system/fidl/fuchsia-net:c",
+    "$zx/system/fidl/fuchsia-paver:c",
     "$zx/system/fidl/fuchsia-process:c",
     "$zx/system/fidl/fuchsia-scheduler:c",
     "$zx/system/fidl/fuchsia-sysmem:c",
diff --git a/zircon/system/core/svchost/svchost.cpp b/zircon/system/core/svchost/svchost.cpp
index c0cc5a962cc..642c97b9fc2 100644
--- a/zircon/system/core/svchost/svchost.cpp
+++ b/zircon/system/core/svchost/svchost.cpp
@@ -9,6 +9,7 @@
 #include <fs/remote-dir.h>
 #include <fuchsia/device/manager/c/fidl.h>
 #include <fuchsia/fshost/c/fidl.h>
+#include <fuchsia/paver/c/fidl.h>
 #include <fuchsia/virtualconsole/c/fidl.h>
 #include <fuchsia/net/c/fidl.h>
 #include <lib/async-loop/cpp/loop.h>
@@ -149,6 +150,12 @@ static constexpr const char* fshost_services[] = {
     nullptr,
 };
 
+// Forward these Zircon services to miscsvc.
+static constexpr const char* miscsvc_services[] = {
+    fuchsia_paver_Paver_Name,
+    nullptr,
+};
+
 // The ServiceProxy is a Vnode which, if opened, connects to a service.
 // However, if treated like a directory, the service proxy will attempt to
 // relay the underlying request to the connected service channel.
@@ -237,6 +244,7 @@ int main(int argc, char** argv) {
     zx::channel devmgr_proxy_channel = zx::channel(zx_take_startup_handle(PA_HND(PA_USER0, 3)));
     zx::channel fshost_svc = zx::channel(zx_take_startup_handle(PA_HND(PA_USER0, 4)));
     zx::channel virtcon_proxy_channel = zx::channel(zx_take_startup_handle(PA_HND(PA_USER0, 5)));
+    zx::channel miscsvc_svc = zx::channel(zx_take_startup_handle(PA_HND(PA_USER0, 6)));
 
     zx_status_t status = outgoing.ServeFromStartupInfo();
     if (status != ZX_OK) {
@@ -292,6 +300,7 @@ int main(int argc, char** argv) {
 
     publish_services(outgoing.public_dir(), deprecated_services, zx::unowned_channel(appmgr_svc));
     publish_services(outgoing.public_dir(), fshost_services, zx::unowned_channel(fshost_svc));
+    publish_services(outgoing.public_dir(), miscsvc_services, zx::unowned_channel(miscsvc_svc));
 
     publish_remote_service(outgoing.public_dir(),
                           fuchsia_device_manager_DebugDumper_Name,
diff --git a/zircon/system/utest/BUILD.gn b/zircon/system/utest/BUILD.gn
index d1f24665fd7..981fd942ab8 100644
--- a/zircon/system/utest/BUILD.gn
+++ b/zircon/system/utest/BUILD.gn
@@ -141,6 +141,7 @@ if (current_cpu != "") {
       "log",
       "logger",
       "memfs",
+      "miscsvc",
       "msd",
       "namespace",
       "perftest",
diff --git a/zircon/system/utest/miscsvc/BUILD.gn b/zircon/system/utest/miscsvc/BUILD.gn
new file mode 100644
index 00000000000..d1f14282681
--- /dev/null
+++ b/zircon/system/utest/miscsvc/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright 2019 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.
+
+test("miscsvc") {
+  sources = [ "main.cpp" ]
+  deps = [
+    "$zx/system/fidl/fuchsia-paver:c",
+    "$zx/system/ulib/fdio",
+    "$zx/system/ulib/zircon",
+    "$zx/system/ulib/zx",
+    "$zx/system/ulib/zxcpp",
+    "$zx/system/ulib/zxtest",
+  ]
+}
diff --git a/zircon/system/utest/miscsvc/main.cpp b/zircon/system/utest/miscsvc/main.cpp
new file mode 100644
index 00000000000..ae47a70eb68
--- /dev/null
+++ b/zircon/system/utest/miscsvc/main.cpp
@@ -0,0 +1,33 @@
+// Copyright 2019 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 <fcntl.h>
+
+#include <fuchsia/paver/c/fidl.h>
+#include <lib/fdio/fd.h>
+#include <lib/fdio/fdio.h>
+#include <lib/fdio/directory.h>
+#include <lib/zx/channel.h>
+#include <lib/zx/vmo.h>
+#include <zxtest/zxtest.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+
+namespace {
+
+TEST(MiscSvcTest, PaverSvccEnumeratesSuccessfully) {
+    zx::channel svc_local, svc_remote;
+    ASSERT_OK(zx::channel::create(0, &svc_local, &svc_remote));
+    ASSERT_OK(fdio_service_connect("/svc", svc_remote.release()));
+
+    zx::channel local, remote;
+    ASSERT_OK(zx::channel::create(0, &local, &remote));
+    ASSERT_OK(fdio_service_connect_at(svc_local.get(), fuchsia_paver_Paver_Name, remote.release()));
+
+    zx_status_t status;
+    fuchsia_paver_Configuration* configuration;
+    ASSERT_OK(fuchsia_paver_PaverQueryActiveConfiguration(local.get(), &status, &configuration));
+}
+
+} // namespace
-- 
GitLab