Home | History | Annotate | only in /external/libmojo/mojo/edk/embedder
Up to higher level directory
NameDateSize
BUILD.gn21-Aug-20183.3K
configuration.h21-Aug-20182.5K
connection_params.cc21-Aug-2018749
connection_params.h21-Aug-2018908
embedder.cc21-Aug-20184.6K
embedder.h21-Aug-20187.7K
embedder_internal.h21-Aug-20181K
embedder_unittest.cc21-Aug-201823.5K
entrypoints.cc21-Aug-201812.2K
entrypoints.h21-Aug-2018696
named_platform_channel_pair.h21-Aug-20182.6K
named_platform_handle.h21-Aug-20181.4K
pending_process_connection.cc21-Aug-20181.5K
pending_process_connection.h21-Aug-20185K
platform_channel_pair.cc21-Aug-2018818
platform_channel_pair.h21-Aug-20184.2K
platform_channel_pair_posix.cc21-Aug-20185.7K
platform_channel_pair_posix_unittest.cc21-Aug-20189.2K
platform_channel_pair_win.cc21-Aug-20184.6K
platform_channel_utils_posix.cc21-Aug-20188.9K
platform_channel_utils_posix.h21-Aug-20184K
platform_handle.cc21-Aug-20182.3K
platform_handle.h21-Aug-20182.5K
platform_handle_utils.h21-Aug-20181.1K
platform_handle_utils_posix.cc21-Aug-2018733
platform_handle_utils_win.cc21-Aug-2018866
platform_handle_vector.h21-Aug-20181.1K
platform_shared_buffer.cc21-Aug-20189.3K
platform_shared_buffer.h21-Aug-20186.5K
README.md21-Aug-201810.7K
scoped_platform_handle.h21-Aug-20181.7K
test_embedder.cc21-Aug-20181K
test_embedder.h21-Aug-2018978

