| OLD | NEW | 
|    1 // Copyright 2014 The Chromium Authors. All rights reserved. |    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 |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include "mojo/edk/embedder/embedder.h" |    5 #include "mojo/edk/embedder/embedder.h" | 
|    6  |    6  | 
|    7 #include "base/bind.h" |    7 #include "base/bind.h" | 
|    8 #include "base/location.h" |    8 #include "base/location.h" | 
|    9 #include "base/logging.h" |    9 #include "base/logging.h" | 
|   10 #include "base/memory/scoped_ptr.h" |   10 #include "base/memory/scoped_ptr.h" | 
|   11 #include "base/message_loop/message_loop_proxy.h" |   11 #include "base/message_loop/message_loop_proxy.h" | 
 |   12 #include "mojo/edk/embedder/embedder_internal.h" | 
|   12 #include "mojo/edk/embedder/platform_support.h" |   13 #include "mojo/edk/embedder/platform_support.h" | 
|   13 #include "mojo/edk/system/channel.h" |   14 #include "mojo/edk/system/channel.h" | 
|   14 #include "mojo/edk/system/channel_endpoint.h" |   15 #include "mojo/edk/system/channel_endpoint.h" | 
|   15 #include "mojo/edk/system/channel_info.h" |   16 #include "mojo/edk/system/channel_manager.h" | 
 |   17 #include "mojo/edk/system/configuration.h" | 
