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/system/channel.h" 12 #include "mojo/system/core.h" 13 #include "mojo/system/entrypoints.h" 14 #include "mojo/system/message_in_transit.h" 15 #include "mojo/system/message_pipe.h" 16 #include "mojo/system/message_pipe_dispatcher.h" 17 #include "mojo/system/platform_handle_dispatcher.h" 18 #include "mojo/system/raw_channel.h" 19 20 namespace mojo { 21 namespace embedder { 22 23 // This is defined here (instead of a header file), since it's opaque to the 24 // outside world. But we need to define it before our (internal-only) functions 25 // that use it. 26 struct ChannelInfo { 27 explicit ChannelInfo(scoped_refptr<system::Channel> channel) 28 : channel(channel) {} 29 ~ChannelInfo() {} 30 31 scoped_refptr<system::Channel> channel; 32 }; 33 34 namespace { 35 36 // Helper for |CreateChannelOnIOThread()|. (Note: May return null for some 37 // failures.) 38 scoped_refptr<system::Channel> MakeChannel( 39 ScopedPlatformHandle platform_handle, 40 scoped_refptr<system::MessagePipe> message_pipe) { 41 DCHECK(platform_handle.is_valid()); 42 43 // Create and initialize a |system::Channel|. 44 scoped_refptr<system::Channel> channel = new system::Channel(); 45 if (!channel->Init(system::RawChannel::Create(platform_handle.Pass()))) { 46 // This is very unusual (e.g., maybe |platform_handle| was invalid or we 47 // reached some system resource limit). 48 LOG(ERROR) << "Channel::Init() failed"; 49 // Return null, since |Shutdown()| shouldn't be called in this case. 50 return scoped_refptr<system::Channel>(); 51 } 52 // Once |Init()| has succeeded, we have to return |channel| (since 53 // |Shutdown()| will have to be called on it). 54 55 // Attach the message pipe endpoint. 56 system::MessageInTransit::EndpointId endpoint_id = 57 channel->AttachMessagePipeEndpoint(message_pipe, 1); 58 if (endpoint_id == system::MessageInTransit::kInvalidEndpointId) { 59 // This means that, e.g., the other endpoint of the message pipe was closed 60 // first. But it's not necessarily an error per se. 61 DVLOG(2) << "Channel::AttachMessagePipeEndpoint() failed"; 62 return channel; 63 } 64 CHECK_EQ(endpoint_id, system::Channel::kBootstrapEndpointId); 65 66 if (!channel->RunMessagePipeEndpoint(system::Channel::kBootstrapEndpointId, 67 system::Channel::kBootstrapEndpointId)) { 68 // Currently, there's no reason for this to fail. 69 NOTREACHED() << "Channel::RunMessagePipeEndpoint() failed"; 70 return channel; 71 } 72 73 return channel; 74 } 75 76 void CreateChannelOnIOThread( 77 ScopedPlatformHandle platform_handle, 78 scoped_refptr<system::MessagePipe> message_pipe, 79 DidCreateChannelCallback callback, 80 scoped_refptr<base::TaskRunner> callback_thread_task_runner) { 81 scoped_ptr<ChannelInfo> channel_info( 82 new ChannelInfo(MakeChannel(platform_handle.Pass(), message_pipe))); 83 84 // Hand the channel back to the embedder. 85 if (callback_thread_task_runner) { 86 callback_thread_task_runner->PostTask(FROM_HERE, 87 base::Bind(callback, 88 channel_info.release())); 89 } else { 90 callback.Run(channel_info.release()); 91 } 92 } 93 94 } // namespace 95 96 void Init() { 97 system::entrypoints::SetCore(new system::Core()); 98 } 99 100 ScopedMessagePipeHandle CreateChannel( 101 ScopedPlatformHandle platform_handle, 102 scoped_refptr<base::TaskRunner> io_thread_task_runner, 103 DidCreateChannelCallback callback, 104 scoped_refptr<base::TaskRunner> callback_thread_task_runner) { 105 DCHECK(platform_handle.is_valid()); 106 107 std::pair<scoped_refptr<system::MessagePipeDispatcher>, 108 scoped_refptr<system::MessagePipe> > remote_message_pipe = 109 system::MessagePipeDispatcher::CreateRemoteMessagePipe(); 110 111 system::Core* core = system::entrypoints::GetCore(); 112 DCHECK(core); 113 ScopedMessagePipeHandle rv( 114 MessagePipeHandle(core->AddDispatcher(remote_message_pipe.first))); 115 // TODO(vtl): Do we properly handle the failure case here? 116 if (rv.is_valid()) { 117 io_thread_task_runner->PostTask(FROM_HERE, 118 base::Bind(&CreateChannelOnIOThread, 119 base::Passed(&platform_handle), 120 remote_message_pipe.second, 121 callback, 122 callback_thread_task_runner)); 123 } 124 return rv.Pass(); 125 } 126 127 void DestroyChannelOnIOThread(ChannelInfo* channel_info) { 128 DCHECK(channel_info); 129 if (!channel_info->channel) { 130 // Presumably, |Init()| on the channel failed. 131 return; 132 } 133 134 channel_info->channel->Shutdown(); 135 delete channel_info; 136 } 137 138 MojoResult CreatePlatformHandleWrapper( 139 ScopedPlatformHandle platform_handle, 140 MojoHandle* platform_handle_wrapper_handle) { 141 DCHECK(platform_handle_wrapper_handle); 142 143 scoped_refptr<system::Dispatcher> dispatcher( 144 new system::PlatformHandleDispatcher(platform_handle.Pass())); 145 146 system::Core* core = system::entrypoints::GetCore(); 147 DCHECK(core); 148 MojoHandle h = core->AddDispatcher(dispatcher); 149 if (h == MOJO_HANDLE_INVALID) { 150 LOG(ERROR) << "Handle table full"; 151 dispatcher->Close(); 152 return MOJO_RESULT_RESOURCE_EXHAUSTED; 153 } 154 155 *platform_handle_wrapper_handle = h; 156 return MOJO_RESULT_OK; 157 } 158 159 MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle, 160 ScopedPlatformHandle* platform_handle) { 161 DCHECK(platform_handle); 162 163 system::Core* core = system::entrypoints::GetCore(); 164 DCHECK(core); 165 scoped_refptr<system::Dispatcher> dispatcher( 166 core->GetDispatcher(platform_handle_wrapper_handle)); 167 if (!dispatcher) 168 return MOJO_RESULT_INVALID_ARGUMENT; 169 170 if (dispatcher->GetType() != system::Dispatcher::kTypePlatformHandle) 171 return MOJO_RESULT_INVALID_ARGUMENT; 172 173 *platform_handle = static_cast<system::PlatformHandleDispatcher*>( 174 dispatcher.get())->PassPlatformHandle().Pass(); 175 return MOJO_RESULT_OK; 176 } 177 178 } // namespace embedder 179 } // namespace mojo 180