From 082d4818eaf46c59bf4c1f6e65c3f843ed79b04a Mon Sep 17 00:00:00 2001
From: Jeremy Manson <jeremymanson@google.com>
Date: Fri, 26 Apr 2019 23:24:52 +0000
Subject: [PATCH] [fidlcat] Fix issue with interface vector resizing.

When the number of interfaces grows, the vector containing the interfaces
grows with it.  This involves the interface being moved.

When you generate an interface for the first time, each interface method is
given a pointer to the enclosing interface.

When the interface vector is resized, the interface method's pointer is
dangling.

This CL fixes the issue in two ways:

- The move constructor for the interface now creates an updated interface
method instead of reusing the old one.

- Interface vector initialization now reserves enough space for all of the
interfaces, so that moves will no longer be necessary.

Change-Id: Ifa4c51f21bb3dc194695d5af5029a46b862ae907
---
 tools/fidlcat/lib/BUILD.gn                  |  12 +
 tools/fidlcat/lib/generate_test_includes.sh |   8 +-
 tools/fidlcat/lib/library_loader.cc         |  30 +-
 tools/fidlcat/lib/library_loader.h          |  34 +-
 tools/fidlcat/lib/library_loader_test.cc    |  56 ++-
 tools/fidlcat/lib/testdata/sys.test.fidl    | 380 ++++++++++++++++++++
 6 files changed, 498 insertions(+), 22 deletions(-)
 create mode 100644 tools/fidlcat/lib/testdata/sys.test.fidl

diff --git a/tools/fidlcat/lib/BUILD.gn b/tools/fidlcat/lib/BUILD.gn
index a5faccdffc7..32d907ec9c2 100644
--- a/tools/fidlcat/lib/BUILD.gn
+++ b/tools/fidlcat/lib/BUILD.gn
@@ -89,6 +89,8 @@ source_set("tests") {
 action("json_for_test") {
   deps = [
     ":fidl($fidl_toolchain)",
+    ":fidl-sys($fidl_toolchain)",
+    "//sdk/fidl/fuchsia.sys",
     "//sdk/lib/fidl/cpp/test:frobinator",
     "//zircon/public/fidl/fuchsia-io",
   ]
@@ -104,6 +106,8 @@ action("json_for_test") {
         "/fidling/gen/zircon/public/fidl/fuchsia-io/fuchsia-io.fidl.json",
     rebase_path(root_build_dir) +
         "/fidling/gen/tools/fidlcat/lib/fidl.fidl.json",
+    rebase_path(root_build_dir) +
+        "/fidling/gen/tools/fidlcat/lib/fidl-sys.fidl.json",
   ]
 }
 
@@ -115,3 +119,11 @@ fidl("fidl") {
     "testdata/types.test.fidl",
   ]
 }
