Clean up Mojo embedder APIs
Some preparatory work for introducing new internal IPC protocol. Cleans
up how Mojo is initialized, deletes some dead code, reoganizes embedder
API surface and extends existing documentation, establishes the basic
concepts of broker and broker client processes, and introduces a nominal
unified API for managing physical process connections.
BUG=696031
TBR=alokp@chromium.org
TBR=tsepez@chromium.org
Change-Id: Ibb8750218dc672e73ecf46aa5c3cb540769d46a0
Reviewed-on: https://chromium-review.googlesource.com/495371
Reviewed-by: Ken Rockot <rockot@chromium.org>
Reviewed-by: Jay Civelli <jcivelli@chromium.org>
Commit-Queue: Ken Rockot <rockot@chromium.org>
Cr-Commit-Position: refs/heads/master@{#469351}
CrOS-Libchrome-Original-Commit: c7f6819e1e825876b2df2a3b5b378eebfe684c65
diff --git a/mojo/edk/embedder/configuration.h b/mojo/edk/embedder/configuration.h
index 1990fb1..d02b999 100644
--- a/mojo/edk/embedder/configuration.h
+++ b/mojo/edk/embedder/configuration.h
@@ -11,52 +11,34 @@
namespace mojo {
namespace edk {
-// A set of constants that the Mojo system internally uses. These values should
-// be consistent across all processes on the same system.
+// A set of configuration parameters that the Mojo system uses internally. The
+// configuration used can be overridden from the default by passing a
+// Configuration into |mojo::edk::Init()|. See embedder.h.
//
-// In general, there should be no need to change these values from their
-// defaults. However, if you do change them, you must do so before
-// initialization.
+// NOTE: Please ensure that this type remains a simple aggregate of POD fields.
struct Configuration {
- // Maximum number of open (Mojo) handles. The default is 1,000,000.
+ // Indicates whether this process should act as the sole broker process within
+ // its graph of interconnected Mojo-embedder processes. This setting is only
+ // relevant in multiprocess environments.
+ bool is_broker_process = false;
+
+ // If |true|, this process will always attempt to allocate shared memory
+ // directly rather than synchronously delegating to a broker process where
+ // applicable.
//
- // TODO(vtl): This doesn't count "live" handles, some of which may live in
- // messages.
- size_t max_handle_table_size;
+ // This is useful to set in processes which are not acting as the broker but
+ // which are otherwise sufficiently privileged to allocate named shared memory
+ // objects.
+ bool force_direct_shared_memory_allocation = false;
- // Maximum number of active memory mappings. The default is 1,000,000.
- size_t max_mapping_table_sze;
+ // Maximum number of active memory mappings.
+ size_t max_mapping_table_size = 1000000;
- // Maximum data size of messages sent over message pipes, in bytes. The
- // default is 4MB.
- size_t max_message_num_bytes;
+ // Maximum data size of messages sent over message pipes, in bytes.
+ size_t max_message_num_bytes = 256 * 1024 * 1024;
- // Maximum number of handles that can be attached to messages sent over
- // message pipes. The default is 10,000.
- size_t max_message_num_handles;
-
- // Maximum capacity of a data pipe, in bytes. The default is 256MB. This value
- // must fit into a |uint32_t|. WARNING: If you bump it closer to 2^32, you
- // must audit all the code to check that we don't overflow (2^31 would
- // definitely be risky; up to 2^30 is probably okay).
- size_t max_data_pipe_capacity_bytes;
-
- // Default data pipe capacity, if not specified explicitly in the creation
- // options. The default is 1MB.
- size_t default_data_pipe_capacity_bytes;
-
- // Alignment for the "start" of the data buffer used by data pipes. (The
- // alignment of elements will depend on this and the element size.) The
- // default is 16 bytes.
- size_t data_pipe_buffer_alignment_bytes;
-
- // Maximum size of a single shared memory segment, in bytes. The default is
- // 1GB.
- //
- // TODO(vtl): Set this hard limit appropriately (e.g., higher on 64-bit).
- // (This will also entail some auditing to make sure I'm not messing up my
- // checks anywhere.)
- size_t max_shared_memory_num_bytes;
+ // Maximum size of a single shared memory segment, in bytes.
+ size_t max_shared_memory_num_bytes = 1024 * 1024 * 1024;
};
} // namespace edk
diff --git a/mojo/edk/embedder/connection_params.cc b/mojo/edk/embedder/connection_params.cc
index 9b7ec54..92c343c 100644
--- a/mojo/edk/embedder/connection_params.cc
+++ b/mojo/edk/embedder/connection_params.cc
@@ -6,17 +6,28 @@
#include <utility>
+#include "base/logging.h"
+
namespace mojo {
namespace edk {
ConnectionParams::ConnectionParams(ScopedPlatformHandle channel)
- : channel_(std::move(channel)) {}
+ : ConnectionParams(TransportProtocol::kLegacy, std::move(channel)) {}
-ConnectionParams::ConnectionParams(ConnectionParams&& param)
- : channel_(std::move(param.channel_)) {}
+ConnectionParams::ConnectionParams(TransportProtocol protocol,
+ ScopedPlatformHandle channel)
+ : protocol_(protocol), channel_(std::move(channel)) {
+ // TODO(rockot): Support other protocols.
+ DCHECK_EQ(TransportProtocol::kLegacy, protocol);
+}
-ConnectionParams& ConnectionParams::operator=(ConnectionParams&& param) {
- channel_ = std::move(param.channel_);
+ConnectionParams::ConnectionParams(ConnectionParams&& params) {
+ *this = std::move(params);
+}
+
+ConnectionParams& ConnectionParams::operator=(ConnectionParams&& params) {
+ protocol_ = params.protocol_;
+ channel_ = std::move(params.channel_);
return *this;
}
diff --git a/mojo/edk/embedder/connection_params.h b/mojo/edk/embedder/connection_params.h
index 25ffdde..b6544b5 100644
--- a/mojo/edk/embedder/connection_params.h
+++ b/mojo/edk/embedder/connection_params.h
@@ -13,16 +13,57 @@
namespace mojo {
namespace edk {
+// A set of parameters used when establishing a connection to another process.
class MOJO_SYSTEM_IMPL_EXPORT ConnectionParams {
public:
+ // Selects the transport protocol to use when connecting to the remote
+ // process.
+ //
+ // New code should generally prefer to use |kAutomatic| to allow the protocol
+ // to be negotiated by the two processes involved in the connection. As noted
+ // below, this is not possible when either one of the two processes only
+ // supports the legacy protocol. In such cases both ends of the connection
+ // must be aware and explicitly use |kLegacy|, which is the default for now.
+ enum class TransportProtocol {
+ // Legacy transport protocol. Should only be used when connecting to
+ // embedders which may not support at least |kVersion0|. Deprecated.
+ kLegacy = -2,
+
+ // Automatically negotiate the transport protocol. This will ultimately
+ // select the highest protocol version supported by all of the calling
+ // process, the broker process (if any), and the target process.
+ //
+ // This may only be used when connecting to embedders which support at least
+ // |kVersion0|. Otherwise the deprecated |kLegacy| protocol must be used.
+ kAutomatic = -1,
+
+ // Protocol version 0. This is NOT backwards compatible with the legacy
+ // protocol. If this is used to establish a connection, the remote embedder
+ // (and the broker, if applicable) must also support at least version 0.
+ kVersion0 = 0,
+
+ // The maximum version supported by the current process. This must be
+ // updated if a new version is added.
+ kMaxSupportedVersion = kVersion0,
+ };
+
+ // Configures an OS pipe-based, |kBrokerClient| connection to the remote
+ // process using the legacy transport protocol.
explicit ConnectionParams(ScopedPlatformHandle channel);
- ConnectionParams(ConnectionParams&& param);
- ConnectionParams& operator=(ConnectionParams&& param);
+ // Configures an OS pipe-based connection of type |type| to the remote process
+ // using the given transport |protocol|.
+ ConnectionParams(TransportProtocol protocol, ScopedPlatformHandle channel);
+
+ ConnectionParams(ConnectionParams&& params);
+ ConnectionParams& operator=(ConnectionParams&& params);
+
+ TransportProtocol protocol() const { return protocol_; }
ScopedPlatformHandle TakeChannelHandle();
private:
+ TransportProtocol protocol_;
ScopedPlatformHandle channel_;
DISALLOW_COPY_AND_ASSIGN(ConnectionParams);
diff --git a/mojo/edk/embedder/embedder.cc b/mojo/edk/embedder/embedder.cc
index 0fdda5c..c72137d 100644
--- a/mojo/edk/embedder/embedder.cc
+++ b/mojo/edk/embedder/embedder.cc
@@ -18,6 +18,7 @@
#include "mojo/edk/embedder/embedder_internal.h"
#include "mojo/edk/embedder/entrypoints.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/edk/system/configuration.h"
#include "mojo/edk/system/core.h"
#include "mojo/edk/system/node_controller.h"
@@ -39,49 +40,38 @@
} // namespace internal
-void SetMaxMessageSize(size_t bytes) {
-}
+// Basic configuration/initialization ------------------------------------------
-void SetParentPipeHandle(ScopedPlatformHandle pipe) {
- CHECK(internal::g_core);
- internal::g_core->InitChild(ConnectionParams(std::move(pipe)));
-}
-
-void SetParentPipeHandleFromCommandLine() {
- ScopedPlatformHandle platform_channel =
- PlatformChannelPair::PassClientHandleFromParentProcess(
- *base::CommandLine::ForCurrentProcess());
- CHECK(platform_channel.is_valid());
- SetParentPipeHandle(std::move(platform_channel));
-}
-
-ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe) {
- return ConnectToPeerProcess(std::move(pipe), GenerateRandomToken());
-}
-
-ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe,
- const std::string& peer_token) {
- DCHECK(pipe.is_valid());
- DCHECK(!peer_token.empty());
- return internal::g_core->ConnectToPeerProcess(std::move(pipe), peer_token);
-}
-
-void ClosePeerConnection(const std::string& peer_token) {
- return internal::g_core->ClosePeerConnection(peer_token);
-}
-
-void Init() {
+void Init(const Configuration& configuration) {
MojoSystemThunks thunks = MakeSystemThunks();
size_t expected_size = MojoEmbedderSetSystemThunks(&thunks);
DCHECK_EQ(expected_size, sizeof(thunks));
- internal::g_core = new Core();
+ internal::g_configuration = configuration;
+ internal::g_core = new Core;
+}
+
+void Init() {
+ Init(Configuration());
}
void SetDefaultProcessErrorCallback(const ProcessErrorCallback& callback) {
internal::g_core->SetDefaultProcessErrorCallback(callback);
}
+std::string GenerateRandomToken() {
+ char random_bytes[16];
+#if defined(OS_NACL)
+ // Not secure. For NaCl only!
+ base::RandBytes(random_bytes, 16);
+#else
+ crypto::RandBytes(random_bytes, 16);
+#endif
+ return base::HexEncode(random_bytes, 16);
+}
+
+// Basic functions -------------------------------------------------------------
+
MojoResult CreatePlatformHandleWrapper(
ScopedPlatformHandle platform_handle,
MojoHandle* platform_handle_wrapper_handle) {
@@ -113,6 +103,13 @@
mojo_handle, shared_memory_handle, num_bytes, read_only);
}
+MojoResult SetProperty(MojoPropertyType type, const void* value) {
+ CHECK(internal::g_core);
+ return internal::g_core->SetProperty(type, value);
+}
+
+// Initialialization/shutdown for interprocess communication (IPC) -------------
+
void InitIPCSupport(scoped_refptr<base::TaskRunner> io_thread_task_runner) {
CHECK(internal::g_core);
internal::g_core->SetIOTaskRunner(io_thread_task_runner);
@@ -134,25 +131,39 @@
}
#endif
+// Legacy IPC Helpers ----------------------------------------------------------
+
+void SetParentPipeHandle(ScopedPlatformHandle pipe) {
+ CHECK(internal::g_core);
+ internal::g_core->InitChild(ConnectionParams(std::move(pipe)));
+}
+
+void SetParentPipeHandleFromCommandLine() {
+ ScopedPlatformHandle platform_channel =
+ PlatformChannelPair::PassClientHandleFromParentProcess(
+ *base::CommandLine::ForCurrentProcess());
+ CHECK(platform_channel.is_valid());
+ SetParentPipeHandle(std::move(platform_channel));
+}
+
+ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe) {
+ return ConnectToPeerProcess(std::move(pipe), GenerateRandomToken());
+}
+
+ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe,
+ const std::string& peer_token) {
+ DCHECK(pipe.is_valid());
+ DCHECK(!peer_token.empty());
+ return internal::g_core->ConnectToPeerProcess(std::move(pipe), peer_token);
+}
+
+void ClosePeerConnection(const std::string& peer_token) {
+ return internal::g_core->ClosePeerConnection(peer_token);
+}
+
ScopedMessagePipeHandle CreateChildMessagePipe(const std::string& token) {
return internal::g_core->CreateChildMessagePipe(token);
}
-std::string GenerateRandomToken() {
- char random_bytes[16];
-#if defined(OS_NACL)
- // Not secure. For NaCl only!
- base::RandBytes(random_bytes, 16);
-#else
- crypto::RandBytes(random_bytes, 16);
-#endif
- return base::HexEncode(random_bytes, 16);
-}
-
-MojoResult SetProperty(MojoPropertyType type, const void* value) {
- CHECK(internal::g_core);
- return internal::g_core->SetProperty(type, value);
-}
-
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/embedder/embedder.h b/mojo/edk/embedder/embedder.h
index e3122c6..1e90b54 100644
--- a/mojo/edk/embedder/embedder.h
+++ b/mojo/edk/embedder/embedder.h
@@ -16,6 +16,8 @@
#include "base/memory/shared_memory_handle.h"
#include "base/process/process_handle.h"
#include "base/task_runner.h"
+#include "mojo/edk/embedder/configuration.h"
+#include "mojo/edk/embedder/connection_params.h"
#include "mojo/edk/embedder/pending_process_connection.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
#include "mojo/edk/system/system_impl_export.h"
@@ -30,53 +32,29 @@
// Basic configuration/initialization ------------------------------------------
-// |Init()| sets up the basic Mojo system environment, making the |Mojo...()|
-// functions available and functional. This is never shut down (except in tests
-// -- see test_embedder.h).
-
-// Allows changing the default max message size. Must be called before Init.
-MOJO_SYSTEM_IMPL_EXPORT void SetMaxMessageSize(size_t bytes);
-
-// Should be called as early as possible in a child process with a handle to the
-// other end of a pipe provided in the parent to
-// PendingProcessConnection::Connect.
-MOJO_SYSTEM_IMPL_EXPORT void SetParentPipeHandle(ScopedPlatformHandle pipe);
-
-// Same as above but extracts the pipe handle from the command line. See
-// PlatformChannelPair for details.
-MOJO_SYSTEM_IMPL_EXPORT void SetParentPipeHandleFromCommandLine();
-
-// Called to connect to a peer process. This should be called only if there
-// is no common ancestor for the processes involved within this mojo system.
-// Both processes must call this function, each passing one end of a platform
-// channel. This returns one end of a message pipe to each process.
-MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
-ConnectToPeerProcess(ScopedPlatformHandle pipe);
-
-// Called to connect to a peer process. This should be called only if there
-// is no common ancestor for the processes involved within this mojo system.
-// Both processes must call this function, each passing one end of a platform
-// channel. This returns one end of a message pipe to each process. |peer_token|
-// may be passed to ClosePeerConnection() to close the connection.
-MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
-ConnectToPeerProcess(ScopedPlatformHandle pipe, const std::string& peer_token);
-
-// Closes a connection to a peer process created by ConnectToPeerProcess()
-// where the same |peer_token| was used.
-MOJO_SYSTEM_IMPL_EXPORT void ClosePeerConnection(const std::string& peer_token);
-
// Must be called first, or just after setting configuration parameters, to
-// initialize the (global, singleton) system.
+// initialize the (global, singleton) system state. There is no corresponding
+// shutdown operation: once the EDK is initialized, public Mojo C API calls
+// remain available for the remainder of the process's lifetime.
+MOJO_SYSTEM_IMPL_EXPORT void Init(const Configuration& configuration);
+
+// Like above but uses a default Configuration.
MOJO_SYSTEM_IMPL_EXPORT void Init();
// Sets a default callback to invoke when an internal error is reported but
-// cannot be associated with a specific child process.
+// cannot be associated with a specific child process. Calling this is optional.
MOJO_SYSTEM_IMPL_EXPORT void SetDefaultProcessErrorCallback(
const ProcessErrorCallback& callback);
-// Basic functions -------------------------------------------------------------
+// Generates a random ASCII token string for use with various APIs that expect
+// a globally unique token string. May be called at any time on any thread.
+MOJO_SYSTEM_IMPL_EXPORT std::string GenerateRandomToken();
-// The functions in this section are available once |Init()| has been called.
+// Basic functions -------------------------------------------------------------
+//
+// The functions in this section are available once |Init()| has been called and
+// provide the embedder with some extra capabilities not exposed by public Mojo
+// C APIs.
// Creates a |MojoHandle| that wraps the given |PlatformHandle| (taking
// ownership of it). This |MojoHandle| can then, e.g., be passed through message
@@ -118,11 +96,20 @@
size_t* num_bytes,
bool* read_only);
+// Sets system properties that can be read by the MojoGetProperty() API. See the
+// documentation for MojoPropertyType for supported property types and their
+// corresponding value type.
+//
+// Default property values:
+// |MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED| - true
+MOJO_SYSTEM_IMPL_EXPORT MojoResult SetProperty(MojoPropertyType type,
+ const void* value);
+
// Initialialization/shutdown for interprocess communication (IPC) -------------
// |InitIPCSupport()| sets up the subsystem for interprocess communication,
// making the IPC functions (in the following section) available and functional.
-// (This may only be done after |Init()|.)
+// This may only be done after |Init()|.
//
// This subsystem may be shut down using |ShutdownIPCSupport()|. None of the IPC
// functions may be called after this is called.
@@ -144,29 +131,57 @@
#if defined(OS_MACOSX) && !defined(OS_IOS)
// Set the |base::PortProvider| for this process. Can be called on any thread,
// but must be set in the root process before any Mach ports can be transferred.
+//
+// If called at all, this must be called after |InitIPCSupport()| and before the
+// creation of any PendingProcessConnection instances.
MOJO_SYSTEM_IMPL_EXPORT void SetMachPortProvider(
base::PortProvider* port_provider);
#endif
+// Legacy IPC Helpers ----------------------------------------------------------
+//
+// Functions in this section are used to help connect processes together via the
+// legacy transport protocol. All functions in this section should be considered
+// DEPRECATED.
+//
+// Use PendingProcessConnection to establish connections to other Mojo
+// embedder processes in the system. See the documentation in
+// pending_process_connection.h for details.
+
+// Should be called as early as possible in a child process with a handle to the
+// other end of a pipe provided in the parent to
+// PendingProcessConnection::Connect.
+MOJO_SYSTEM_IMPL_EXPORT void SetParentPipeHandle(ScopedPlatformHandle pipe);
+
+// Same as above but extracts the pipe handle from the command line. See
+// PlatformChannelPair for details.
+MOJO_SYSTEM_IMPL_EXPORT void SetParentPipeHandleFromCommandLine();
+
+// Called to connect to a peer process. This should be called only if there
+// is no common ancestor for the processes involved within this mojo system.
+// Both processes must call this function, each passing one end of a platform
+// channel. This returns one end of a message pipe to each process.
+MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
+ConnectToPeerProcess(ScopedPlatformHandle pipe);
+
+// Called to connect to a peer process. This should be called only if there
+// is no common ancestor for the processes involved within this mojo system.
+// Both processes must call this function, each passing one end of a platform
+// channel. This returns one end of a message pipe to each process. |peer_token|
+// may be passed to ClosePeerConnection() to close the connection.
+MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
+ConnectToPeerProcess(ScopedPlatformHandle pipe, const std::string& peer_token);
+
+// Closes a connection to a peer process created by ConnectToPeerProcess()
+// where the same |peer_token| was used.
+MOJO_SYSTEM_IMPL_EXPORT void ClosePeerConnection(const std::string& peer_token);
+
// Creates a message pipe from a token in a child process. This token must have
// been acquired by a corresponding call to
// PendingProcessConnection::CreateMessagePipe.
MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
CreateChildMessagePipe(const std::string& token);
-// Generates a random ASCII token string for use with various APIs that expect
-// a globally unique token string.
-MOJO_SYSTEM_IMPL_EXPORT std::string GenerateRandomToken();
-
-// Sets system properties that can be read by the MojoGetProperty() API. See the
-// documentation for MojoPropertyType for supported property types and their
-// corresponding value type.
-//
-// Default property values:
-// |MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED| - true
-MOJO_SYSTEM_IMPL_EXPORT MojoResult SetProperty(MojoPropertyType type,
- const void* value);
-
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/embedder/pending_process_connection.cc b/mojo/edk/embedder/pending_process_connection.cc
index d6be76e..40c8166 100644
--- a/mojo/edk/embedder/pending_process_connection.cc
+++ b/mojo/edk/embedder/pending_process_connection.cc
@@ -12,8 +12,14 @@
namespace edk {
PendingProcessConnection::PendingProcessConnection()
- : process_token_(GenerateRandomToken()) {
+ : PendingProcessConnection(Type::kBrokerIntroduction) {}
+
+PendingProcessConnection::PendingProcessConnection(Type type)
+ : type_(type), process_token_(GenerateRandomToken()) {
DCHECK(internal::g_core);
+
+ // TODO(rockot): Support other process connection types.
+ DCHECK_EQ(Type::kBrokerIntroduction, type_);
}
PendingProcessConnection::~PendingProcessConnection() {
@@ -27,10 +33,18 @@
std::string* token) {
has_message_pipes_ = true;
DCHECK(internal::g_core);
+ DCHECK_EQ(Type::kBrokerIntroduction, type_);
*token = GenerateRandomToken();
return internal::g_core->CreateParentMessagePipe(*token, process_token_);
}
+ScopedMessagePipeHandle PendingProcessConnection::CreateMessagePipe(
+ const std::string& name) {
+ // TODO(rockot): Implement this.
+ NOTREACHED();
+ return ScopedMessagePipeHandle();
+}
+
void PendingProcessConnection::Connect(
base::ProcessHandle process,
ConnectionParams connection_params,
diff --git a/mojo/edk/embedder/pending_process_connection.h b/mojo/edk/embedder/pending_process_connection.h
index ca18227..ac48628 100644
--- a/mojo/edk/embedder/pending_process_connection.h
+++ b/mojo/edk/embedder/pending_process_connection.h
@@ -20,11 +20,16 @@
using ProcessErrorCallback = base::Callback<void(const std::string& error)>;
-// Represents a potential connection to an external process. Use this object
-// to make other processes reachable from this one via Mojo IPC. Typical usage
-// might look something like:
+// Represents a potential connection to an external process.
//
-// PendingProcessConnection connection;
+// NOTE: This class must only be used while IPC support is active. See
+// documentation for |InitIPCSupport()| in embedder.h or ScopedIPCSupport in
+// scoped_ipc_support.h.
+//
+// Precise usage depends on the nature of the relationship between the calling
+// process and the remote process, but a typical use might look something like:
+//
+// mojo::edk::PendingProcessConnection connection;
//
// std::string pipe_token;
// ScopedMessagePipeHandle pipe = connection.CreateMessagePipe(&pipe_token);
@@ -33,7 +38,7 @@
// // away, even if the process doesn't exist yet.
// GoDoSomethingInteresting(std::move(pipe));
//
-// ScopedPlatformChannelPair channel;
+// mojo::edk::ScopedPlatformChannelPair channel;
//
// // Give the pipe token to the child process via command-line.
// child_command_line.AppendSwitchASCII("yer-pipe", pipe_token);
@@ -43,19 +48,30 @@
// LaunchProcess(child_command_line, channel.PassClientHandle());
//
// // Some time later...
-// connection.Connect(new_process, channel.PassServerHandle());
+// connection.Connect(
+// new_process,
+// mojo::edk::ConnectionParams(
+// mojo::edk::ConnectionParams::ConnectionType::kBrokerIntroduction,
+// mojo::edk::ConnectionParams::TransportProtocol::kAutomatic,
+// channel.PassServerHandle()));
//
-// If at any point during the above process, |connection| is destroyed before
-// Connect() can be called, |pipe| will imminently behave as if its peer has
-// been closed.
+// If |connection| is destroyed before Connect() can be called, any pipe
+// created by |connection.CreateMessagePipe()| will imminently behave as if its
+// peer has been closed.
//
-// Otherwise, if the remote process in this example eventually calls:
+// Otherwise if the remote process in this example eventually executes:
//
-// mojo::edk::SetParentPipeHandle(std::move(client_channel_handle));
+// mojo::edk::PendingProcessConnection connection;
//
// std::string token = command_line.GetSwitchValueASCII("yer-pipe");
// ScopedMessagePipeHandle pipe = mojo::edk::CreateChildMessagePipe(token);
//
+// connection.Connect(
+// base::kNullProcessHandle,
+// mojo::edk::ConnectionParams(
+// mojo::edk::ConnectionParams::ConnectionType::kBrokerClient,
+// mojo::edk::ConnectionParams::TransportProtocol::kAutomatic))
+//
// it will be connected to this process, and its |pipe| will be connected to
// this process's |pipe|.
//
@@ -63,10 +79,68 @@
// before calling CreateChildMessagePipe for a given message pipe token,
// this process's end of the corresponding message pipe will imminently behave
// as if its peer has been closed.
-//
class MOJO_SYSTEM_IMPL_EXPORT PendingProcessConnection {
public:
+ // Selects the type of connection to establish to the remote process. The
+ // value names here correspond to the local process's role in the pending
+ // connection.
+ enum class Type {
+ // Connect the process as a broker client. In this case, the remote process
+ // must either be the broker itself or another broker client, and its end
+ // of the connection must be constructed as |Type::kBrokerIntroduction|.
+ //
+ // Processes connected in this way become fully functional broker clients
+ // and can thus seamlessly send and receive platform object handles to and
+ // from the broker and/or any other broker client in the graph of connected
+ // processes.
+ kBrokerClient,
+
+ // Connect to the process and introduce it to the broker. This is used to
+ // introduce new broker clients into the calling process's process graph and
+ // may be used by either the broker itself or by any established broker
+ // client who wishes to introduce a new broker client process.
+ //
+ // The other end of the ConnectionParams' underlying connection primitive
+ // (e.g. the other end of the channel pipe) must be used to connect a
+ // PendingProcessConnection of type |Type::kBrokerClient| within the
+ // remote process.
+ kBrokerIntroduction,
+
+ // Connect to the process as a peer. This may be used to interconnect two
+ // processes in a way that does not support any kind of mutual brokering,
+ // i.e. a one-off interprocess connection.
+ //
+ // Both ends of the ConnectionParams' underlying connection primitive
+ // (e.g. both ends of the channel pipe) must ultimately be connected in
+ // either process using a PendingProcessConnection of this type.
+ //
+ // Such connections do NOT guarantee any kind of support for platform handle
+ // transmission over message pipes or introduction to any other processes
+ // in either peer's graph of connected processes. Mojo handle transmission
+ // from either peer to some other process in the other peer's extended
+ // process graph may arbitrarily fail without explanation.
+ //
+ // This connection type should be used rarely, only when it's impossible to
+ // make any guarantees about the relative lifetime of the two processes;
+ // when there is no suitable broker process in the system; and/or when it's
+ // impossible for at least one of the two processes to acquire a
+ // |base::ProcessHandle| to the other.
+ kPeer,
+ };
+
+ // Constructs a PendingProcessConnection of type |Type::kBrokerIntroduction|.
+ // This exists to support legacy code which used PendingProcessConnection
+ // before different connection types were supported.
+ //
+ // DEPRECATED. Please use the explicit signature below.
+ //
+ // TODO(rockot): Remove this constructor.
PendingProcessConnection();
+
+ // Constructs a PendingProcessConnection of the given |type|. See the
+ // documentation for Type above.
+ explicit PendingProcessConnection(Type type);
+
~PendingProcessConnection();
// Creates a message pipe associated with a new globally unique string value
@@ -84,28 +158,60 @@
// pipes to the same remote process. This call ALWAYS succeeds, returning
// a valid message pipe handle and populating |*token| with a new unique
// string value.
+ //
+ // DEPRECATED: The version of CreateMessagePipe below should be preferred to
+ // this one. There is no compelling reason to randomly generate token strings
+ // and it is generally more convenient for embedders to use fixed name values
+ // on each end of a connection.
ScopedMessagePipeHandle CreateMessagePipe(std::string* token);
- // Connects to the process. This must be called at most once, with the process
- // handle in |process|.
+ // Like above, this creates a message pipe whose other end is obtainable in
+ // the remote process. Unlike above, the pipe is associated with an arbitrary
+ // |name| given by the caller rather than a randomly generated token string.
//
- // |connection_param| contains the platform handle of an OS pipe which can be
- // used to communicate with the connected process. The other end of that pipe
- // must ultimately be passed to mojo::edk::SetParentPipeHandle in the remote
- // process, and getting that end of the pipe into the other process is the
- // embedder's responsibility.
+ // |name| must be unique within the context of this PendingProcessConnection
+ // instance, but it's fine to have multiple PendingProcessConnections use the
+ // same |name| to each create a unique pipe. In other words, the value of
+ // |name| is always scoped to the PendingProcessConnection instance.
+ //
+ // The remote process can acquire the other end of the returned pipe by
+ // passing the same name to CreateMessagePipe on a corresponding
+ // PendingProcessConnection. In general, |name| is some string which is
+ // already agreed upon ahead of time, typically hard-coded into both processes
+ // on either end of the connection.
+ //
+ // NOTE: It's important to ensure that on kBrokerIntroduction/kBrokerClient
+ // connections using kLegacy protocol, the kBrokerIntroduction side must have
+ // already created a named pipe by the time the kBrokerClient side attempts to
+ // use the same name; otherwise the behavior is racy. This restriction does
+ // not apply to symmetrical kPeer/kPeer connections or to any type of
+ // connection using a newer (>= kVersion0) TransportProtocol.
+ ScopedMessagePipeHandle CreateMessagePipe(const std::string& name);
+
+ // Connects to the process. This must be called at most once, with the process
+ // handle in |process|. If the process handle is unknown (as is often the case
+ // in broker client processes), it should be |base::kNullProcessHandle|.
+ //
+ // |connection_params| contains details specifying the precise nature of the
+ // connection, including one half of some underlying OS IPC primitive (e.g.
+ // a socket FD) to be used for physical transport. The other half must be
+ // provided to a corresponding PendingProcessConnection in the remote process.
+ // See the documentation for ConnectionParams in connection_params.h.
//
// If this method is not called by the time the PendingProcessConnection is
// destroyed, it's assumed that the process is unavailable (e.g. process
// launch failed or the process has otherwise been terminated early), and
- // any associated resources, such as remote endpoints of messages pipes
- // created by CreateMessagePipe above) will be cleaned up at that time.
+ // any associated resources will be cleaned up at that time. Message pipe
+ // handles returned by |CreateMessagePipe()| above will appear to have their
+ // peers closed at this time as well.
void Connect(
base::ProcessHandle process,
ConnectionParams connection_params,
const ProcessErrorCallback& error_callback = ProcessErrorCallback());
private:
+ const Type type_;
+
// A GUID representing a potential new process to be connected to this one.
const std::string process_token_;
diff --git a/mojo/edk/system/channel.cc b/mojo/edk/system/channel.cc
index 8a44d36..7ded3dd 100644
--- a/mojo/edk/system/channel.cc
+++ b/mojo/edk/system/channel.cc
@@ -14,7 +14,10 @@
#include "base/macros.h"
#include "base/memory/aligned_memory.h"
#include "base/process/process_handle.h"
+#include "mojo/edk/embedder/embedder_internal.h"
#include "mojo/edk/embedder/platform_handle.h"
+#include "mojo/edk/system/configuration.h"
+#include "mojo/edk/system/core.h"
#if defined(OS_MACOSX) && !defined(OS_IOS)
#include "base/mac/mach_logging.h"
@@ -49,7 +52,6 @@
const size_t kReadBufferSize = 4096;
const size_t kMaxUnusedReadBufferCapacity = 4096;
-const size_t kMaxChannelMessageSize = 256 * 1024 * 1024;
const size_t kMaxAttachedHandles = 128;
Channel::Message::Message(size_t payload_size, size_t max_handles)
@@ -587,8 +589,9 @@
reinterpret_cast<const Message::LegacyHeader*>(
read_buffer_->occupied_bytes());
+ const size_t kMaxMessageSize = GetConfiguration().max_message_num_bytes;
if (legacy_header->num_bytes < sizeof(Message::LegacyHeader) ||
- legacy_header->num_bytes > kMaxChannelMessageSize) {
+ legacy_header->num_bytes > kMaxMessageSize) {
LOG(ERROR) << "Invalid message size: " << legacy_header->num_bytes;
return false;
}
diff --git a/mojo/edk/system/configuration.cc b/mojo/edk/system/configuration.cc
index f5eb2b8..f9a5d10 100644
--- a/mojo/edk/system/configuration.cc
+++ b/mojo/edk/system/configuration.cc
@@ -8,17 +8,7 @@
namespace edk {
namespace internal {
-// These default values should be synced with the documentation in
-// mojo/edk/embedder/configuration.h.
-Configuration g_configuration = {
- 1000000, // max_handle_table_size
- 1000000, // max_mapping_table_sze
- 4 * 1024 * 1024, // max_message_num_bytes
- 10000, // max_message_num_handles
- 256 * 1024 * 1024, // max_data_pipe_capacity_bytes
- 1024 * 1024, // default_data_pipe_capacity_bytes
- 16, // data_pipe_buffer_alignment_bytes
- 1024 * 1024 * 1024}; // max_shared_memory_num_bytes
+Configuration g_configuration;
} // namespace internal
} // namespace edk
diff --git a/mojo/edk/system/configuration.h b/mojo/edk/system/configuration.h
index 038835f..489d20b 100644
--- a/mojo/edk/system/configuration.h
+++ b/mojo/edk/system/configuration.h
@@ -19,10 +19,6 @@
return internal::g_configuration;
}
-MOJO_SYSTEM_IMPL_EXPORT inline Configuration* GetMutableConfiguration() {
- return &internal::g_configuration;
-}
-
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/system/mapping_table.cc b/mojo/edk/system/mapping_table.cc
index 8509443..4b8fa61 100644
--- a/mojo/edk/system/mapping_table.cc
+++ b/mojo/edk/system/mapping_table.cc
@@ -24,7 +24,7 @@
DCHECK(mapping);
if (address_to_mapping_map_.size() >=
- GetConfiguration().max_mapping_table_sze)
+ GetConfiguration().max_mapping_table_size)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
void* address = mapping->GetBase();
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc
index 73b16b1..4c5065a 100644
--- a/mojo/edk/system/node_controller.cc
+++ b/mojo/edk/system/node_controller.cc
@@ -23,6 +23,7 @@
#include "mojo/edk/embedder/platform_channel_pair.h"
#include "mojo/edk/system/broker.h"
#include "mojo/edk/system/broker_host.h"
+#include "mojo/edk/system/configuration.h"
#include "mojo/edk/system/core.h"
#include "mojo/edk/system/ports_message.h"
#include "mojo/edk/system/request_context.h"
@@ -233,6 +234,7 @@
}
void NodeController::ConnectToParent(ConnectionParams connection_params) {
+ DCHECK(!GetConfiguration().is_broker_process);
#if !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
// Use the bootstrap channel for the broker and receive the node's channel
// synchronously as the first message from the broker.
@@ -363,12 +365,9 @@
size_t num_bytes) {
#if !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
// Shared buffer creation failure is fatal, so always use the broker when we
- // have one. This does mean that a non-root process that has children will use
- // the broker for shared buffer creation even though that process is
- // privileged.
- if (broker_) {
+ // have one; unless of course the embedder forces us not to.
+ if (!GetConfiguration().force_direct_shared_memory_allocation && broker_)
return broker_->GetSharedBuffer(num_bytes);
- }
#endif
return PlatformSharedBuffer::Create(num_bytes);
}
@@ -516,6 +515,9 @@
}
scoped_refptr<NodeChannel> NodeController::GetBrokerChannel() {
+ if (GetConfiguration().is_broker_process)
+ return nullptr;
+
ports::NodeName broker_name;
{
base::AutoLock lock(broker_lock_);
@@ -657,7 +659,7 @@
// the broker to relay for us.
scoped_refptr<NodeChannel> broker = GetBrokerChannel();
if (!peer || !peer->HasRemoteProcessHandle()) {
- if (broker) {
+ if (!GetConfiguration().is_broker_process && broker) {
broker->RelayPortsMessage(name, std::move(channel_message));
} else {
base::AutoLock lock(broker_lock_);
@@ -671,11 +673,12 @@
// Messages containing Mach ports are always routed through the broker, even
// if the broker process is the intended recipient.
bool use_broker = false;
- {
+ if (!GetConfiguration().is_broker_process) {
base::AutoLock lock(parent_lock_);
use_broker = (bootstrap_parent_channel_ ||
parent_name_ != ports::kInvalidNodeName);
}
+
if (use_broker) {
scoped_refptr<NodeChannel> broker = GetBrokerChannel();
if (broker) {
@@ -1051,6 +1054,8 @@
void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node,
const ports::NodeName& broker_name,
ScopedPlatformHandle broker_channel) {
+ DCHECK(!GetConfiguration().is_broker_process);
+
// This node should already have a parent in bootstrap mode.
ports::NodeName parent_name;
scoped_refptr<NodeChannel> parent;