|   16 #include "mojo/edk/system/core.h" |   18 #include "mojo/edk/system/core.h" | 
|   17 #include "mojo/edk/system/entrypoints.h" |  | 
|   18 #include "mojo/edk/system/message_pipe_dispatcher.h" |   19 #include "mojo/edk/system/message_pipe_dispatcher.h" | 
|   19 #include "mojo/edk/system/platform_handle_dispatcher.h" |   20 #include "mojo/edk/system/platform_handle_dispatcher.h" | 
|   20 #include "mojo/edk/system/raw_channel.h" |   21 #include "mojo/edk/system/raw_channel.h" | 
|   21  |   22  | 
|   22 namespace mojo { |   23 namespace mojo { | 
|   23 namespace embedder { |   24 namespace embedder { | 
|   24  |   25  | 
|   25 namespace { |   26 namespace { | 
|   26  |   27  | 
|   27 // Helper for |CreateChannel...()|. (Note: May return null for some failures.) |   28 // Helper for |CreateChannel...()|. Returns 0 on failure. Called on the channel | 
|   28 scoped_refptr<system::Channel> MakeChannel( |   29 // creation thread. | 
|   29     system::Core* core, |   30 system::ChannelId MakeChannel( | 
|   30     ScopedPlatformHandle platform_handle, |   31     ScopedPlatformHandle platform_handle, | 
|   31     scoped_refptr<system::ChannelEndpoint> channel_endpoint) { |   32     scoped_refptr<system::ChannelEndpoint> channel_endpoint) { | 
|   32   DCHECK(platform_handle.is_valid()); |   33   DCHECK(platform_handle.is_valid()); | 
|   33  |   34  | 
|   34   // Create and initialize a |system::Channel|. |   35   // Create and initialize a |system::Channel|. | 
 |   36   DCHECK(internal::g_core); | 
|   35   scoped_refptr<system::Channel> channel = |   37   scoped_refptr<system::Channel> channel = | 
|   36       new system::Channel(core->platform_support()); |   38       new system::Channel(internal::g_core->platform_support()); | 
|   37   if (!channel->Init(system::RawChannel::Create(platform_handle.Pass()))) { |   39   if (!channel->Init(system::RawChannel::Create(platform_handle.Pass()))) { | 
|   38     // This is very unusual (e.g., maybe |platform_handle| was invalid or we |   40     // This is very unusual (e.g., maybe |platform_handle| was invalid or we | 
|   39     // reached some system resource limit). |   41     // reached some system resource limit). | 
|   40     LOG(ERROR) << "Channel::Init() failed"; |   42     LOG(ERROR) << "Channel::Init() failed"; | 
|   41     // Return null, since |Shutdown()| shouldn't be called in this case. |   43     // Return null, since |Shutdown()| shouldn't be called in this case. | 
|   42     return scoped_refptr<system::Channel>(); |   44     return 0; | 
|   43   } |   45   } | 
|   44   // Once |Init()| has succeeded, we have to return |channel| (since |  | 
|   45   // |Shutdown()| will have to be called on it). |  | 
|   46  |   46  | 
|   47   channel->AttachAndRunEndpoint(channel_endpoint, true); |   47   channel->AttachAndRunEndpoint(channel_endpoint, true); | 
|   48   return channel; |   48  | 
 |   49   DCHECK(internal::g_channel_manager); | 
 |   50   return internal::g_channel_manager->AddChannel( | 
 |   51       channel, base::MessageLoopProxy::current()); | 
|   49 } |   52 } | 
|   50  |   53  | 
 |   54 // Helper for |CreateChannel()|. Called on the channel creation thread. | 
|   51 void CreateChannelHelper( |   55 void CreateChannelHelper( | 
|   52     system::Core* core, |  | 
|   53     ScopedPlatformHandle platform_handle, |   56     ScopedPlatformHandle platform_handle, | 
|   54     scoped_ptr<ChannelInfo> channel_info, |   57     scoped_ptr<ChannelInfo> channel_info, | 
|   55     scoped_refptr<system::ChannelEndpoint> channel_endpoint, |   58     scoped_refptr<system::ChannelEndpoint> channel_endpoint, | 
|   56     DidCreateChannelCallback callback, |   59     DidCreateChannelCallback callback, | 
|   57     scoped_refptr<base::TaskRunner> callback_thread_task_runner) { |   60     scoped_refptr<base::TaskRunner> callback_thread_task_runner) { | 
|   58   channel_info->channel = |   61   channel_info->channel_id = | 
|   59       MakeChannel(core, platform_handle.Pass(), channel_endpoint); |   62       MakeChannel(platform_handle.Pass(), channel_endpoint); | 
|   60  |   63  | 
|   61   // Hand the channel back to the embedder. |   64   // Hand the channel back to the embedder. | 
|   62   if (callback_thread_task_runner.get()) { |   65   if (callback_thread_task_runner.get()) { | 
|   63     callback_thread_task_runner->PostTask( |   66     callback_thread_task_runner->PostTask( | 
|   64         FROM_HERE, base::Bind(callback, channel_info.release())); |   67         FROM_HERE, base::Bind(callback, channel_info.release())); | 
|   65   } else { |   68   } else { | 
|   66     callback.Run(channel_info.release()); |   69     callback.Run(channel_info.release()); | 
|   67   } |   70   } | 
|   68 } |   71 } | 
|   69  |   72  | 
|   70 }  // namespace |   73 }  // namespace | 
|   71  |   74  | 
 |   75 namespace internal { | 
 |   76  | 
 |   77 // Declared in embedder_internal.h. | 
 |   78 system::Core* g_core = nullptr; | 
 |   79 system::ChannelManager* g_channel_manager = nullptr; | 
 |   80  | 
 |   81 }  // namespace internal | 
 |   82  | 
|   72 void Init(scoped_ptr<PlatformSupport> platform_support) { |   83 void Init(scoped_ptr<PlatformSupport> platform_support) { | 
|   73   system::entrypoints::SetCore(new system::Core(platform_support.Pass())); |   84   DCHECK(!internal::g_core); | 
 |   85   internal::g_core = new system::Core(platform_support.Pass()); | 
 |   86   DCHECK(!internal::g_channel_manager); | 
 |   87   internal::g_channel_manager = new system::ChannelManager(); | 
 |   88 } | 
 |   89  | 
 |   90 Configuration* GetConfiguration() { | 
 |   91   return system::GetMutableConfiguration(); | 
|   74 } |   92 } | 
|   75  |   93  | 
|   76 // TODO(vtl): Write tests for this. |   94 // TODO(vtl): Write tests for this. | 
|   77 ScopedMessagePipeHandle CreateChannelOnIOThread( |   95 ScopedMessagePipeHandle CreateChannelOnIOThread( | 
|   78     ScopedPlatformHandle platform_handle, |   96     ScopedPlatformHandle platform_handle, | 
|   79     ChannelInfo** channel_info) { |   97     ChannelInfo** channel_info) { | 
|   80   DCHECK(platform_handle.is_valid()); |   98   DCHECK(platform_handle.is_valid()); | 
|   81   DCHECK(channel_info); |   99   DCHECK(channel_info); | 
|   82  |  100  | 
|   83   scoped_refptr<system::ChannelEndpoint> channel_endpoint; |  101   scoped_refptr<system::ChannelEndpoint> channel_endpoint; | 
|   84   scoped_refptr<system::MessagePipeDispatcher> dispatcher = |  102   scoped_refptr<system::MessagePipeDispatcher> dispatcher = | 
|   85       system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint); |  103       system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint); | 
|   86  |  104  | 
|   87   system::Core* core = system::entrypoints::GetCore(); |  105   DCHECK(internal::g_core); | 
|   88   DCHECK(core); |  | 
|   89   ScopedMessagePipeHandle rv( |  106   ScopedMessagePipeHandle rv( | 
|   90       MessagePipeHandle(core->AddDispatcher(dispatcher))); |  107       MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); | 
|   91  |  108  | 
|   92   *channel_info = new ChannelInfo( |  109   *channel_info = | 
|   93       MakeChannel(core, platform_handle.Pass(), channel_endpoint), |  110       new ChannelInfo(MakeChannel(platform_handle.Pass(), channel_endpoint)); | 
|   94       base::MessageLoopProxy::current()); |  | 
|   95  |  111  | 
|   96   return rv.Pass(); |  112   return rv.Pass(); | 
|   97 } |  113 } | 
|   98  |  114  | 
|   99 ScopedMessagePipeHandle CreateChannel( |  115 ScopedMessagePipeHandle CreateChannel( | 
|  100     ScopedPlatformHandle platform_handle, |  116     ScopedPlatformHandle platform_handle, | 
|  101     scoped_refptr<base::TaskRunner> io_thread_task_runner, |  117     scoped_refptr<base::TaskRunner> io_thread_task_runner, | 
|  102     DidCreateChannelCallback callback, |  118     DidCreateChannelCallback callback, | 
|  103     scoped_refptr<base::TaskRunner> callback_thread_task_runner) { |  119     scoped_refptr<base::TaskRunner> callback_thread_task_runner) { | 
|  104   DCHECK(platform_handle.is_valid()); |  120   DCHECK(platform_handle.is_valid()); | 
|  105   DCHECK(io_thread_task_runner.get()); |  121   DCHECK(io_thread_task_runner.get()); | 
|  106   DCHECK(!callback.is_null()); |  122   DCHECK(!callback.is_null()); | 
|  107  |  123  | 
|  108   scoped_refptr<system::ChannelEndpoint> channel_endpoint; |  124   scoped_refptr<system::ChannelEndpoint> channel_endpoint; | 
|  109   scoped_refptr<system::MessagePipeDispatcher> dispatcher = |  125   scoped_refptr<system::MessagePipeDispatcher> dispatcher = | 
|  110       system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint); |  126       system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint); | 
|  111  |  127  | 
|  112   system::Core* core = system::entrypoints::GetCore(); |  128   DCHECK(internal::g_core); | 
|  113   DCHECK(core); |  | 
|  114   ScopedMessagePipeHandle rv( |  129   ScopedMessagePipeHandle rv( | 
|  115       MessagePipeHandle(core->AddDispatcher(dispatcher))); |  130       MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); | 
|  116  |  131  | 
 |  132   // We'll have to set |channel_info->channel_id| on the I/O thread. | 
|  117   scoped_ptr<ChannelInfo> channel_info(new ChannelInfo()); |  133   scoped_ptr<ChannelInfo> channel_info(new ChannelInfo()); | 
|  118   // We'll have to set |channel_info->channel| on the I/O thread. |  | 
|  119   channel_info->channel_thread_task_runner = io_thread_task_runner; |  | 
|  120  |  134  | 
|  121   if (rv.is_valid()) { |  135   if (rv.is_valid()) { | 
|  122     io_thread_task_runner->PostTask(FROM_HERE, |  136     io_thread_task_runner->PostTask( | 
|  123                                     base::Bind(&CreateChannelHelper, |  137         FROM_HERE, | 
|  124                                                base::Unretained(core), |  138         base::Bind(&CreateChannelHelper, base::Passed(&platform_handle), | 
|  125                                                base::Passed(&platform_handle), |  139                    base::Passed(&channel_info), channel_endpoint, callback, | 
|  126                                                base::Passed(&channel_info), |  140                    callback_thread_task_runner)); | 
|  127                                                channel_endpoint, |  | 
|  128                                                callback, |  | 
|  129                                                callback_thread_task_runner)); |  | 
|  130   } else { |  141   } else { | 
|  131     (callback_thread_task_runner.get() ? callback_thread_task_runner |  142     (callback_thread_task_runner.get() ? callback_thread_task_runner | 
|  132                                        : io_thread_task_runner) |  143                                        : io_thread_task_runner) | 
|  133         ->PostTask(FROM_HERE, base::Bind(callback, channel_info.release())); |  144         ->PostTask(FROM_HERE, base::Bind(callback, channel_info.release())); | 
|  134   } |  145   } | 
|  135  |  146  | 
|  136   return rv.Pass(); |  147   return rv.Pass(); | 
|  137 } |  148 } | 
|  138  |  149  | 
|  139 void DestroyChannelOnIOThread(ChannelInfo* channel_info) { |  | 
|  140   DCHECK(channel_info); |  | 
|  141   if (!channel_info->channel.get()) { |  | 
|  142     // Presumably, |Init()| on the channel failed. |  | 
|  143     return; |  | 
|  144   } |  | 
|  145  |  | 
|  146   channel_info->channel->Shutdown(); |  | 
|  147   delete channel_info; |  | 
|  148 } |  | 
|  149  |  | 
|  150 // TODO(vtl): Write tests for this. |  150 // TODO(vtl): Write tests for this. | 
|  151 void DestroyChannel(ChannelInfo* channel_info) { |  151 void DestroyChannel(ChannelInfo* channel_info) { | 
|  152   DCHECK(channel_info); |  152   DCHECK(channel_info); | 
|  153   DCHECK(channel_info->channel_thread_task_runner.get()); |  153   if (!channel_info->channel_id) { | 
|  154  |  | 
|  155   if (!channel_info->channel.get()) { |  | 
|  156     // Presumably, |Init()| on the channel failed. |  154     // Presumably, |Init()| on the channel failed. | 
|  157     return; |  155     return; | 
|  158   } |  156   } | 
|  159  |  157  | 
|  160   channel_info->channel->WillShutdownSoon(); |  158   DCHECK(internal::g_channel_manager); | 
|  161   channel_info->channel_thread_task_runner->PostTask( |  159   // This will destroy the channel synchronously if called from the channel | 
|  162       FROM_HERE, base::Bind(&DestroyChannelOnIOThread, channel_info)); |  160   // thread. | 
 |  161   internal::g_channel_manager->ShutdownChannel(channel_info->channel_id); | 
 |  162   delete channel_info; | 
|  163 } |  163 } | 
|  164  |  164  | 
|  165 void WillDestroyChannelSoon(ChannelInfo* channel_info) { |  165 void WillDestroyChannelSoon(ChannelInfo* channel_info) { | 
|  166   DCHECK(channel_info); |  166   DCHECK(channel_info); | 
|  167   channel_info->channel->WillShutdownSoon(); |  167   DCHECK(internal::g_channel_manager); | 
 |  168   internal::g_channel_manager->WillShutdownChannel(channel_info->channel_id); | 
|  168 } |  169 } | 
|  169  |  170  | 
|  170 MojoResult CreatePlatformHandleWrapper( |  171 MojoResult CreatePlatformHandleWrapper( | 
|  171     ScopedPlatformHandle platform_handle, |  172     ScopedPlatformHandle platform_handle, | 
|  172     MojoHandle* platform_handle_wrapper_handle) { |  173     MojoHandle* platform_handle_wrapper_handle) { | 
|  173   DCHECK(platform_handle_wrapper_handle); |  174   DCHECK(platform_handle_wrapper_handle); | 
|  174  |  175  | 
|  175   scoped_refptr<system::Dispatcher> dispatcher( |  176   scoped_refptr<system::Dispatcher> dispatcher( | 
|  176       new system::PlatformHandleDispatcher(platform_handle.Pass())); |  177       new system::PlatformHandleDispatcher(platform_handle.Pass())); | 
|  177  |  178  | 
|  178   system::Core* core = system::entrypoints::GetCore(); |  179   DCHECK(internal::g_core); | 
|  179   DCHECK(core); |  180   MojoHandle h = internal::g_core->AddDispatcher(dispatcher); | 
|  180   MojoHandle h = core->AddDispatcher(dispatcher); |  | 
|  181   if (h == MOJO_HANDLE_INVALID) { |  181   if (h == MOJO_HANDLE_INVALID) { | 
|  182     LOG(ERROR) << "Handle table full"; |  182     LOG(ERROR) << "Handle table full"; | 
|  183     dispatcher->Close(); |  183     dispatcher->Close(); | 
|  184     return MOJO_RESULT_RESOURCE_EXHAUSTED; |  184     return MOJO_RESULT_RESOURCE_EXHAUSTED; | 
|  185   } |  185   } | 
|  186  |  186  | 
|  187   *platform_handle_wrapper_handle = h; |  187   *platform_handle_wrapper_handle = h; | 
|  188   return MOJO_RESULT_OK; |  188   return MOJO_RESULT_OK; | 
|  189 } |  189 } | 
|  190  |  190  | 
|  191 MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle, |  191 MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle, | 
|  192                                      ScopedPlatformHandle* platform_handle) { |  192                                      ScopedPlatformHandle* platform_handle) { | 
|  193   DCHECK(platform_handle); |  193   DCHECK(platform_handle); | 
|  194  |  194  | 
|  195   system::Core* core = system::entrypoints::GetCore(); |  195   DCHECK(internal::g_core); | 
|  196   DCHECK(core); |  | 
|  197   scoped_refptr<system::Dispatcher> dispatcher( |  196   scoped_refptr<system::Dispatcher> dispatcher( | 
|  198       core->GetDispatcher(platform_handle_wrapper_handle)); |  197       internal::g_core->GetDispatcher(platform_handle_wrapper_handle)); | 
|  199   if (!dispatcher.get()) |  198   if (!dispatcher.get()) | 
|  200     return MOJO_RESULT_INVALID_ARGUMENT; |  199     return MOJO_RESULT_INVALID_ARGUMENT; | 
|  201  |  200  | 
|  202   if (dispatcher->GetType() != system::Dispatcher::kTypePlatformHandle) |  201   if (dispatcher->GetType() != system::Dispatcher::kTypePlatformHandle) | 
|  203     return MOJO_RESULT_INVALID_ARGUMENT; |  202     return MOJO_RESULT_INVALID_ARGUMENT; | 
|  204  |  203  | 
|  205   *platform_handle = |  204   *platform_handle = | 
|  206       static_cast<system::PlatformHandleDispatcher*>(dispatcher.get()) |  205       static_cast<system::PlatformHandleDispatcher*>(dispatcher.get()) | 
|  207           ->PassPlatformHandle() |  206           ->PassPlatformHandle() | 
|  208           .Pass(); |  207           .Pass(); | 
|  209   return MOJO_RESULT_OK; |  208   return MOJO_RESULT_OK; | 
|  210 } |  209 } | 
|  211  |  210  | 
|  212 }  // namespace embedder |  211 }  // namespace embedder | 
|  213 }  // namespace mojo |  212 }  // namespace mojo | 
| OLD | NEW |