| // 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. |
| |
| #ifndef CHROMEOS_COMPONENTS_MOJO_BOOTSTRAP_PENDING_CONNECTION_MANAGER_H_ |
| #define CHROMEOS_COMPONENTS_MOJO_BOOTSTRAP_PENDING_CONNECTION_MANAGER_H_ |
| |
| #include <string> |
| |
| #include "base/callback.h" |
| #include "base/compiler_specific.h" |
| #include "base/component_export.h" |
| #include "base/containers/flat_map.h" |
| #include "base/files/scoped_file.h" |
| #include "base/macros.h" |
| #include "base/no_destructor.h" |
| #include "base/unguessable_token.h" |
| |
| namespace mojo_bootstrap { |
| |
| class PendingConnectionManagerTest; |
| |
| // PendingConnectionManager is used to wait for a unix domain socket to be used |
| // for bootstrapping a Mojo connection. The typical use case is where a system |
| // service is started by Chrome, but only text arguments can be passed to the |
| // service startup. An example of this are filesystems mounted by cros-disks, |
| // where only an array of strings can be passed as options to the Mount() D-Bus |
| // method. This class is NOT needed if a socket end can be passed to the system |
| // service directly. |
| // |
| // To use this class: |
| // 1. Create and export a D-Bus service in Chrome containing a single method |
| // which is passed a string and FD. (eg. org.chromium.DriveFileStream). |
| // This method simply calls PendingConnectionManager::OpenIpcChannel(). |
| // 2. Create an UnguessableToken and pass the string serialisation to the system |
| // service. Use PendingConnectionManager::ExpectOpenIpcChannel() to wait for |
| // an FD. |
| // 3. In the system service, create a socketpair() and pass one end over the |
| // D-Bus method created in step 1, along with the token. |
| // |
| // Sample usage: |
| // --- Chrome --- |
| // class MyClass { |
| // private: |
| // const base::UnguessableToken token_; |
| // mojo::OutgoingInvitation invitation_; |
| // }; |
| // |
| // MyClass::MyClass() : token_(base::UnguessableToken::Create()) {} |
| // |
| // void MyClass::StartService() { |
| // // Use this message pipe to bind an InterfacePtr<> to the Mojo service. |
| // mojo::ScopedMessagePipeHandle bootstrap_handle = |
| // invitation_.AttachMessagePipe("myservice-bootstrap"); |
| // |
| // base::UnguessableToken token = base::UnguessableToken::Create(); |
| // PendingConnectionManager::Get().ExpectOpenIpcChannel( |
| // token_, base::BindOnce(&MyClass::AcceptConnection, |
| // base::Unretained(this))); |
| // StartMySystemService(token_.ToString()); |
| // } |
| // |
| // void MyClass::AcceptConnection(base::ScopedFD handle) { |
| // mojo::OutgoingInvitation::Send( |
| // std::move(invitation_), base::kNullProcessHandle, |
| // mojo::PlatformChannelEndpoint( |
| // mojo::PlatformHandle(std::move(handle)))); |
| // } |
| // |
| // void MyClass::MyExportedDbusConnectMethod( |
| // dbus::MethodCall* method_call, |
| // dbus::ExportedObject::ResponseSender response_sender) { |
| // std::string token = // Pop token passed to StartMySystemService() |
| // base::ScopedFD fd = // Pop FD |
| // CHECK(PendingConnectionManager::Get().OpenIpcChannel( |
| // token, std::move(fd))); |
| // } |
| // |
| // --- System Service --- |
| // // Returns an InterfaceRequest<> that can be used to bind the Mojo service |
| // // implementation. |
| // mojom::MyServiceRequest MyService::BootstrapMojo() { |
| // mojo::edk::PlatformChannelPair channel; |
| // org::chromium::MyChromeServiceProxy dbus_proxy(bus_, kServiceName); |
| // brillo::ErrorPtr error; |
| // CHECK(dbus_proxy.MyExportedDbusConnectMethod( |
| // token_, channel.PassClientHandle().get().handle, &error)); |
| // mojo::edk::SetParentPipeHandle(channel.PassServerHandle()); |
| // |
| // mojom::MyServiceRequest request; |
| // request.Bind(mojo::edk::CreateChildMessagePipe("myservice-bootstrap")); |
| // return request; |
| // } |
| class COMPONENT_EXPORT(MOJO_BOOTSTRAP) PendingConnectionManager { |
| public: |
| using OpenIpcChannelCallback = base::OnceCallback<void(base::ScopedFD)>; |
| |
| static PendingConnectionManager& Get(); |
| |
| // Responds to a file descriptor request for |token| with |fd|. |token| is the |
| // UnguessableToken::ToString() representation of the |token| parameter to |
| // ExpectOpenIpcChannel(). |
| bool OpenIpcChannel(const std::string& token, base::ScopedFD ipc_channel); |
| |
| // Registers a callback that is run when a file descriptor is received for |
| // |token|. |
| void ExpectOpenIpcChannel(base::UnguessableToken token, |
| OpenIpcChannelCallback handler); |
| |
| // Cancels the pending callback for |token|. |
| void CancelExpectedOpenIpcChannel(base::UnguessableToken token); |
| |
| private: |
| friend class base::NoDestructor<PendingConnectionManager>; |
| friend class PendingConnectionManagerTest; |
| |
| PendingConnectionManager(); |
| ~PendingConnectionManager(); |
| |
| base::flat_map<std::string, OpenIpcChannelCallback> |
| open_ipc_channel_callbacks_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PendingConnectionManager); |
| }; |
| |
| } // namespace mojo_bootstrap |
| |
| #endif // CHROMEOS_COMPONENTS_MOJO_BOOTSTRAP_PENDING_CONNECTION_MANAGER_H_ |