Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / mojo / edk / embedder / embedder.cc
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/edk/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 "base/message_loop/message_loop_proxy.h"
12 #include "mojo/edk/embedder/platform_support.h"
13 #include "mojo/edk/system/channel.h"
14 #include "mojo/edk/system/channel_endpoint.h"
15 #include "mojo/edk/system/channel_info.h"
16 #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/platform_handle_dispatcher.h"
20 #include "mojo/edk/system/raw_channel.h"
21
22 namespace mojo {
23 namespace embedder {
24
25 namespace {
26
27 // Helper for |CreateChannel...()|. (Note: May return null for some failures.)
28 scoped_refptr<system::Channel> MakeChannel(
29     system::Core* core,
30     ScopedPlatformHandle platform_handle,
31     scoped_refptr<system::ChannelEndpoint> channel_endpoint) {
32   DCHECK(platform_handle.is_valid());
33
34   // Create and initialize a |system::Channel|.
35   scoped_refptr<system::Channel> channel =
36       new system::Channel(core->platform_support());
37   if (!channel->Init(system::RawChannel::Create(platform_handle.Pass()))) {
38     // This is very unusual (e.g., maybe |platform_handle| was invalid or we
39     // reached some system resource limit).
40     LOG(ERROR) << "Channel::Init() failed";
41     // Return null, since |Shutdown()| shouldn't be called in this case.
42     return scoped_refptr<system::Channel>();
43   }
44   // Once |Init()| has succeeded, we have to return |channel| (since
45   // |Shutdown()| will have to be called on it).
46
47   channel->AttachAndRunEndpoint(channel_endpoint, true);
48   return channel;
49 }
50
51 void CreateChannelHelper(
52     system::Core* core,
53     ScopedPlatformHandle platform_handle,
54     scoped_ptr<ChannelInfo> channel_info,
55     scoped_refptr<system::ChannelEndpoint> channel_endpoint,
56     DidCreateChannelCallback callback,
57     scoped_refptr<base::TaskRunner> callback_thread_task_runner) {
58   channel_info->channel =
59       MakeChannel(core, platform_handle.Pass(), channel_endpoint);
60
61   // Hand the channel back to the embedder.
62   if (callback_thread_task_runner.get()) {
63     callback_thread_task_runner->PostTask(
64         FROM_HERE, base::Bind(callback, channel_info.release()));
65   } else {
66     callback.Run(channel_info.release());
67   }
68 }
69
70 }  // namespace
71
72 void Init(scoped_ptr<PlatformSupport> platform_support) {
73   system::entrypoints::SetCore(new system::Core(platform_support.Pass()));
74 }
75
76 // TODO(vtl): Write tests for this.
77 ScopedMessagePipeHandle CreateChannelOnIOThread(
78     ScopedPlatformHandle platform_handle,
79     ChannelInfo** channel_info) {
80   DCHECK(platform_handle.is_valid());
81   DCHECK(channel_info);
82
83   scoped_refptr<system::ChannelEndpoint> channel_endpoint;
84   scoped_refptr<system::MessagePipeDispatcher> dispatcher =
85       system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint);
86
87   system::Core* core = system::entrypoints::GetCore();
88   DCHECK(core);
89   ScopedMessagePipeHandle rv(
90       MessagePipeHandle(core->AddDispatcher(dispatcher)));
91
92   *channel_info = new ChannelInfo(
93       MakeChannel(core, platform_handle.Pass(), channel_endpoint),
94       base::MessageLoopProxy::current());
95
96   return rv.Pass();
97 }
98
99 ScopedMessagePipeHandle CreateChannel(
100     ScopedPlatformHandle platform_handle,
101     scoped_refptr<base::TaskRunner> io_thread_task_runner,
102     DidCreateChannelCallback callback,
103     scoped_refptr<base::TaskRunner> callback_thread_task_runner) {
104   DCHECK(platform_handle.is_valid());
105   DCHECK(io_thread_task_runner.get());
106   DCHECK(!callback.is_null());
107
108   scoped_refptr<system::ChannelEndpoint> channel_endpoint;
109   scoped_refptr<system::MessagePipeDispatcher> dispatcher =
110       system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint);
111
112   system::Core* core = system::entrypoints::GetCore();
113   DCHECK(core);
114   ScopedMessagePipeHandle rv(
115       MessagePipeHandle(core->AddDispatcher(dispatcher)));
116
117   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
121   if (rv.is_valid()) {
122     io_thread_task_runner->PostTask(FROM_HERE,
123                                     base::Bind(&CreateChannelHelper,
124                                                base::Unretained(core),
125                                                base::Passed(&platform_handle),
126                                                base::Passed(&channel_info),
127                                                channel_endpoint,
128                                                callback,
129                                                callback_thread_task_runner));
130   } else {
131     (callback_thread_task_runner.get() ? callback_thread_task_runner
132                                        : io_thread_task_runner)
133         ->PostTask(FROM_HERE, base::Bind(callback, channel_info.release()));
134   }
135
136   return rv.Pass();
137 }
138
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.
151 void DestroyChannel(ChannelInfo* channel_info) {
152   DCHECK(channel_info);
153   DCHECK(channel_info->channel_thread_task_runner.get());
154
155   if (!channel_info->channel.get()) {
156     // Presumably, |Init()| on the channel failed.
157     return;
158   }
159
160   channel_info->channel->WillShutdownSoon();
161   channel_info->channel_thread_task_runner->PostTask(
162       FROM_HERE, base::Bind(&DestroyChannelOnIOThread, channel_info));
163 }
164
165 void WillDestroyChannelSoon(ChannelInfo* channel_info) {
166   DCHECK(channel_info);
167   channel_info->channel->WillShutdownSoon();
168 }
169
170 MojoResult CreatePlatformHandleWrapper(
171     ScopedPlatformHandle platform_handle,
172     MojoHandle* platform_handle_wrapper_handle) {
173   DCHECK(platform_handle_wrapper_handle);
174
175   scoped_refptr<system::Dispatcher> dispatcher(
176       new system::PlatformHandleDispatcher(platform_handle.Pass()));
177
178   system::Core* core = system::entrypoints::GetCore();
179   DCHECK(core);
180   MojoHandle h = core->AddDispatcher(dispatcher);
181   if (h == MOJO_HANDLE_INVALID) {
182     LOG(ERROR) << "Handle table full";
183     dispatcher->Close();
184     return MOJO_RESULT_RESOURCE_EXHAUSTED;
185   }
186
187   *platform_handle_wrapper_handle = h;
188   return MOJO_RESULT_OK;
189 }
190
191 MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle,
192                                      ScopedPlatformHandle* platform_handle) {
193   DCHECK(platform_handle);
194
195   system::Core* core = system::entrypoints::GetCore();
196   DCHECK(core);
197   scoped_refptr<system::Dispatcher> dispatcher(
198       core->GetDispatcher(platform_handle_wrapper_handle));
199   if (!dispatcher.get())
200     return MOJO_RESULT_INVALID_ARGUMENT;
201
202   if (dispatcher->GetType() != system::Dispatcher::kTypePlatformHandle)
203     return MOJO_RESULT_INVALID_ARGUMENT;
204
205   *platform_handle =
206       static_cast<system::PlatformHandleDispatcher*>(dispatcher.get())
207           ->PassPlatformHandle()
208           .Pass();
209   return MOJO_RESULT_OK;
210 }
211
212 }  // namespace embedder
213 }  // namespace mojo