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.
5 #include "xwalk/extensions/browser/xwalk_extension_service.h"
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 "ipc/message_filter.h"
20 #include "xwalk/extensions/browser/xwalk_extension_data.h"
21 #include "xwalk/extensions/browser/xwalk_extension_process_host.h"
22 #include "xwalk/extensions/common/xwalk_extension.h"
23 #include "xwalk/extensions/common/xwalk_extension_messages.h"
24 #include "xwalk/extensions/common/xwalk_extension_server.h"
25 #include "xwalk/extensions/common/xwalk_extension_switches.h"
27 using content::BrowserThread;
30 namespace extensions {
34 XWalkExtensionService::CreateExtensionsCallback
35 g_create_extension_thread_extensions_callback;
37 XWalkExtensionService::CreateExtensionsCallback
38 g_create_ui_thread_extensions_callback;
40 base::FilePath g_external_extensions_path_for_testing_;
44 // This object intercepts messages destined to a XWalkExtensionServer and
45 // dispatch them to its task runner. A message loop proxy of a thread is a
46 // task runner. Like other filters, this filter will run in the IO-thread.
48 // In the case of in process extensions, we will pass the task runner of the
50 class ExtensionServerMessageFilter : public IPC::MessageFilter,
53 ExtensionServerMessageFilter(
54 scoped_refptr<base::SequencedTaskRunner> task_runner,
55 XWalkExtensionServer* extension_thread_server,
56 XWalkExtensionServer* ui_thread_server)
58 task_runner_(task_runner),
59 extension_thread_server_(extension_thread_server),
60 ui_thread_server_(ui_thread_server) {}
62 // Tells the filter to stop dispatching messages to the server.
64 base::AutoLock l(lock_);
67 extension_thread_server_ = NULL;
68 ui_thread_server_ = NULL;
71 // IPC::Sender implementation.
72 virtual bool Send(IPC::Message* msg_ptr) OVERRIDE {
73 scoped_ptr<IPC::Message> msg(msg_ptr);
78 return sender_->Send(msg.release());
82 virtual ~ExtensionServerMessageFilter() {}
84 int64_t GetInstanceIDFromMessage(const IPC::Message& message) {
87 if (message.is_sync())
88 iter = IPC::SyncMessage::GetDataIterator(&message);
90 iter = PickleIterator(message);
93 if (!iter.ReadInt64(&instance_id))
99 void RouteMessageToServer(const IPC::Message& message) {
100 int64_t id = GetInstanceIDFromMessage(message);
103 XWalkExtensionServer* server;
104 base::TaskRunner* task_runner;
105 scoped_refptr<base::TaskRunner> task_runner_ref;
107 if (ContainsKey(extension_thread_instances_ids_, id)) {
108 server = extension_thread_server_;
109 task_runner = task_runner_.get();
111 server = ui_thread_server_;
113 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
114 task_runner = task_runner_ref.get();
117 base::Closure closure = base::Bind(
118 base::IgnoreResult(&XWalkExtensionServer::OnMessageReceived),
119 server->AsWeakPtr(), message);
121 task_runner->PostTask(FROM_HERE, closure);
124 void OnCreateInstance(int64_t instance_id, std::string name) {
125 XWalkExtensionServer* server;
126 base::TaskRunner* task_runner;
127 scoped_refptr<base::TaskRunner> task_runner_ref;
129 if (extension_thread_server_->ContainsExtension(name)) {
130 extension_thread_instances_ids_.insert(instance_id);
131 server = extension_thread_server_;
132 task_runner = task_runner_.get();
134 server = ui_thread_server_;
136 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
137 task_runner = task_runner_ref.get();
140 base::Closure closure = base::Bind(
141 base::IgnoreResult(&XWalkExtensionServer::OnCreateInstance),
142 server->AsWeakPtr(), instance_id, name);
144 task_runner->PostTask(FROM_HERE, closure);
147 void OnGetExtensions(
148 std::vector<XWalkExtensionServerMsg_ExtensionRegisterParams>* reply) {
149 extension_thread_server_->OnGetExtensions(reply);
150 ui_thread_server_->OnGetExtensions(reply);
153 // IPC::ChannelProxy::MessageFilter implementation.
154 virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE {
158 virtual void OnFilterRemoved() OVERRIDE {
162 virtual void OnChannelClosing() OVERRIDE {
166 virtual void OnChannelError() OVERRIDE {
170 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
171 if (IPC_MESSAGE_CLASS(message) != XWalkExtensionClientServerMsgStart)
174 base::AutoLock l(lock_);
176 if (!extension_thread_server_ || !ui_thread_server_)
180 IPC_BEGIN_MESSAGE_MAP(ExtensionServerMessageFilter, message)
181 IPC_MESSAGE_HANDLER(XWalkExtensionServerMsg_CreateInstance,
183 IPC_MESSAGE_HANDLER(XWalkExtensionServerMsg_GetExtensions,
185 IPC_MESSAGE_UNHANDLED(handled = false)
186 IPC_END_MESSAGE_MAP()
189 RouteMessageToServer(message);
194 // This lock is used to protect access to filter members.
197 IPC::Sender* sender_;
198 scoped_refptr<base::SequencedTaskRunner> task_runner_;
199 XWalkExtensionServer* extension_thread_server_;
200 XWalkExtensionServer* ui_thread_server_;
201 std::set<int64_t> extension_thread_instances_ids_;
204 bool XWalkExtensionService::Delegate::RegisterPermissions(
205 int render_process_id,
206 const std::string& extension_name,
207 const std::string& perm_table) {
211 XWalkExtensionService::XWalkExtensionService(Delegate* delegate)
212 : extension_thread_("XWalkExtensionThread"),
213 delegate_(delegate) {
214 if (!g_external_extensions_path_for_testing_.empty())
215 external_extensions_path_ = g_external_extensions_path_for_testing_;
216 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
217 content::NotificationService::AllBrowserContextsAndSources());
219 // IO main loop is needed by extensions watching file descriptors events.
220 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
221 extension_thread_.StartWithOptions(options);
224 XWalkExtensionService::~XWalkExtensionService() {
225 // This object should have been released and asked to be deleted in the
227 if (!extension_data_map_.empty())
228 VLOG(1) << "The ExtensionData map is not empty!";
231 void XWalkExtensionService::RegisterExternalExtensionsForPath(
232 const base::FilePath& path) {
233 external_extensions_path_ = path;
236 void XWalkExtensionService::OnRenderProcessHostCreatedInternal(
237 content::RenderProcessHost* host,
238 XWalkExtensionVector* ui_thread_extensions,
239 XWalkExtensionVector* extension_thread_extensions,
240 scoped_ptr<base::ValueMap> runtime_variables) {
241 XWalkExtensionData* data = new XWalkExtensionData;
242 data->set_render_process_host(host);
244 CreateInProcessExtensionServers(host, data, ui_thread_extensions,
245 extension_thread_extensions);
247 CommandLine* cmd_line = CommandLine::ForCurrentProcess();
248 if (!cmd_line->HasSwitch(switches::kXWalkDisableExtensionProcess)) {
249 CreateExtensionProcessHost(host, data, runtime_variables.Pass());
250 } else if (!external_extensions_path_.empty()) {
251 RegisterExternalExtensionsInDirectory(
252 data->in_process_ui_thread_server(),
253 external_extensions_path_, runtime_variables.Pass());
256 extension_data_map_[host->GetID()] = data;
259 void XWalkExtensionService::OnRenderProcessWillLaunch(
260 content::RenderProcessHost* host,
261 XWalkExtensionVector* ui_thread_extensions,
262 XWalkExtensionVector* extension_thread_extensions,
263 scoped_ptr<base::ValueMap> runtime_variables) {
266 if (!g_external_extensions_path_for_testing_.empty()) {
267 (*runtime_variables)["runtime_name"] =
268 new base::StringValue("xwalk");
269 OnRenderProcessHostCreatedInternal(host, ui_thread_extensions,
270 extension_thread_extensions, runtime_variables.Pass());
274 OnRenderProcessHostCreatedInternal(host, ui_thread_extensions,
275 extension_thread_extensions, runtime_variables.Pass());
280 XWalkExtensionService::SetCreateExtensionThreadExtensionsCallbackForTesting(
281 const CreateExtensionsCallback& callback) {
282 g_create_extension_thread_extensions_callback = callback;
287 XWalkExtensionService::SetCreateUIThreadExtensionsCallbackForTesting(
288 const CreateExtensionsCallback& callback) {
289 g_create_ui_thread_extensions_callback = callback;
293 void XWalkExtensionService::SetExternalExtensionsPathForTesting(
294 const base::FilePath& path) {
295 g_external_extensions_path_for_testing_ = path;
298 // We use this to keep track of the RenderProcess shutdown events.
299 // This is _very_ important so we can clean up all we need gracefully,
300 // avoiding invalid IPC steps after the IPC channel is gonne.
301 void XWalkExtensionService::Observe(int type,
302 const content::NotificationSource& source,
303 const content::NotificationDetails& details) {
305 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
306 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
307 content::RenderProcessHost* rph =
308 content::Source<content::RenderProcessHost>(source).ptr();
309 OnRenderProcessHostClosed(rph);
314 void XWalkExtensionService::OnRenderProcessHostClosed(
315 content::RenderProcessHost* host) {
316 RenderProcessToExtensionDataMap::iterator it =
317 extension_data_map_.find(host->GetID());
319 if (it == extension_data_map_.end())
322 XWalkExtensionData* data = it->second;
324 // Invalidate the objects in the different threads so they stop posting
325 // messages to each other. This is important because we'll schedule the
326 // deletion of both objects to their respective threads.
327 ExtensionServerMessageFilter* message_filter =
328 data->in_process_message_filter();
329 CHECK(message_filter);
331 message_filter->Invalidate();
333 // This will cause the filter to be deleted in the IO-thread.
334 host->GetChannel()->RemoveFilter(message_filter);
336 extension_data_map_.erase(it);
342 void RegisterExtensionsIntoServer(XWalkExtensionVector* extensions,
343 XWalkExtensionServer* server) {
344 XWalkExtensionVector::iterator it = extensions->begin();
345 for (; it != extensions->end(); ++it) {
346 std::string name = (*it)->name();
347 if (!server->RegisterExtension(scoped_ptr<XWalkExtension>(*it))) {
348 LOG(WARNING) << "Couldn't register extension with name '"
358 void XWalkExtensionService::CreateInProcessExtensionServers(
359 content::RenderProcessHost* host, XWalkExtensionData* data,
360 XWalkExtensionVector* ui_thread_extensions,
361 XWalkExtensionVector* extension_thread_extensions) {
362 scoped_ptr<XWalkExtensionServer> extension_thread_server(
363 new XWalkExtensionServer);
364 scoped_ptr<XWalkExtensionServer> ui_thread_server(
365 new XWalkExtensionServer);
367 IPC::ChannelProxy* channel = host->GetChannel();
369 extension_thread_server->Initialize(channel);
370 ui_thread_server->Initialize(channel);
372 RegisterExtensionsIntoServer(extension_thread_extensions,
373 extension_thread_server.get());
374 RegisterExtensionsIntoServer(ui_thread_extensions, ui_thread_server.get());
376 if (!g_create_ui_thread_extensions_callback.is_null()) {
377 XWalkExtensionVector extensions;
378 g_create_ui_thread_extensions_callback.Run(&extensions);
379 RegisterExtensionsIntoServer(&extensions, ui_thread_server.get());
382 if (!g_create_extension_thread_extensions_callback.is_null()) {
383 XWalkExtensionVector extensions;
384 g_create_extension_thread_extensions_callback.Run(&extensions);
385 RegisterExtensionsIntoServer(&extensions, extension_thread_server.get());
388 ExtensionServerMessageFilter* message_filter =
389 new ExtensionServerMessageFilter(extension_thread_.message_loop_proxy(),
390 extension_thread_server.get(),
391 ui_thread_server.get());
393 // The filter is owned by the IPC channel but we keep a reference to remove
394 // it from the Channel later during a RenderProcess shutdown.
395 data->set_in_process_message_filter(message_filter);
396 channel->AddFilter(message_filter);
398 data->set_in_process_extension_thread_server(extension_thread_server.Pass());
399 data->set_in_process_ui_thread_server(ui_thread_server.Pass());
401 data->set_extension_thread(&extension_thread_);
404 void XWalkExtensionService::CreateExtensionProcessHost(
405 content::RenderProcessHost* host, XWalkExtensionData* data,
406 scoped_ptr<base::ValueMap> runtime_variables) {
407 data->set_extension_process_host(make_scoped_ptr(
408 new XWalkExtensionProcessHost(host, external_extensions_path_, this,
409 runtime_variables.Pass())));
412 void XWalkExtensionService::OnExtensionProcessDied(
413 XWalkExtensionProcessHost* eph, int render_process_id) {
414 // When this is called it means that XWalkExtensionProcessHost is about
415 // to be deleted. We should invalidate our reference to it so we avoid a
416 // segfault when trying to delete it within
417 // XWalkExtensionService::OnRenderProcessHostClosed();
419 RenderProcessToExtensionDataMap::iterator it =
420 extension_data_map_.find(render_process_id);
422 if (it == extension_data_map_.end())
425 XWalkExtensionData* data = it->second;
427 XWalkExtensionProcessHost* stored_eph =
428 data->extension_process_host().release();
429 CHECK_EQ(stored_eph, eph);
431 content::RenderProcessHost* rph = data->render_process_host();
433 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
434 base::IgnoreResult(&content::RenderProcessHost::FastShutdownIfPossible),
435 base::Unretained(rph)));
438 extension_data_map_.erase(it);
442 void XWalkExtensionService::OnRenderProcessDied(
443 content::RenderProcessHost* host) {
444 RenderProcessToExtensionDataMap::iterator it =
445 extension_data_map_.find(host->GetID());
447 if (it == extension_data_map_.end())
450 XWalkExtensionData* data = it->second;
452 extension_data_map_.erase(it);
456 void XWalkExtensionService::OnExtensionProcessCreated(
457 int render_process_id,
458 const IPC::ChannelHandle channel_handle) {
460 delegate_->ExtensionProcessCreated(render_process_id, channel_handle);
463 void XWalkExtensionService::OnCheckAPIAccessControl(
464 int render_process_id,
465 const std::string& extension_name,
466 const std::string& api_name,
467 const PermissionCallback& callback) {
469 delegate_->CheckAPIAccessControl(render_process_id, extension_name,
473 bool XWalkExtensionService::OnRegisterPermissions(
474 int render_process_id,
475 const std::string& extension_name,
476 const std::string& perm_table) {
478 return delegate_->RegisterPermissions(render_process_id,
479 extension_name, perm_table);
482 void XWalkExtensionService::OnRenderChannelCreated(int render_process_id) {
484 delegate_->RenderChannelCreated(render_process_id);
487 } // namespace extensions