Home | History | Annotate | Download | only in embedder
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/embedder/embedder.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/location.h"
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "mojo/embedder/platform_support.h"
     12 #include "mojo/system/channel.h"
     13 #include "mojo/system/channel_endpoint.h"
     14 #include "mojo/system/core.h"
     15 #include "mojo/system/entrypoints.h"
     16 #include "mojo/system/message_in_transit.h"
     17 #include "mojo/system/message_pipe_dispatcher.h"
     18 #include "mojo/system/platform_handle_dispatcher.h"
     19 #include "mojo/system/raw_channel.h"
     20 
     21 namespace mojo {
     22 namespace embedder {
     23 
     24 // This is defined here (instead of a header file), since it's opaque to the
     25 // outside world. But we need to define it before our (internal-only) functions
     26 // that use it.
     27 struct ChannelInfo {
     28   ChannelInfo() {}
     29   ~ChannelInfo() {}
     30 
     31   scoped_refptr<system::Channel> channel;
     32 
     33   // May be null, in which case |DestroyChannelOnIOThread()| must be used (from
     34   // the IO thread), instead of |DestroyChannel()|.
     35   scoped_refptr<base::TaskRunner> io_thread_task_runner;
     36 };
     37 
     38 namespace {
     39 
     40 // Helper for |CreateChannel...()|. (Note: May return null for some failures.)
     41 scoped_refptr<system::Channel> MakeChannel(
     42     system::Core* core,
     43     ScopedPlatformHandle platform_handle,
     44     scoped_refptr<system::ChannelEndpoint> channel_endpoint) {
     45   DCHECK(platform_handle.is_valid());
     46 
     47   // Create and initialize a |system::Channel|.
     48   scoped_refptr<system::Channel> channel =
     49       new system::Channel(core->platform_support());
     50   if (!channel->Init(system::RawChannel::Create(platform_handle.Pass()))) {
     51     // This is very unusual (e.g., maybe |platform_handle| was invalid or we
     52     // reached some system resource limit).
     53     LOG(ERROR) << "Channel::Init() failed";
     54     // Return null, since |Shutdown()| shouldn't be called in this case.
     55     return scoped_refptr<system::Channel>();
     56   }
     57   // Once |Init()| has succeeded, we have to return |channel| (since
     58   // |Shutdown()| will have to be called on it).
     59 
     60   // Attach the endpoint.
     61   system::MessageInTransit::EndpointId endpoint_id =
     62       channel->AttachEndpoint(channel_endpoint);
     63   if (endpoint_id == system::MessageInTransit::kInvalidEndpointId) {
     64     // This means that, e.g., the other endpoint of the message pipe was closed
     65     // first. But it's not necessarily an error per se.
     66     DVLOG(2) << "Channel::AttachEndpoint() failed";
     67     return channel;
     68   }
     69   CHECK_EQ(endpoint_id, system::Channel::kBootstrapEndpointId);
     70 
     71   if (!channel->RunMessagePipeEndpoint(system::Channel::kBootstrapEndpointId,
     72                                        system::Channel::kBootstrapEndpointId)) {
     73     // Currently, there's no reason for this to fail.
     74     NOTREACHED() << "Channel::RunMessagePipeEndpoint() failed";
     75     return channel;
     76   }
     77 
     78   return channel;
     79 }
     80 
     81 void CreateChannelHelper(
     82     system::Core* core,
     83     ScopedPlatformHandle platform_handle,
     84     scoped_ptr<ChannelInfo> channel_info,
     85     scoped_refptr<system::ChannelEndpoint> channel_endpoint,
     86     DidCreateChannelCallback callback,
     87     scoped_refptr<base::TaskRunner> callback_thread_task_runner) {
     88   channel_info->channel =
     89       MakeChannel(core, platform_handle.Pass(), channel_endpoint);
     90 
     91   // Hand the channel back to the embedder.
     92   if (callback_thread_task_runner.get()) {
     93     callback_thread_task_runner->PostTask(
     94         FROM_HERE, base::Bind(callback, channel_info.release()));
     95   } else {
     96     callback.Run(channel_info.release());
     97   }
     98 }
     99 
    100 }  // namespace
    101 
    102 void Init(scoped_ptr<PlatformSupport> platform_support) {
    103   system::entrypoints::SetCore(new system::Core(platform_support.Pass()));
    104 }
    105 
    106 // TODO(vtl): Write tests for this.
    107 ScopedMessagePipeHandle CreateChannelOnIOThread(
    108     ScopedPlatformHandle platform_handle,
    109     ChannelInfo** channel_info) {
    110   DCHECK(platform_handle.is_valid());
    111   DCHECK(channel_info);
    112 
    113   scoped_refptr<system::ChannelEndpoint> channel_endpoint;
    114   scoped_refptr<system::MessagePipeDispatcher> dispatcher =
    115       system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint);
    116 
    117   system::Core* core = system::entrypoints::GetCore();
    118   DCHECK(core);
    119   ScopedMessagePipeHandle rv(
    120       MessagePipeHandle(core->AddDispatcher(dispatcher)));
    121 
    122   *channel_info = new ChannelInfo();
    123   (*channel_info)->channel =
    124       MakeChannel(core, platform_handle.Pass(), channel_endpoint);
    125 
    126   return rv.Pass();
    127 }
    128 
    129 ScopedMessagePipeHandle CreateChannel(
    130     ScopedPlatformHandle platform_handle,
    131     scoped_refptr<base::TaskRunner> io_thread_task_runner,
    132     DidCreateChannelCallback callback,
    133     scoped_refptr<base::TaskRunner> callback_thread_task_runner) {
    134   DCHECK(platform_handle.is_valid());
    135 
    136   scoped_refptr<system::ChannelEndpoint> channel_endpoint;
    137   scoped_refptr<system::MessagePipeDispatcher> dispatcher =
    138       system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint);
    139 
    140   system::Core* core = system::entrypoints::GetCore();
    141   DCHECK(core);
    142   ScopedMessagePipeHandle rv(
    143       MessagePipeHandle(core->AddDispatcher(dispatcher)));
    144 
    145   scoped_ptr<ChannelInfo> channel_info(new ChannelInfo());
    146   channel_info->io_thread_task_runner = io_thread_task_runner;
    147 
    148   if (rv.is_valid()) {
    149     io_thread_task_runner->PostTask(FROM_HERE,
    150                                     base::Bind(&CreateChannelHelper,
    151                                                base::Unretained(core),
    152                                                base::Passed(&platform_handle),
    153                                                base::Passed(&channel_info),
    154                                                channel_endpoint,
    155                                                callback,
    156                                                callback_thread_task_runner));
    157   } else {
    158     (callback_thread_task_runner.get() ? callback_thread_task_runner
    159                                        : io_thread_task_runner)
    160         ->PostTask(FROM_HERE, base::Bind(callback, channel_info.release()));
    161   }
    162 
    163   return rv.Pass();
    164 }
    165 
    166 void DestroyChannelOnIOThread(ChannelInfo* channel_info) {
    167   DCHECK(channel_info);
    168   if (!channel_info->channel.get()) {
    169     // Presumably, |Init()| on the channel failed.
    170     return;
    171   }
    172 
    173   channel_info->channel->Shutdown();
    174   delete channel_info;
    175 }
    176 
    177 // TODO(vtl): Write tests for this.
    178 void DestroyChannel(ChannelInfo* channel_info) {
    179   DCHECK(channel_info);
    180   DCHECK(channel_info->io_thread_task_runner.get());
    181 
    182   if (!channel_info->channel.get()) {
    183     // Presumably, |Init()| on the channel failed.
    184     return;
    185   }
    186 
    187   channel_info->channel->WillShutdownSoon();
    188   channel_info->io_thread_task_runner->PostTask(
    189       FROM_HERE, base::Bind(&DestroyChannelOnIOThread, channel_info));
    190 }
    191 
    192 void WillDestroyChannelSoon(ChannelInfo* channel_info) {
    193   DCHECK(channel_info);
    194   channel_info->channel->WillShutdownSoon();
    195 }
    196 
    197 MojoResult CreatePlatformHandleWrapper(
    198     ScopedPlatformHandle platform_handle,
    199     MojoHandle* platform_handle_wrapper_handle) {
    200   DCHECK(platform_handle_wrapper_handle);
    201 
    202   scoped_refptr<system::Dispatcher> dispatcher(
    203       new system::PlatformHandleDispatcher(platform_handle.Pass()));
    204 
    205   system::Core* core = system::entrypoints::GetCore();
    206   DCHECK(core);
    207   MojoHandle h = core->AddDispatcher(dispatcher);
    208   if (h == MOJO_HANDLE_INVALID) {
    209     LOG(ERROR) << "Handle table full";
    210     dispatcher->Close();
    211     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    212   }
    213 
    214   *platform_handle_wrapper_handle = h;
    215   return MOJO_RESULT_OK;
    216 }
    217 
    218 MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle,
    219                                      ScopedPlatformHandle* platform_handle) {
    220   DCHECK(platform_handle);
    221 
    222   system::Core* core = system::entrypoints::GetCore();
    223   DCHECK(core);
    224   scoped_refptr<system::Dispatcher> dispatcher(
    225       core->GetDispatcher(platform_handle_wrapper_handle));
    226   if (!dispatcher.get())
    227     return MOJO_RESULT_INVALID_ARGUMENT;
    228 
    229   if (dispatcher->GetType() != system::Dispatcher::kTypePlatformHandle)
    230     return MOJO_RESULT_INVALID_ARGUMENT;
    231 
    232   *platform_handle =
    233       static_cast<system::PlatformHandleDispatcher*>(dispatcher.get())
    234           ->PassPlatformHandle()
    235           .Pass();
    236   return MOJO_RESULT_OK;
    237 }
    238 
    239 }  // namespace embedder
    240 }  // namespace mojo
    241