README.md

      1 # Mojo Embedder Development Kit (EDK)
      2 
      3 The Mojo EDK is a (binary-unstable) API which enables a process to use Mojo both
      4 internally and for IPC to other Mojo-embedding processes.
      5 
      6 Using any of the API surface in `//mojo/edk/embedder` requires (somewhat
      7 confusingly) a direct dependency on the GN `//mojo/edk/system` target. Despite
      8 this fact, you should never reference any of the headers in `mojo/edk/system`
      9 directly, as everything there is considered to be an internal detail of the EDK.
     10 
     11 ## Basic Initialization
     12 
     13 In order to use Mojo in a given process, it's necessary to call
     14 `mojo::edk::Init` exactly once:
     15 
     16 ```
     17 #include "mojo/edk/embedder/embedder.h"
     18 
     19 int main(int argc, char** argv) {
     20   mojo::edk::Init();
     21 
     22   // Now you can create message pipes, write messages, etc
     23 
     24   return 0;
     25 }
     26 ```
     27 
     28 As it happens though, Mojo is less useful without some kind of IPC support as
     29 well, and that's a second initialization step.
     30 
     31 ## IPC Initialization
     32 
     33 You also need to provide the system with a background TaskRunner on which it can
     34 watch for inbound I/O from any of the various other processes you will later
     35 connect to it.
     36 
     37 Here we'll just create a new background thread for IPC and let Mojo use that.
     38 Note that in Chromium, we use the existing "IO thread" in the browser process
     39 and content child processes.
     40 
     41 ```
     42 #include "base/threading/thread.h"
     43 #include "mojo/edk/embedder/embedder.h"
     44 #include "mojo/edk/embedder/scoped_ipc_support.h"
     45 
     46 int main(int argc, char** argv) {
     47   mojo::edk::Init();
     48 
     49   base::Thread ipc_thread("ipc!");
     50   ipc_thread.StartWithOptions(
     51       base::Thread::Options(base::MessageLoop::TYPE_IO));
     52 
     53   // As long as this object is alive, all EDK API surface relevant to IPC
     54   // connections is usable and message pipes which span a process boundary will
     55   // continue to function.
     56   mojo::edk::ScopedIPCSupport ipc_support(
     57       ipc_thread.task_runner(),
     58       mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
     59 
     60   return 0;
     61 }
     62 ```
     63 
     64 This process is now fully prepared to use Mojo IPC!
     65 
     66 Note that all existing process types in Chromium already perform this setup
     67 very early during startup.
     68 
     69 ## Connecting Two Processes
     70 
     71 Now suppose you're running a process which has initialized Mojo IPC, and you
     72 want to launch another process which you know will also initialize Mojo IPC.
     73 You want to be able to connect Mojo interfaces between these two processes.
     74 Rejoice, because this section was written just for you.
     75 
     76 NOTE: For legacy reasons, some API terminology may refer to concepts of "parent"
     77 and "child" as a relationship between processes being connected by Mojo. This
     78 relationship is today completely orthogonal to any notion of process hierarchy
     79 in the OS, and so use of these APIs is not constrained by an adherence to any
     80 such hierarchy.
     81 
     82 Mojo requires you to bring your own OS pipe to the party, and it will do the
     83 rest. It also provides a convenient mechanism for creating such pipes, known as
     84 a `PlatformChannelPair`.
     85 
     86 You provide one end of this pipe to the EDK in the local process via
     87 `PendingProcessConnection` - which can also be used to create cross-process
     88 message pipes (see the next section) - and you're responsible for getting the
     89 other end into the remote process.
     90 
     91 ```
     92 #include "base/process/process_handle.h"
     93 #include "base/threading/thread.h"
     94 #include "mojo/edk/embedder/embedder.h"
     95 #include "mojo/edk/embedder/pending_process_connection.h"
     96 #include "mojo/edk/embedder/platform_channel_pair.h"
     97 #include "mojo/edk/embedder/scoped_ipc_support.h"
     98 
     99 // You write this. It launches a new process, passing the pipe handle
    100 // encapsulated by |channel| by any means possible (e.g. on Windows or POSIX
    101 // you may inhert the file descriptor/HANDLE at launch and pass a commandline
    102 // argument to indicate its numeric value). Returns the handle of the new
    103 // process.
    104 base::ProcessHandle LaunchCoolChildProcess(
    105     mojo::edk::ScopedPlatformHandle channel);
    106 
    107 int main(int argc, char** argv) {
    108   mojo::edk::Init();
    109 
    110   base::Thread ipc_thread("ipc!");
    111   ipc_thread.StartWithOptions(
    112       base::Thread::Options(base::MessageLoop::TYPE_IO));
    113 
    114   mojo::edk::ScopedIPCSupport ipc_support(
    115       ipc_thread.task_runner(),
    116       mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
    117 
    118   // This is essentially always an OS pipe (domain socket pair, Windows named
    119   // pipe, etc.)
    120   mojo::edk::PlatformChannelPair channel;
    121 
    122   // This is a scoper which encapsulates the intent to connect to another
    123   // process. It exists because process connection is inherently asynchronous,
    124   // things may go wrong, and the lifetime of any associated resources is bound
    125   // by the lifetime of this object regardless of success or failure.
    126   mojo::edk::PendingProcessConnection child;
    127 
    128   base::ProcessHandle child_handle =
    129       LaunchCoolChildProcess(channel.PassClientHandle());
    130 
    131   // At this point it's safe for |child| to go out of scope and nothing will
    132   // break.
    133   child.Connect(child_handle, channel.PassServerHandle());
    134 
    135   return 0;
    136 }
    137 ```
    138 
    139 The launched process code uses `SetParentPipeHandle` to get connected, and might
    140 look something like:
    141 
    142 ```
    143 #include "base/threading/thread.h"
    144 #include "mojo/edk/embedder/embedder.h"
    145 #include "mojo/edk/embedder/scoped_ipc_support.h"
    146 
    147 // You write this. It acquires the ScopedPlatformHandle that was passed by
    148 // whomever launched this process (i.e. LaunchCoolChildProcess above).
    149 mojo::edk::ScopedPlatformHandle GetChannelHandle();
    150 
    151 int main(int argc, char** argv) {
    152   mojo::edk::Init();
    153 
    154   base::Thread ipc_thread("ipc!");
    155   ipc_thread.StartWithOptions(
    156       base::Thread::Options(base::MessageLoop::TYPE_IO));
    157 
    158   mojo::edk::ScopedIPCSupport ipc_support(
    159       ipc_thread.task_runner(),
    160       mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
    161 
    162   mojo::edk::SetParentPipeHandle(GetChannelHandle());
    163 
    164   return 0;
    165 }
    166 ```
    167 
    168 Now you have IPC initialized between two processes. For some practical examples
    169 of how this is done, you can dig into the various multiprocess tests in the
    170 `mojo_system_unittests` test suite.
    171 
    172 ## Bootstrapping Cross-Process Message Pipes
    173 
    174 Having internal Mojo IPC support initialized is pretty useless if you don't have
    175 any message pipes spanning the process boundary. Fortunately, this is made
    176 trivial by the EDK: `PendingProcessConnection` has a
    177 `CreateMessagePipe` method which synthesizes a new solitary message pipe
    178 endpoint for your immediate use, while also generating a magic token string that
    179 can be exchanged for the other end of the pipe via
    180 `mojo::edk::CreateChildMessagePipe`.
    181 
    182 The token exchange can be done by the same process (which is sometimes useful),
    183 or by the process that is eventually connected via `Connect()` on that
    184 `PendingProcessConnection`. This means that you can effectively pass message
    185 pipes on the commandline by passing a token string.
    186 
    187 We can modify our existing sample code as follows:
    188 
    189 ```
    190 #include "base/command_line.h"
    191 #include "base/process/process_handle.h"
    192 #include "base/threading/thread.h"
    193 #include "mojo/edk/embedder/embedder.h"
    194 #include "mojo/edk/embedder/pending_process_connection.h"
    195 #include "mojo/edk/embedder/platform_channel_pair.h"
    196 #include "mojo/edk/embedder/scoped_ipc_support.h"
    197 #include "mojo/public/cpp/system/message_pipe.h"
    198 #include "local/foo.mojom.h"  // You provide this
    199 
    200 base::ProcessHandle LaunchCoolChildProcess(
    201     const base::CommandLine& command_line,
    202     mojo::edk::ScopedPlatformHandle channel);
    203 
    204 int main(int argc, char** argv) {
    205   mojo::edk::Init();
    206 
    207   base::Thread ipc_thread("ipc!");
    208   ipc_thread.StartWithOptions(
    209       base::Thread::Options(base::MessageLoop::TYPE_IO));
    210 
    211   mojo::edk::ScopedIPCSupport ipc_support(
    212       ipc_thread.task_runner(),
    213       mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
    214 
    215   mojo::edk::PlatformChannelPair channel;
    216 
    217   mojo::edk::PendingProcessConnection child;
    218 
    219   base::CommandLine command_line;  // Assume this is appropriately initialized
    220 
    221   // Create a new message pipe with one end being retrievable in the new
    222   // process. Note that it doesn't matter whether we call CreateMessagePipe()
    223   // before or after Connect(), and we can create as many different pipes as
    224   // we like.
    225   std::string pipe_token;
    226   mojo::ScopedMessagePipeHandle my_pipe = child.CreateMessagePipe(&pipe_token);
    227   command_line.AppendSwitchASCII("primordial-pipe", pipe_token);
    228 
    229   base::ProcessHandle child_handle =
    230       LaunchCoolChildProcess(command_line, channel.PassClientHandle());
    231 
    232   child.Connect(child_handle, channel.PassServerHandle());
    233 
    234   // We can start using our end of the pipe immediately. Here we assume the
    235   // other end will eventually be bound to a local::mojom::Foo implementation,
    236   // so we can start making calls on that interface.
    237   //
    238   // Note that this could even be done before the child process is launched and
    239   // it would still work as expected.
    240   local::mojom::FooPtr foo;
    241   foo.Bind(local::mojom::FooPtrInfo(std::move(my_pipe), 0));
    242   foo->DoSomeStuff(42);
    243 
    244   return 0;
    245 }
    246 ```
    247 
    248 and for the launched process:
    249 
    250 
    251 ```
    252 #include "base/command_line.h"
    253 #include "base/run_loop/run_loop.h"
    254 #include "base/threading/thread.h"
    255 #include "mojo/edk/embedder/embedder.h"
    256 #include "mojo/edk/embedder/scoped_ipc_support.h"
    257 #include "mojo/public/cpp/bindings/binding.h"
    258 #include "mojo/public/cpp/system/message_pipe.h"
    259 #include "local/foo.mojom.h"  // You provide this
    260 
    261 mojo::edk::ScopedPlatformHandle GetChannelHandle();
    262 
    263 class FooImpl : local::mojom::Foo {
    264  public:
    265   explicit FooImpl(local::mojom::FooRequest request)
    266       : binding_(this, std::move(request)) {}
    267   ~FooImpl() override {}
    268 
    269   void DoSomeStuff(int32_t n) override {
    270     // ...
    271   }
    272 
    273  private:
    274   mojo::Binding<local::mojom::Foo> binding_;
    275 
    276   DISALLOW_COPY_AND_ASSIGN(FooImpl);
    277 };
    278 
    279 int main(int argc, char** argv) {
    280   base::CommandLine::Init(argc, argv);
    281 
    282   mojo::edk::Init();
    283 
    284   base::Thread ipc_thread("ipc!");
    285   ipc_thread.StartWithOptions(
    286       base::Thread::Options(base::MessageLoop::TYPE_IO));
    287 
    288   mojo::edk::ScopedIPCSupport ipc_support(
    289       ipc_thread.task_runner(),
    290       mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
    291 
    292   mojo::edk::SetParentPipeHandle(GetChannelHandle());
    293 
    294   mojo::ScopedMessagePipeHandle my_pipe = mojo::edk::CreateChildMessagePipe(
    295       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    296           "primordial-pipe"));
    297 
    298   local::mojom::FooRequest foo_request;
    299   foo_request.Bind(std::move(my_pipe));
    300   FooImpl impl(std::move(foo_request));
    301 
    302   // Run forever!
    303   base::RunLoop().Run();
    304 
    305   return 0;
    306 }
    307 ```
    308 
    309 Note that the above samples assume an interface definition in
    310 `//local/test.mojom` which would look something like:
    311 
    312 ```
    313 module local.mojom;
    314 
    315 interface Foo {
    316   DoSomeStuff(int32 n);
    317 };
    318 ```
    319 
    320 Once you've bootstrapped your process connection with a real mojom interface,
    321 you can avoid any further mucking around with EDK APIs or raw message pipe
    322 handles, as everything beyond this point - including the passing of other
    323 interface pipes - can be handled eloquently using public bindings APIs.
    324 
    325 See [additional Mojo documentation](
    326     https://www.chromium.org/developers/design-documents/mojo) for more
    327 information.
    328