Upstream version 5.34.97.0
[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 bool XWalkExtensionService::Delegate::RegisterPermissions(
204     int render_process_id,
205     const std::string& extension_name,
206     const std::string& perm_table) {
207   return false;
208 }
209
210 XWalkExtensionService::XWalkExtensionService(Delegate* delegate)
211     : extension_thread_("XWalkExtensionThread"),
212       delegate_(delegate) {
213   if (!g_external_extensions_path_for_testing_.empty())
214     external_extensions_path_ = g_external_extensions_path_for_testing_;
215   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
216                  content::NotificationService::AllBrowserContextsAndSources());
217
218   // IO main loop is needed by extensions watching file descriptors events.
219   base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
220   extension_thread_.StartWithOptions(options);
221 }
222
223 XWalkExtensionService::~XWalkExtensionService() {
224   // This object should have been released and asked to be deleted in the
225   // extension thread.
226   if (!extension_data_map_.empty())
227     VLOG(1) << "The ExtensionData map is not empty!";
228 }
229
230 void XWalkExtensionService::RegisterExternalExtensionsForPath(
231     const base::FilePath& path) {
232   external_extensions_path_ = path;
233 }
234
235 void XWalkExtensionService::OnRenderProcessHostCreatedInternal(
236     content::RenderProcessHost* host,
237     XWalkExtensionVector* ui_thread_extensions,
238     XWalkExtensionVector* extension_thread_extensions,
239     const base::ValueMap& runtime_variables) {
240   XWalkExtensionData* data = new XWalkExtensionData;
241   data->set_render_process_host(host);
242
243   CreateInProcessExtensionServers(host, data, ui_thread_extensions,
244                                   extension_thread_extensions);
245
246   CommandLine* cmd_line = CommandLine::ForCurrentProcess();
247   if (!cmd_line->HasSwitch(switches::kXWalkDisableExtensionProcess))
248     CreateExtensionProcessHost(host, data, runtime_variables);
249   else if (!external_extensions_path_.empty()) {
250     RegisterExternalExtensionsInDirectory(
251         data->in_process_ui_thread_server(),
252         external_extensions_path_, runtime_variables);
253   }
254
255   extension_data_map_[host->GetID()] = data;
256 }
257
258 void XWalkExtensionService::OnRenderProcessWillLaunch(
259     content::RenderProcessHost* host,
260     XWalkExtensionVector* ui_thread_extensions,
261     XWalkExtensionVector* extension_thread_extensions,
262     const base::ValueMap& runtime_variables) {
263   CHECK(host);
264
265   if (!g_external_extensions_path_for_testing_.empty()) {
266     base::ValueMap test_variables;
267     test_variables["runtime_name"] = base::Value::CreateStringValue("xwalk");
268     OnRenderProcessHostCreatedInternal(host, ui_thread_extensions,
269         extension_thread_extensions, test_variables);
270     return;
271   }
272
273   OnRenderProcessHostCreatedInternal(host, ui_thread_extensions,
274       extension_thread_extensions, runtime_variables);
275 }
276
277 // static
278 void
279 XWalkExtensionService::SetCreateExtensionThreadExtensionsCallbackForTesting(
280     const CreateExtensionsCallback& callback) {
281   g_create_extension_thread_extensions_callback = callback;
282 }
283
284 // static
285 void
286 XWalkExtensionService::SetCreateUIThreadExtensionsCallbackForTesting(
287     const CreateExtensionsCallback& callback) {
288   g_create_ui_thread_extensions_callback = callback;
289 }
290
291 // static
292 void XWalkExtensionService::SetExternalExtensionsPathForTesting(
293     const base::FilePath& path) {
294   g_external_extensions_path_for_testing_ = path;
295 }
296
297 // We use this to keep track of the RenderProcess shutdown events.
298 // This is _very_ important so we can clean up all we need gracefully,
299 // avoiding invalid IPC steps after the IPC channel is gonne.
300 void XWalkExtensionService::Observe(int type,
301                               const content::NotificationSource& source,
302                               const content::NotificationDetails& details) {
303   switch (type) {
304     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
305     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
306       content::RenderProcessHost* rph =
307           content::Source<content::RenderProcessHost>(source).ptr();
308       OnRenderProcessHostClosed(rph);
309     }
310   }
311 }
312
313 void XWalkExtensionService::OnRenderProcessHostClosed(
314     content::RenderProcessHost* host) {
315   RenderProcessToExtensionDataMap::iterator it =
316       extension_data_map_.find(host->GetID());
317
318   if (it == extension_data_map_.end())
319     return;
320
321   XWalkExtensionData* data = it->second;
322
323   // Invalidate the objects in the different threads so they stop posting
324   // messages to each other. This is important because we'll schedule the
325   // deletion of both objects to their respective threads.
326   ExtensionServerMessageFilter* message_filter =
327       data->in_process_message_filter();
328   CHECK(message_filter);
329
330   message_filter->Invalidate();
331
332   // This will cause the filter to be deleted in the IO-thread.
333   host->GetChannel()->RemoveFilter(message_filter);
334
335   extension_data_map_.erase(it);
336   delete data;
337 }
338
339 namespace {
340
341 void RegisterExtensionsIntoServer(XWalkExtensionVector* extensions,
342                                   XWalkExtensionServer* server) {
343   XWalkExtensionVector::iterator it = extensions->begin();
344   for (; it != extensions->end(); ++it) {
345     std::string name = (*it)->name();
346     if (!server->RegisterExtension(scoped_ptr<XWalkExtension>(*it))) {
347       LOG(WARNING) << "Couldn't register extension with name '"
348                    << name << "'\n";
349     }
350   }
351   extensions->clear();
352 }
353
354 }  // namespace
355
356
357 void XWalkExtensionService::CreateInProcessExtensionServers(
358     content::RenderProcessHost* host, XWalkExtensionData* data,
359     XWalkExtensionVector* ui_thread_extensions,
360     XWalkExtensionVector* extension_thread_extensions) {
361   scoped_ptr<XWalkExtensionServer> extension_thread_server(
362       new XWalkExtensionServer);
363   scoped_ptr<XWalkExtensionServer> ui_thread_server(
364       new XWalkExtensionServer);
365
366   IPC::ChannelProxy* channel = host->GetChannel();
367
368   extension_thread_server->Initialize(channel);
369   ui_thread_server->Initialize(channel);
370
371   RegisterExtensionsIntoServer(extension_thread_extensions,
372                                extension_thread_server.get());
373   RegisterExtensionsIntoServer(ui_thread_extensions, ui_thread_server.get());
374
375   if (!g_create_ui_thread_extensions_callback.is_null()) {
376     XWalkExtensionVector extensions;
377     g_create_ui_thread_extensions_callback.Run(&extensions);
378     RegisterExtensionsIntoServer(&extensions, ui_thread_server.get());
379   }
380
381   if (!g_create_extension_thread_extensions_callback.is_null()) {
382     XWalkExtensionVector extensions;
383     g_create_extension_thread_extensions_callback.Run(&extensions);
384     RegisterExtensionsIntoServer(&extensions, extension_thread_server.get());
385   }
386
387   ExtensionServerMessageFilter* message_filter =
388       new ExtensionServerMessageFilter(extension_thread_.message_loop_proxy(),
389                                        extension_thread_server.get(),
390                                        ui_thread_server.get());
391
392   // The filter is owned by the IPC channel but we keep a reference to remove
393   // it from the Channel later during a RenderProcess shutdown.
394   data->set_in_process_message_filter(message_filter);
395   channel->AddFilter(message_filter);
396
397   data->set_in_process_extension_thread_server(extension_thread_server.Pass());
398   data->set_in_process_ui_thread_server(ui_thread_server.Pass());
399
400   data->set_extension_thread(&extension_thread_);
401 }
402
403 void XWalkExtensionService::CreateExtensionProcessHost(
404     content::RenderProcessHost* host, XWalkExtensionData* data,
405     const base::ValueMap& runtime_variables) {
406   data->set_extension_process_host(make_scoped_ptr(
407       new XWalkExtensionProcessHost(host, external_extensions_path_, this,
408                                     runtime_variables)));
409 }
410
411 void XWalkExtensionService::OnExtensionProcessDied(
412     XWalkExtensionProcessHost* eph, int render_process_id) {
413   // When this is called it means that XWalkExtensionProcessHost is about
414   // to be deleted. We should invalidate our reference to it so we avoid a
415   // segfault when trying to delete it within
416   // XWalkExtensionService::OnRenderProcessHostClosed();
417
418   RenderProcessToExtensionDataMap::iterator it =
419       extension_data_map_.find(render_process_id);
420
421   if (it == extension_data_map_.end())
422     return;
423
424   XWalkExtensionData* data = it->second;
425
426   XWalkExtensionProcessHost* stored_eph =
427       data->extension_process_host().release();
428   CHECK_EQ(stored_eph, eph);
429
430   content::RenderProcessHost* rph = data->render_process_host();
431   if (rph) {
432     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
433         base::IgnoreResult(&content::RenderProcessHost::FastShutdownIfPossible),
434         base::Unretained(rph)));
435   }
436
437   extension_data_map_.erase(it);
438   delete data;
439 }
440
441 void XWalkExtensionService::OnRenderProcessDied(
442     content::RenderProcessHost* host) {
443   RenderProcessToExtensionDataMap::iterator it =
444       extension_data_map_.find(host->GetID());
445
446   if (it == extension_data_map_.end())
447     return;
448
449   XWalkExtensionData* data = it->second;
450
451   extension_data_map_.erase(it);
452   delete data;
453 }
454
455 void XWalkExtensionService::OnCheckAPIAccessControl(
456     int render_process_id,
457     const std::string& extension_name,
458     const std::string& api_name,
459     const PermissionCallback& callback) {
460   CHECK(delegate_);
461   delegate_->CheckAPIAccessControl(render_process_id, extension_name,
462                                    api_name, callback);
463 }
464
465 bool XWalkExtensionService::OnRegisterPermissions(
466     int render_process_id,
467     const std::string& extension_name,
468     const std::string& perm_table) {
469   CHECK(delegate_);
470   return delegate_->RegisterPermissions(render_process_id,
471                                         extension_name, perm_table);
472 }
473
474 }  // namespace extensions
475 }  // namespace xwalk