+
+fidl("fidl-sys") {
+  name = "test.fidlcat.sys"
+
+  sources = [
+    "testdata/sys.test.fidl",
+  ]
+}
diff --git a/tools/fidlcat/lib/generate_test_includes.sh b/tools/fidlcat/lib/generate_test_includes.sh
index 3081f57bcd9..9e5ed7712f2 100755
--- a/tools/fidlcat/lib/generate_test_includes.sh
+++ b/tools/fidlcat/lib/generate_test_includes.sh
@@ -25,11 +25,17 @@ class ExampleMap {
   ExampleMap() {
     map_ = {
 EOF
-for i in "$@"; do \
+
+for i in "$@"; do
+  if [[ ! -f "${i}" ]]; then
+     echo "file ${i} not found"
+     exit 1
+  fi;
   cat >> "${FILENAME}" << EOF
     {"${i}", R"FIDL($(cat "${i}"))FIDL"},
 EOF
 done
+
 cat >> "${FILENAME}" << EOF
     };
   }
diff --git a/tools/fidlcat/lib/library_loader.cc b/tools/fidlcat/lib/library_loader.cc
index 2da97a45d84..cf0b6dd54c9 100644
--- a/tools/fidlcat/lib/library_loader.cc
+++ b/tools/fidlcat/lib/library_loader.cc
@@ -51,6 +51,17 @@ std::unique_ptr<Type> Library::TypeFromIdentifier(
   return Type::get_illegal();
 }
 
+bool Library::GetInterfaceByName(const std::string& name,
+                                 const Interface** ptr) const {
+  for (const auto& interface : interfaces()) {
+    if (interface.name() == name) {
+      *ptr = &interface;
+      return true;
+    }
+  }
+  return false;
+}
+
 const std::unique_ptr<Type> Enum::GetType() const {
   // TODO Consider caching this.
   return Type::ScalarTypeFromName(value_["type"].GetString());
@@ -145,7 +156,9 @@ InterfaceMethod::InterfaceMethod(const Interface& interface,
   if (value_["has_request"].GetBool()) {
     request_params_ =
         std::make_optional<std::vector<InterfaceMethodParameter>>();
-    for (auto& request : value["maybe_request"].GetArray()) {
+    auto request_arr = value["maybe_request"].GetArray();
+    request_params_->reserve(request_arr.Size());
+    for (auto& request : request_arr) {
       request_params_->emplace_back(*this, request);
     }
   } else {
@@ -155,7 +168,9 @@ InterfaceMethod::InterfaceMethod(const Interface& interface,
   if (value_["has_response"].GetBool()) {
     response_params_ =
         std::make_optional<std::vector<InterfaceMethodParameter>>();
-    for (auto& response : value["maybe_response"].GetArray()) {
+    auto response_arr = value["maybe_response"].GetArray();
+    response_params_->reserve(response_arr.Size());
+    for (auto& response : response_arr) {
       response_params_->emplace_back(*this, response);
     }
   } else {
@@ -190,4 +205,15 @@ std::string InterfaceMethod::fully_qualified_name() const {
   return enclosing_interface_.name() + "." + name();
 }
 
+bool Interface::GetMethodByFullName(const std::string& name,
+                                    const InterfaceMethod** method_ptr) const {
+  for (const auto& method : methods()) {
+    if (method.fully_qualified_name() == name) {
+      *method_ptr = &method;
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace fidlcat
diff --git a/tools/fidlcat/lib/library_loader.h b/tools/fidlcat/lib/library_loader.h
index cbcc41fafd0..75f95b0c53f 100644
--- a/tools/fidlcat/lib/library_loader.h
+++ b/tools/fidlcat/lib/library_loader.h
@@ -89,10 +89,11 @@ class InterfaceMethodParameter {
 
 class InterfaceMethod {
  public:
+  friend class Interface;
   InterfaceMethod(const Interface& interface, const rapidjson::Value& value);
   InterfaceMethod(InterfaceMethod&& other);
 
-  int32_t get_ordinal() const {
+  Ordinal get_ordinal() const {
     return std::strtoll(value_["ordinal"].GetString(), nullptr, 10);
   }
 
@@ -139,6 +140,16 @@ class Interface {
     }
   }
 
+  Interface(Interface&& other)
+      : value_(other.value_), enclosing_library_(other.enclosing_library_) {
+    for (auto& method : other.interface_methods_) {
+      interface_methods_.emplace_back(*this, method.value_);
+    }
+  }
+
+  Interface(const Interface& other) = delete;
+  Interface& operator=(const Interface&) = delete;
+
   std::string name() const { return value_["name"].GetString(); }
 
   void AddMethodsToIndex(std::map<Ordinal, const InterfaceMethod*>& index) {
@@ -149,6 +160,10 @@ class Interface {
     }
   }
 
+  // Sets *|method| to the fully qualified |name|'s InterfaceMethod
+  bool GetMethodByFullName(const std::string& name,
+                           const InterfaceMethod** method) const;
+
   const Library& enclosing_library() const { return enclosing_library_; }
 
   const std::vector<InterfaceMethod>& methods() const {
@@ -224,7 +239,9 @@ class Union {
       : enclosing_library_(enclosing_library),
         value_(value),
         illegal_(nullptr) {
-    for (auto& member : value["members"].GetArray()) {
+    auto member_arr = value["members"].GetArray();
+    members_.reserve(member_arr.Size());
+    for (auto& member : member_arr) {
       members_.emplace_back(*this, member);
     }
   }
@@ -286,7 +303,9 @@ class Struct {
  public:
   Struct(const Library& enclosing_library, const rapidjson::Value& value)
       : enclosing_library_(enclosing_library), value_(value) {
-    for (auto& member : value["members"].GetArray()) {
+    auto member_arr = value["members"].GetArray();
+    members_.reserve(member_arr.Size());
+    for (auto& member : member_arr) {
       members_.emplace_back(*this, member);
     }
   }
@@ -311,7 +330,11 @@ class Library {
  public:
   Library(const LibraryLoader& enclosing, rapidjson::Document& document)
       : enclosing_loader_(enclosing), backing_document_(std::move(document)) {
-    for (auto& decl : backing_document_["interface_declarations"].GetArray()) {
+    auto interfaces_array =
+        backing_document_["interface_declarations"].GetArray();
+    interfaces_.reserve(interfaces_array.Size());
+
+    for (auto& decl : interfaces_array) {
       interfaces_.emplace_back(*this, decl);
     }
     for (auto& enu : backing_document_["enum_declarations"].GetArray()) {
@@ -352,6 +375,9 @@ class Library {
 
   const std::vector<Interface>& interfaces() const { return interfaces_; }
 
+  // Set *ptr to the Interface called |name|
+  bool GetInterfaceByName(const std::string& name, const Interface** ptr) const;
+
   Library& operator=(const Library&) = delete;
   Library(const Library&) = delete;
 
diff --git a/tools/fidlcat/lib/library_loader_test.cc b/tools/fidlcat/lib/library_loader_test.cc
index 50e09e259c5..6fd00605710 100644
--- a/tools/fidlcat/lib/library_loader_test.cc
+++ b/tools/fidlcat/lib/library_loader_test.cc
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "library_loader.h"
+
 #include <iostream>
 #include <sstream>
 #include <string>
 #include <vector>
 
 #include "gtest/gtest.h"
-#include "library_loader.h"
 #include "tools/fidlcat/lib/library_loader_test_data.h"
 
 namespace fidlcat {
@@ -28,29 +29,54 @@ TEST(LibraryLoader, LoadSimple) {
 
   const Library* library_ptr;
   loader.GetLibraryFromName("fidl.test.frobinator", &library_ptr);
-  const std::vector<Interface>& interfaces = library_ptr->interfaces();
 
   std::string kDesiredInterfaceName = "fidl.test.frobinator/Frobinator";
   const Interface* found_interface = nullptr;
-  for (const auto& interface : interfaces) {
-    if (interface.name() == kDesiredInterfaceName) {
-      found_interface = &interface;
-      break;
-    }
-  }
+  ASSERT_TRUE(
+      library_ptr->GetInterfaceByName(kDesiredInterfaceName, &found_interface));
+
   ASSERT_NE(found_interface, nullptr)
       << "Could not find interface " << kDesiredInterfaceName;
 
-  const InterfaceMethod* found_method = nullptr;
   std::string kDesiredFullMethodName = "fidl.test.frobinator/Frobinator.Frob";
-  for (const auto& method : found_interface->methods()) {
-    if (method.fully_qualified_name() == kDesiredFullMethodName) {
-      found_method = &method;
-      break;
-    }
-  }
+  const InterfaceMethod* found_method = nullptr;
+  found_interface->GetMethodByFullName(kDesiredFullMethodName, &found_method);
+
   ASSERT_NE(found_method, nullptr)
       << "Could not find method " << kDesiredFullMethodName;
 }
 
+TEST(LibraryLoader, LoadFromOrdinal) {
+  fidlcat_test::ExampleMap examples;
+  std::vector<std::unique_ptr<std::istream>> library_files;
+  for (auto element : examples.map()) {
+    std::unique_ptr<std::istream> file = std::make_unique<std::istringstream>(
+        std::istringstream(element.second));
+
+    library_files.push_back(std::move(file));
+  }
+  LibraryReadError err;
+  LibraryLoader loader = LibraryLoader(library_files, &err);
+  ASSERT_EQ(LibraryReadError::kOk, err.value);
+
+  const Library* library_ptr = nullptr;
+  ASSERT_TRUE(loader.GetLibraryFromName("test.fidlcat.sys", &library_ptr));
+
+  std::string kDesiredInterfaceName = "test.fidlcat.sys/ComponentController";
+  const Interface* found_interface = nullptr;
+  ASSERT_TRUE(
+      library_ptr->GetInterfaceByName(kDesiredInterfaceName, &found_interface));
+
+  const InterfaceMethod* found_method = nullptr;
+  found_interface->GetMethodByFullName(
+      "test.fidlcat.sys/ComponentController.OnDirectoryReady", &found_method);
+
+  Ordinal correct_ordinal = found_method->get_ordinal();
+  const InterfaceMethod* ordinal_method;
+  ASSERT_TRUE(loader.GetByOrdinal(correct_ordinal, &ordinal_method));
+  ASSERT_STREQ(kDesiredInterfaceName.c_str(),
+               ordinal_method->enclosing_interface().name().c_str());
+  ASSERT_STREQ("OnDirectoryReady", ordinal_method->name().c_str());
+}
+
 }  // namespace fidlcat
diff --git a/tools/fidlcat/lib/testdata/sys.test.fidl b/tools/fidlcat/lib/testdata/sys.test.fidl
new file mode 100644
index 00000000000..3e795755919
--- /dev/null
+++ b/tools/fidlcat/lib/testdata/sys.test.fidl
@@ -0,0 +1,380 @@
+// Copyright 2019 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.
+
+library test.fidlcat.sys;
+
+// The goal of this file is to get a pretty big library.  It's a copy
+// of fuchsia.sys and fuchsia.mem as of 26 April 2019.
+
+/// A Buffer for data whose size is not necessarily a multiple of the page
+/// size.
+///
+/// VMO objects have a physical size that is always a multiple of the page
+/// size. As such, VMO alone cannot serve as a buffer for arbitrarly sized
+/// data. |fuchsia.mem.Buffer| is a standard struct that aggregate the VMO
+/// and its size.
+struct Buffer {
+    /// The vmo.
+    handle<vmo> vmo;
+
+    /// The size of the data in the vmo in bytes. This size must be smaller
+    /// than the physical size of the vmo.
+    uint64 size;
+};
+
+enum TerminationReason {
+    // The channel closed without giving a termination reason.
+    UNKNOWN = 0;
+    // Component ran and exited with a given return_code.
+    EXITED = 1;
+    // The given URL given to launch was invalid.
+    URL_INVALID = 2;
+    // The requested package could not be found.
+    PACKAGE_NOT_FOUND = 3;
+    // An internal error happened during the launch process.
+    INTERNAL_ERROR = 4;
+    // Process creation failed.
+    PROCESS_CREATION_ERROR = 5;
+    // A Runner failed to start.
+    RUNNER_FAILED = 6;
+    // A Runner terminated while attempting to run a component.
+    RUNNER_TERMINATED = 7;
+    // Attempted to use an unsupported feature.
+    UNSUPPORTED = 8;
+};
+
+// An interface for controlling components.
+//
+// Closing this interface implicitly kills the controlled component unless
+// the |Detach| method has been called.
+//
+// If the component exits, this interface will be closed.
+//
+// Typically obtained via |Launcher.CreateComponent|.
+protocol ComponentController {
+    // Terminates the component.
+    //
+    // This ComponentController connection is closed when the component has
+    // terminated.
+    Kill();
+
+    // Decouples the lifetime of the component from this controller.
+    //
+    // After calling |Detach|, the component will not be implicitly killed when
+    // this interface is closed.
+    Detach();
+
+    // DEPRECATED: Use OnTerminated instead of Wait().
+    // 3: Wait()
+
+    // Event that is triggered when the component is terminated.
+    //
+    // This event provides the return code of the process and reason for
+    // its termination. The return_code is only valid if the termination
+    // reason is EXITED. If the termination reason is not EXITED, the
+    // return code is guaranteed not to be 0.
+    -> OnTerminated(int64 return_code, TerminationReason termination_reason);
+
+    // Event that is triggered when the component's output directory is mounted.
+    //
+    // This event will not be triggered for every component, only those that
+    // serve a directory over their PA_DIRECTORY_REQUEST handle.
+    -> OnDirectoryReady();
+};
+
+// An interface for controlling an environment.
+//
+// Closing this interface implicitly kills the controlled environment unless
+// the |Detach| method has been called.
+//
+// If the environment is destroyed, this interface will be closed.
+//
+// Typically obtained via |Environment.CreateNestedEnvironment|.
+protocol EnvironmentController {
+    // Terminates the environment.
+    //
+    // When an |Environment| is terminated, all applications launched
+    // in the environment (and in all transitively nested environments) are also
+    // killed.
+    Kill() -> ();
+
+    // Decouples the lifetime of the environment from this controller.
+    //
+    // After calling |Detach|, the environment will not be implicitly killed when
+    // this interface is closed.
+    Detach();
+
+    // Event that is triggered when the environment is created.
+    -> OnCreated();
+};
+
+// Maximum length for an environment label.
+const uint32 kLabelMaxLength = 32;
+
+struct EnvironmentOptions {
+    // True if this environment should inherit services provided by the
+    // parent environment.
+    bool inherit_parent_services;
+    // True if components in this environment can share a runner provided
+    // by the parent environment. If false, a new runner will be started
+    // in this environment for components.
+    bool allow_parent_runners;
+    // True if this environment should be killed first in out of memory
+    // situations by setting the ZX_PROP_JOB_KILL_ON_OOM property on this
+    // environment's job.
+    bool kill_on_oom;
+    // True if "persistent" storage requested by components in this environment should not actually
+    // be persistent, and instead be deleted when this environment is killed.
+    bool delete_storage_on_death;
+};
+
+// An interface for managing a set of applications.
+//
+// Applications run inside environments, which provide ambient services and
+// support for their lifecycle.
+[Discoverable]
+protocol Environment {
+    // Creates a new environment nested inside this environment.
+    //
+    // When applications are created inside the nested environment using the
+    // environment's |Launcher|, the environment requests the
+    // environment services from |host_directory| before passing those services to
+    // the newly created application in its |StartupInfo|.
+    //
+    // The |controller| can be used to control the lifecycle of the created
+    // environment. Note that by default the environment will be killed
+    // automatically when the |EnvironmentController|'s interface is closed. You
+    // can use |EnvironmentController.Detach| to disable this behavior.
+    //
+    // |label| defines the new environment's label/name. It must be unique within
+    // the parent environment (though not globally) and is used for isolating
+    // separate environments. It can also be used for diagnostic purposes. The
+    // label will be truncated if it is longer than |kLabelMaxLength|.
+    //
+    // |additional_services|, which may be empty, contains a list of services
+    // that the environment provides, which are hosted by
+    // |additional_services.host_directory|. If |options.inherit_parent_services|
+    // is false, |host_directory| must provide a |Loader| service if it wishes to
+    // allow new components to be loaded in the new environment.
+    //
+    // |options| provides additional options, see |EnvironmentOptions| for
+    // details.
+    CreateNestedEnvironment(request<Environment> environment,
+                            request<EnvironmentController> controller,
+                            string label,
+                            ServiceList? additional_services,
+                            EnvironmentOptions options);
+
+    // Gets the Launcher associated with this environment.
+    //
+    // Applications created using this application launcher will be given the
+    // environment services provided by this environment's |host_directory|.
+    GetLauncher(request<Launcher> launcher);
+
+    // Gets a superset of services provided by this environment's
+    // |host_directory|.
+    GetServices(request<ServiceProvider> services);
+
+    // Gets a superset of services provided by this environment's
+    // |host_directory|.
+    GetDirectory(handle<channel> directory_request);
+};
+
+struct FlatNamespace {
+  // The mount point for each of the directories below.
+  //
+  // For example, ["/pkg", "/svc"].
+  vector<string> paths;
+
+  // The directories mounted at each path in the namespace.
+  vector<handle<channel>> directories;
+};
+
+// An interface for providing a job handle. Instances of this interface are
+// created in the context of an already-identified realm, so there is no need
+// to explicitly identify the realm below.
+[Discoverable]
+protocol JobProvider {
+    // Gets the root job associated with the realm.
+    GetJob() -> (handle<job> job);
+};
+
+// An FDIO file descriptor.
+// TODO(abarth): Use the real FDIO declaration once FDIO converts to FIDL2.
+struct FileDescriptor {
+    // The FDIO types of the handle (e.g., FA_FDIO_REMOTE).
+    int32 type0;
+    int32 type1;
+    int32 type2;
+
+    // The handles for the file descriptor (e.g., a channel).
+    handle? handle0;
+    handle? handle1;
+    handle? handle2;
+};
+
+// Information used to create an instance of a component and obtain
+// services from it.
+struct LaunchInfo {
+    // The location from which to retrieve this component.
+    //
+    // This field will probably be replaced with a stronger notion of identity,
+    // such as an unforgeable token. This field is included in this iteration to
+    // ease the transition from the previous component interfaces.
+    string url;
+
+    // The arguments to be provided to the component.
+    vector<string>? arguments;
+
+    // The file descriptor to use for stdout.
+    //
+    // If null, the component will use the default stdout for the environment.
+    FileDescriptor? out;
+
+    // The file descriptor to use for stderr.
+    //
+    // If null, the component will use the default stderr for the environment.
+    FileDescriptor? err;
+
+    // The interface request for a Directory that is passed through to the
+    // component and arrives in the component as its |directory_request|
+    // interface request.
+    handle<channel>? directory_request;
+
+    // A custom namespace that can be appended to the namespace generated by
+    // appmgr and provided to this component.
+    // Adding a mount point at standard paths like 'pkg' or 'svc' will be ignored.
+    // HACK(alhaad): Adding mount points for deprecated default directories like
+    // '/data' will override the default.
+    FlatNamespace? flat_namespace;
+
+    // A list of services to be added to this component's svc namespace. These
+    // services are in addition to those coming from Environment.
+    ServiceList? additional_services;
+};
+
+struct ServiceList {
+    // A list of services that can be requested from |provider|.
+    vector<string> names;
+
+    // A service provider to get the services listed in |names| from.
+    ServiceProvider? provider;
+
+    // A channel to the directory hosting the services in |names|.
+    // TODO(CP-124): Support |host_directory| for CreateComponent and deprecate
+    // |provider|.
+    handle<channel>? host_directory;
+};
+
+// An interface for creating component instances.
+//
+// Typically obtained via |Environment.GetLauncher|.
+[Discoverable]
+protocol Launcher {
+    // Creates a new instance of the component described by |launch_info|.
+    //
+    // The component instance is created in the |Environment|
+    // associated with this |Launcher|. When creating the component,
+    // the environment requests the environment services for this component from
+    // its |EnvironmentHost|.
+    //
+    // The |controller| can be used to control the lifecycle of the created
+    // component instance. If an |ComponentController|'s interface is
+    // requested, the component instance is killed when the interface is closed.
+    CreateComponent(LaunchInfo launch_info,
+                    request<ComponentController>? controller);
+};
+
+// An interface for loading from pacakges.
+[Discoverable]
+protocol Loader {
+    // LoadUrl a package by url.
+    LoadUrl(string url) -> (Package? package);
+};
+
+// Information given to components at startup.
+//
+// For ELF binaries, this information is provided in the initialization message
+// given to libc by fuchsia.process.Launcher.
+struct StartupInfo {
+    // The launch info for the to start.
+    LaunchInfo launch_info;
+
+    // The namespace in which to run the component.
+    FlatNamespace flat_namespace;
+
+    // Key string value string map of the component's program metadata, obtained
+    // from its component manifest.
+    vector<ProgramMetadata>? program_metadata;
+
+    // TODO(abarth): Add more fields to this struct relating to component and
+    // environment identity.
+};
+
+// Program information about a component.
+struct ProgramMetadata {
+    // Key for program metadata pair. E.g. "binary" for an ELF binary component,
+    // or "data" for a flutter/dart component.
+    string key;
+
+    // Value for program metadata pair. E.g. "bin/app" for a "binary" key, or
+    // "data/foo" for a flutter/dart component.
+    string value;
+};
+
+// A binary representation of a component.
+//
+// Typically provided to |Runner.StartComponent| when starting a
+// component.
+struct Package {
+    // A read-only binary representation of the component. For example, if the
+    // component is intended to run in the Dart virtual machine, this data might
+    // contain a dartx package.
+    Buffer? data;
+
+    // A directory containing the contents of the package. For example, if the
+    // component is stored in pkgfs, this directory will be the pkgfs directory
+    // containing the package.
+    handle<channel>? directory;
+
+    // Resolved URL of the component. This is the url specified in startup_info
+    // after following redirects and resolving relative paths.
+    string resolved_url;
+};
+
+// An interface for running components.
+//
+// Typically exposed by components that provide execution environments for
+// particular classes of programs. For example, the Dart virtual machine exposes
+// this interface to run Dart programs.
+[Discoverable]
+protocol Runner {
+    // Execute the given component.
+    //
+    // Upon startup, the component is to be given the information in
+    // |startup_info|, but the mechanism by which the component receives that
+    // information is up to the component runner.
+    //
+    // The |controller| interface request typically originates from the
+    // |Launcher.CreateComponent| message that caused this
+    // component to be started.
+    StartComponent(Package package,
+                   StartupInfo startup_info,
+                   request<ComponentController>? controller);
+};
+
+// An interface through which a client may request services from a host.
+// Instances of this interface are created within the context of an
+// already-identified client and host pair, so there is no need to explicitly
+// identify the client or host in the methods below.
+//
+// This interface is deprecated.  Services should be published as directory
+// entries instead, just like files.
+// TODO(ZX-1358): Point to the FIDL interface for file I/O once RIO is migrated.
+protocol ServiceProvider {
+    // Asks the host to provide the service identified by |service_name| through
+    // the |channel| endpoint supplied by the caller. If the host is not willing
+    // or able to provide the requested service, it should close the |channel|.
+    ConnectToService(string service_name, handle<channel> channel);
+};
-- 
GitLab