- add third_party src.
[platform/framework/web/crosswalk.git] / src / xwalk / extensions / browser / xwalk_extension_service.cc
1 // Copyright (c) 2013 Intel Corporation. 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 "xwalk/extensions/browser/xwalk_extension_service.h"
6
7 #include <set>
8 #include <vector>
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/pickle.h"
12 #include "base/scoped_native_library.h"
13 #include "base/synchronization/lock.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/notification_types.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "ipc/ipc_message_macros.h"
19 #include "xwalk/extensions/browser/xwalk_extension_data.h"
20 #include "xwalk/extensions/browser/xwalk_extension_process_host.h"
21 #include "xwalk/extensions/common/xwalk_extension.h"
22 #include "xwalk/extensions/common/xwalk_extension_messages.h"
23 #include "xwalk/extensions/common/xwalk_extension_server.h"
24 #include "xwalk/extensions/common/xwalk_extension_switches.h"
25
26 using content::BrowserThread;
27
28 namespace xwalk {
29 namespace extensions {
30
31 namespace {
32
33 XWalkExtensionService::CreateExtensionsCallback
34     g_create_extension_thread_extensions_callback;
35
36 XWalkExtensionService::CreateExtensionsCallback
37     g_create_ui_thread_extensions_callback;
38
39 base::FilePath g_external_extensions_path_for_testing_;
40
41 }  // namespace
42
43 // This object intercepts messages destined to a XWalkExtensionServer and
44 // dispatch them to its task runner. A message loop proxy of a thread is a
45 // task runner. Like other filters, this filter will run in the IO-thread.
46 //
47 // In the case of in process extensions, we will pass the task runner of the
48 // extension thread.
49 class ExtensionServerMessageFilter : public IPC::ChannelProxy::MessageFilter,
50                                      public IPC::Sender {
51  public:
52   ExtensionServerMessageFilter(
53       scoped_refptr<base::SequencedTaskRunner> task_runner,
54       XWalkExtensionServer* extension_thread_server,
55       XWalkExtensionServer* ui_thread_server)
56       : sender_(NULL),
57         task_runner_(task_runner),
58         extension_thread_server_(extension_thread_server),
59         ui_thread_server_(ui_thread_server) {}
60
61   // Tells the filter to stop dispatching messages to the server.
62   void Invalidate() {
63     base::AutoLock l(lock_);
64     sender_ = NULL;
65     task_runner_ = NULL;
66     extension_thread_server_ = NULL;
67     ui_thread_server_ = NULL;
68   }
69
70   // IPC::Sender implementation.
71   virtual bool Send(IPC::Message* msg_ptr) OVERRIDE {
72     scoped_ptr<IPC::Message> msg(msg_ptr);
73
74     if (!sender_)
75       return false;
76
77     return sender_->Send(msg.release());
78   }
79
80  private:
81   virtual ~ExtensionServerMessageFilter() {}
82
83   int64_t GetInstanceIDFromMessage(const IPC::Message& message) {
84     PickleIterator iter;
85
86     if (message.is_sync())
87       iter = IPC::SyncMessage::GetDataIterator(&message);
88     else
89       iter = PickleIterator(message);
90
91     int64_t instance_id;
92     if (!iter.ReadInt64(&instance_id))
93       return -1;
94
95     return instance_id;
96   }
97
98   void RouteMessageToServer(const IPC::Message& message) {
99     int64_t id = GetInstanceIDFromMessage(message);
100     DCHECK_NE(id, -1);
101
102     XWalkExtensionServer* server;
103     base::TaskRunner* task_runner;
104     scoped_refptr<base::TaskRunner> task_runner_ref;
105
106     if (ContainsKey(extension_thread_instances_ids_, id)) {
107       server = extension_thread_server_;
108       task_runner = task_runner_;
109     } else {
110       server = ui_thread_server_;
111       task_runner_ref =
112           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
113       task_runner = task_runner_ref.get();
114     }
115
116     base::Closure closure = base::Bind(
117         base::IgnoreResult(&XWalkExtensionServer::OnMessageReceived),
118         base::Unretained(server), message);
119
120     task_runner->PostTask(FROM_HERE, closure);
121   }
122
123   void OnCreateInstance(int64_t instance_id, std::string name) {
124     XWalkExtensionServer* server;
125     base::TaskRunner* task_runner;
126     scoped_refptr<base::TaskRunner> task_runner_ref;
127
128     if (extension_thread_server_->ContainsExtension(name)) {
129       extension_thread_instances_ids_.insert(instance_id);
130       server = extension_thread_server_;
131       task_runner = task_runner_;
132     } else {
133       server = ui_thread_server_;
134       task_runner_ref =
135           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
136       task_runner = task_runner_ref.get();
137     }
138
139     base::Closure closure = base::Bind(
140         base::IgnoreResult(&XWalkExtensionServer::OnCreateInstance),
141         base::Unretained(server), instance_id, name);
142
143     task_runner->PostTask(FROM_HERE, closure);
144   }
145
146   void OnGetExtensions(
147       std::vector<XWalkExtensionServerMsg_ExtensionRegisterParams>* reply) {
148     extension_thread_server_->OnGetExtensions(reply);
149     ui_thread_server_->OnGetExtensions(reply);
150   }
151
152   // IPC::ChannelProxy::MessageFilter implementation.
153   virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE {
154     sender_ = channel;
155   }
156
157   virtual void OnFilterRemoved() OVERRIDE {
158     sender_ = NULL;
159   }
160
161   virtual void OnChannelClosing() OVERRIDE {
162     sender_ = NULL;
163   }
164
165   virtual void OnChannelError() OVERRIDE {
166     sender_ = NULL;
167   }
168
169   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
170     if (IPC_MESSAGE_CLASS(message) != XWalkExtensionClientServerMsgStart)
171       return false;
172
173     base::AutoLock l(lock_);
174
175     if (!extension_thread_server_ || !ui_thread_server_)
176       return false;
177
178     bool handled = true;
179     IPC_BEGIN_MESSAGE_MAP(ExtensionServerMessageFilter, message)
180       IPC_MESSAGE_HANDLER(XWalkExtensionServerMsg_CreateInstance,
181                           OnCreateInstance)
182       IPC_MESSAGE_HANDLER(XWalkExtensionServerMsg_GetExtensions,
183                           OnGetExtensions)
184       IPC_MESSAGE_UNHANDLED(handled = false)
185     IPC_END_MESSAGE_MAP()
186
187     if (!handled)
188       RouteMessageToServer(message);
189
190     return true;
191   }
192
193   // This lock is used to protect access to filter members.
194   base::Lock lock_;
195
196   IPC::Sender* sender_;
197   scoped_refptr<base::SequencedTaskRunner> task_runner_;
198   XWalkExtensionServer* extension_thread_server_;
199   XWalkExtensionServer* ui_thread_server_;
200   std::set<int64_t> extension_thread_instances_ids_;
201 };
202
203 XWalkExtensionService::XWalkExtensionService()
204     : extension_thread_("XWalkExtensionThread") {
205   if (!g_external_extensions_path_for_testing_.empty())
206     external_extensions_path_ = g_external_extensions_path_for_testing_;
207   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
208                  content::NotificationService::AllBrowserContextsAndSources());
209
210   // IO main loop is needed by extensions watching file descriptors events.
211   base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
212   extension_thread_.StartWithOptions(options);
213 }
214
215 XWalkExtensionService::~XWalkExtensionService() {
216   // This object should have been released and asked to be deleted in the
217   // extension thread.
218   if (!extension_data_map_.empty())
219     VLOG(1) << "The ExtensionData map is not empty!";
220 }
221
222 void XWalkExtensionService::RegisterExternalExtensionsForPath(
223     const base::FilePath& path) {
224   external_extensions_path_ = path;
225 }
226
227 void XWalkExtensionService::OnRenderProcessHostCreated(
228     content::RenderProcessHost* host,
229     XWalkExtensionVector* ui_thread_extensions,
230     XWalkExtensionVector* extension_thread_extensions) {
231   CHECK(host);
232
233   XWalkExtensionData* data = new XWalkExtensionData;
234   data->set_render_process_host(host);
235
236   CreateInProcessExtensionServers(host, data, ui_thread_extensions,
237                                   extension_thread_extensions);
238
239   CommandLine* cmd_line = CommandLine::ForCurrentProcess();
240   if (!cmd_line->HasSwitch(switches::kXWalkDisableExtensionProcess))
241     CreateExtensionProcessHost(host, data);
242   else if (!external_extensions_path_.empty()) {
243     RegisterExternalExtensionsInDirectory(
244         data->in_process_ui_thread_server(),
245         external_extensions_path_);
246   }
247
248   extension_data_map_[host->GetID()] = data;
249 }
250
251 // static
252 void
253 XWalkExtensionService::SetCreateExtensionThreadExtensionsCallbackForTesting(
254     const CreateExtensionsCallback& callback) {
255   g_create_extension_thread_extensions_callback = callback;
256 }
257
258 // static
259 void
260 XWalkExtensionService::SetCreateUIThreadExtensionsCallbackForTesting(
261     const CreateExtensionsCallback& callback) {
262   g_create_ui_thread_extensions_callback = callback;
263 }
264
265 // static
266 void XWalkExtensionService::SetExternalExtensionsPathForTesting(
267     const base::FilePath& path) {
268   g_external_extensions_path_for_testing_ = path;
269 }
270
271 // We use this to keep track of the RenderProcess shutdown events.
272 // This is _very_ important so we can clean up all we need gracefully,
273 // avoiding invalid IPC steps after the IPC channel is gonne.
274 void XWalkExtensionService::Observe(int type,
275                               const content::NotificationSource& source,
276                               const content::NotificationDetails& details) {
277   switch (type) {
278     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
279     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
280       content::RenderProcessHost* rph =
281           content::Source<content::RenderProcessHost>(source).ptr();
282       OnRenderProcessHostClosed(rph);
283     }
284   }
285 }
286
287 void XWalkExtensionService::OnRenderProcessHostClosed(
288     content::RenderProcessHost* host) {
289   RenderProcessToExtensionDataMap::iterator it =
290       extension_data_map_.find(host->GetID());
291
292   if (it == extension_data_map_.end())
293     return;
294
295   XWalkExtensionData* data = it->second;
296
297   // Invalidate the objects in the different threads so they stop posting
298   // messages to each other. This is important because we'll schedule the
299   // deletion of both objects to their respective threads.
300   ExtensionServerMessageFilter* message_filter =
301       data->in_process_message_filter();
302   CHECK(message_filter);
303
304   message_filter->Invalidate();
305
306   // This will cause the filter to be deleted in the IO-thread.
307   host->GetChannel()->RemoveFilter(message_filter);
308
309   extension_data_map_.erase(it);
310   delete data;
311 }
312
313 namespace {
314
315 void RegisterExtensionsIntoServer(XWalkExtensionVector* extensions,
316                                   XWalkExtensionServer* server) {
317   XWalkExtensionVector::iterator it = extensions->begin();
318   for (; it != extensions->end(); ++it) {
319     std::string name = (*it)->name();
320     if (!server->RegisterExtension(scoped_ptr<XWalkExtension>(*it))) {
321       LOG(WARNING) << "Couldn't register extension with name '"
322                    << name << "'\n";
323     }
324   }
325   extensions->clear();
326 }
327
328 }  // namespace
329
330
331 void XWalkExtensionService::CreateInProcessExtensionServers(
332     content::RenderProcessHost* host, XWalkExtensionData* data,
333     XWalkExtensionVector* ui_thread_extensions,
334     XWalkExtensionVector* extension_thread_extensions) {
335   scoped_ptr<XWalkExtensionServer> extension_thread_server(
336       new XWalkExtensionServer);
337   scoped_ptr<XWalkExtensionServer> ui_thread_server(
338       new XWalkExtensionServer);
339
340   IPC::ChannelProxy* channel = host->GetChannel();
341
342   extension_thread_server->Initialize(channel);
343   ui_thread_server->Initialize(channel);
344
345   RegisterExtensionsIntoServer(extension_thread_extensions,
346                                extension_thread_server.get());
347   RegisterExtensionsIntoServer(ui_thread_extensions, ui_thread_server.get());
348
349   if (!g_create_ui_thread_extensions_callback.is_null()) {
350     XWalkExtensionVector extensions;
351     g_create_ui_thread_extensions_callback.Run(&extensions);
352     RegisterExtensionsIntoServer(&extensions, ui_thread_server.get());
353   }
354
355   if (!g_create_extension_thread_extensions_callback.is_null()) {
356     XWalkExtensionVector extensions;
357     g_create_extension_thread_extensions_callback.Run(&extensions);
358     RegisterExtensionsIntoServer(&extensions, extension_thread_server.get());
359   }
360
361   ExtensionServerMessageFilter* message_filter =
362       new ExtensionServerMessageFilter(extension_thread_.message_loop_proxy(),
363                                        extension_thread_server.get(),
364                                        ui_thread_server.get());
365
366   // The filter is owned by the IPC channel but we keep a reference to remove
367   // it from the Channel later during a RenderProcess shutdown.
368   data->set_in_process_message_filter(message_filter);
369   channel->AddFilter(message_filter);
370
371   data->set_in_process_extension_thread_server(extension_thread_server.Pass());
372   data->set_in_process_ui_thread_server(ui_thread_server.Pass());
373
374   data->set_extension_thread(&extension_thread_);
375 }
376
377 void XWalkExtensionService::CreateExtensionProcessHost(
378     content::RenderProcessHost* host, XWalkExtensionData* data) {
379   data->set_extension_process_host(make_scoped_ptr(
380       new XWalkExtensionProcessHost(host, external_extensions_path_, this)));
381 }
382
383 void XWalkExtensionService::OnExtensionProcessDied(
384     XWalkExtensionProcessHost* eph, int render_process_id) {
385   // When this is called it means that XWalkExtensionProcessHost is about
386   // to be deleted. We should invalidate our reference to it so we avoid a
387   // segfault when trying to delete it within
388   // XWalkExtensionService::OnRenderProcessHostClosed();
389
390   RenderProcessToExtensionDataMap::iterator it =
391       extension_data_map_.find(render_process_id);
392
393   if (it == extension_data_map_.end())
394     return;
395
396   XWalkExtensionData* data = it->second;
397
398   XWalkExtensionProcessHost* stored_eph =
399       data->extension_process_host().release();
400   CHECK_EQ(stored_eph, eph);
401
402   content::RenderProcessHost* rph = data->render_process_host();
403   if (rph) {
404     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
405         base::IgnoreResult(&content::RenderProcessHost::FastShutdownIfPossible),
406         base::Unretained(rph)));
407   }
408
409   extension_data_map_.erase(it);
410   delete data;
411 }
412
413 void XWalkExtensionService::OnRenderProcessDied(
414     content::RenderProcessHost* host) {
415   RenderProcessToExtensionDataMap::iterator it =
416       extension_data_map_.find(host->GetID());
417
418   if (it == extension_data_map_.end())
419     return;
420
421   XWalkExtensionData* data = it->second;
422
423   extension_data_map_.erase(it);
424   delete data;
425 }
426
427 }  // namespace extensions
428 }  // namespace xwalk