diff options
Diffstat (limited to 'chromium/mojo/embedder/embedder.cc')
-rw-r--r-- | chromium/mojo/embedder/embedder.cc | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/chromium/mojo/embedder/embedder.cc b/chromium/mojo/embedder/embedder.cc new file mode 100644 index 00000000000..d4fd3814392 --- /dev/null +++ b/chromium/mojo/embedder/embedder.cc @@ -0,0 +1,179 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/embedder/embedder.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/system/channel.h" +#include "mojo/system/core.h" +#include "mojo/system/entrypoints.h" +#include "mojo/system/message_in_transit.h" +#include "mojo/system/message_pipe.h" +#include "mojo/system/message_pipe_dispatcher.h" +#include "mojo/system/platform_handle_dispatcher.h" +#include "mojo/system/raw_channel.h" + +namespace mojo { +namespace embedder { + +// This is defined here (instead of a header file), since it's opaque to the +// outside world. But we need to define it before our (internal-only) functions +// that use it. +struct ChannelInfo { + explicit ChannelInfo(scoped_refptr<system::Channel> channel) + : channel(channel) {} + ~ChannelInfo() {} + + scoped_refptr<system::Channel> channel; +}; + +namespace { + +// Helper for |CreateChannelOnIOThread()|. (Note: May return null for some +// failures.) +scoped_refptr<system::Channel> MakeChannel( + ScopedPlatformHandle platform_handle, + scoped_refptr<system::MessagePipe> message_pipe) { + DCHECK(platform_handle.is_valid()); + + // Create and initialize a |system::Channel|. + scoped_refptr<system::Channel> channel = new system::Channel(); + if (!channel->Init(system::RawChannel::Create(platform_handle.Pass()))) { + // This is very unusual (e.g., maybe |platform_handle| was invalid or we + // reached some system resource limit). + LOG(ERROR) << "Channel::Init() failed"; + // Return null, since |Shutdown()| shouldn't be called in this case. + return scoped_refptr<system::Channel>(); + } + // Once |Init()| has succeeded, we have to return |channel| (since + // |Shutdown()| will have to be called on it). + + // Attach the message pipe endpoint. + system::MessageInTransit::EndpointId endpoint_id = + channel->AttachMessagePipeEndpoint(message_pipe, 1); + if (endpoint_id == system::MessageInTransit::kInvalidEndpointId) { + // This means that, e.g., the other endpoint of the message pipe was closed + // first. But it's not necessarily an error per se. + DVLOG(2) << "Channel::AttachMessagePipeEndpoint() failed"; + return channel; + } + CHECK_EQ(endpoint_id, system::Channel::kBootstrapEndpointId); + + if (!channel->RunMessagePipeEndpoint(system::Channel::kBootstrapEndpointId, + system::Channel::kBootstrapEndpointId)) { + // Currently, there's no reason for this to fail. + NOTREACHED() << "Channel::RunMessagePipeEndpoint() failed"; + return channel; + } + + return channel; +} + +void CreateChannelOnIOThread( + ScopedPlatformHandle platform_handle, + scoped_refptr<system::MessagePipe> message_pipe, + DidCreateChannelCallback callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + scoped_ptr<ChannelInfo> channel_info( + new ChannelInfo(MakeChannel(platform_handle.Pass(), message_pipe))); + + // Hand the channel back to the embedder. + if (callback_thread_task_runner) { + callback_thread_task_runner->PostTask(FROM_HERE, + base::Bind(callback, + channel_info.release())); + } else { + callback.Run(channel_info.release()); + } +} + +} // namespace + +void Init() { + system::entrypoints::SetCore(new system::Core()); +} + +ScopedMessagePipeHandle CreateChannel( + ScopedPlatformHandle platform_handle, + scoped_refptr<base::TaskRunner> io_thread_task_runner, + DidCreateChannelCallback callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + DCHECK(platform_handle.is_valid()); + + std::pair<scoped_refptr<system::MessagePipeDispatcher>, + scoped_refptr<system::MessagePipe> > remote_message_pipe = + system::MessagePipeDispatcher::CreateRemoteMessagePipe(); + + system::Core* core = system::entrypoints::GetCore(); + DCHECK(core); + ScopedMessagePipeHandle rv( + MessagePipeHandle(core->AddDispatcher(remote_message_pipe.first))); + // TODO(vtl): Do we properly handle the failure case here? + if (rv.is_valid()) { + io_thread_task_runner->PostTask(FROM_HERE, + base::Bind(&CreateChannelOnIOThread, + base::Passed(&platform_handle), + remote_message_pipe.second, + callback, + callback_thread_task_runner)); + } + return rv.Pass(); +} + +void DestroyChannelOnIOThread(ChannelInfo* channel_info) { + DCHECK(channel_info); + if (!channel_info->channel) { + // Presumably, |Init()| on the channel failed. + return; + } + + channel_info->channel->Shutdown(); + delete channel_info; +} + +MojoResult CreatePlatformHandleWrapper( + ScopedPlatformHandle platform_handle, + MojoHandle* platform_handle_wrapper_handle) { + DCHECK(platform_handle_wrapper_handle); + + scoped_refptr<system::Dispatcher> dispatcher( + new system::PlatformHandleDispatcher(platform_handle.Pass())); + + system::Core* core = system::entrypoints::GetCore(); + DCHECK(core); + MojoHandle h = core->AddDispatcher(dispatcher); + if (h == MOJO_HANDLE_INVALID) { + LOG(ERROR) << "Handle table full"; + dispatcher->Close(); + return MOJO_RESULT_RESOURCE_EXHAUSTED; + } + + *platform_handle_wrapper_handle = h; + return MOJO_RESULT_OK; +} + +MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle, + ScopedPlatformHandle* platform_handle) { + DCHECK(platform_handle); + + system::Core* core = system::entrypoints::GetCore(); + DCHECK(core); + scoped_refptr<system::Dispatcher> dispatcher( + core->GetDispatcher(platform_handle_wrapper_handle)); + if (!dispatcher) + return MOJO_RESULT_INVALID_ARGUMENT; + + if (dispatcher->GetType() != system::Dispatcher::kTypePlatformHandle) + return MOJO_RESULT_INVALID_ARGUMENT; + + *platform_handle = static_cast<system::PlatformHandleDispatcher*>( + dispatcher.get())->PassPlatformHandle().Pass(); + return MOJO_RESULT_OK; +} + +} // namespace embedder +} // namespace mojo |