blob: 563251ab7454005f3b8ebcd3eae890526c64388e [file] [log] [blame]
lazyboyee4adef2016-05-24 00:55:161// Copyright 2016 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 "extensions/renderer/worker_thread_dispatcher.h"
6
Devlin Cronina3fe3d602017-11-22 04:47:437#include "base/feature_list.h"
Brett Wilson27e878c2017-09-08 21:32:218#include "base/lazy_instance.h"
fdorayba121422016-12-23 19:51:489#include "base/memory/ptr_util.h"
lazyboy8874f2d2017-05-08 15:07:0810#include "base/threading/platform_thread.h"
lazyboyee4adef2016-05-24 00:55:1611#include "base/threading/thread_local.h"
12#include "base/values.h"
lazyboyee4adef2016-05-24 00:55:1613#include "content/public/renderer/render_thread.h"
John Abd-El-Malek383fc8f62017-10-23 00:08:4214#include "content/public/renderer/worker_thread.h"
lazyboye7847242017-06-07 23:29:1815#include "extensions/common/constants.h"
Devlin Cronina3fe3d602017-11-22 04:47:4316#include "extensions/common/extension_features.h"
lazyboyee4adef2016-05-24 00:55:1617#include "extensions/common/extension_messages.h"
lazyboye7847242017-06-07 23:29:1818#include "extensions/renderer/dispatcher.h"
rdevlin.cronin9f338892016-11-21 19:37:0019#include "extensions/renderer/extension_bindings_system.h"
Devlin Cronin4607e322017-07-17 16:17:1820#include "extensions/renderer/ipc_message_sender.h"
rdevlin.cronin9f338892016-11-21 19:37:0021#include "extensions/renderer/js_extension_bindings_system.h"
rdevlin.cronin71d78789e2016-11-22 19:49:2722#include "extensions/renderer/native_extension_bindings_system.h"
lazyboyee4adef2016-05-24 00:55:1623#include "extensions/renderer/service_worker_data.h"
24
25namespace extensions {
26
27namespace {
28
scottmg5e65e3a2017-03-08 08:48:4629base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit g_instance =
lazyboyee4adef2016-05-24 00:55:1630 LAZY_INSTANCE_INITIALIZER;
scottmg5e65e3a2017-03-08 08:48:4631base::LazyInstance<base::ThreadLocalPointer<extensions::ServiceWorkerData>>::
32 DestructorAtExit g_data_tls = LAZY_INSTANCE_INITIALIZER;
lazyboyee4adef2016-05-24 00:55:1633
rdevlin.cronin9f338892016-11-21 19:37:0034ServiceWorkerData* GetServiceWorkerData() {
35 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
36 DCHECK(data);
37 return data;
38}
39
lazyboyee4adef2016-05-24 00:55:1640} // namespace
41
42WorkerThreadDispatcher::WorkerThreadDispatcher() {}
43WorkerThreadDispatcher::~WorkerThreadDispatcher() {}
44
45WorkerThreadDispatcher* WorkerThreadDispatcher::Get() {
46 return g_instance.Pointer();
47}
48
49void WorkerThreadDispatcher::Init(content::RenderThread* render_thread) {
50 DCHECK(render_thread);
51 DCHECK_EQ(content::RenderThread::Get(), render_thread);
52 DCHECK(!message_filter_);
53 message_filter_ = render_thread->GetSyncMessageFilter();
54 render_thread->AddObserver(this);
55}
56
rdevlin.cronin9f338892016-11-21 19:37:0057// static
58ExtensionBindingsSystem* WorkerThreadDispatcher::GetBindingsSystem() {
59 return GetServiceWorkerData()->bindings_system();
lazyboyee4adef2016-05-24 00:55:1660}
61
62// static
rdevlin.cronin9f338892016-11-21 19:37:0063V8SchemaRegistry* WorkerThreadDispatcher::GetV8SchemaRegistry() {
64 return GetServiceWorkerData()->v8_schema_registry();
lazyboyee4adef2016-05-24 00:55:1665}
66
lazyboy8874f2d2017-05-08 15:07:0867// static
Devlin Cronin4f02ff0b2017-07-19 17:46:1068ScriptContext* WorkerThreadDispatcher::GetScriptContext() {
69 return GetServiceWorkerData()->context();
70}
71
72// static
lazyboy8874f2d2017-05-08 15:07:0873bool WorkerThreadDispatcher::HandlesMessageOnWorkerThread(
74 const IPC::Message& message) {
lazyboye7847242017-06-07 23:29:1875 return message.type() == ExtensionMsg_ResponseWorker::ID ||
76 message.type() == ExtensionMsg_DispatchEvent::ID;
lazyboy8874f2d2017-05-08 15:07:0877}
78
79// static
80void WorkerThreadDispatcher::ForwardIPC(int worker_thread_id,
81 const IPC::Message& message) {
82 WorkerThreadDispatcher::Get()->OnMessageReceivedOnWorkerThread(
83 worker_thread_id, message);
84}
85
lazyboyee4adef2016-05-24 00:55:1686bool WorkerThreadDispatcher::OnControlMessageReceived(
87 const IPC::Message& message) {
lazyboy8874f2d2017-05-08 15:07:0888 if (HandlesMessageOnWorkerThread(message)) {
89 int worker_thread_id = base::kInvalidThreadId;
lazyboye7847242017-06-07 23:29:1890 // TODO(lazyboy): Route |message| directly to the child thread using routed
91 // IPC. Probably using mojo?
lazyboy8874f2d2017-05-08 15:07:0892 bool found = base::PickleIterator(message).ReadInt(&worker_thread_id);
lazyboye7847242017-06-07 23:29:1893 CHECK(found);
Istiaque Ahmed461c4ed2017-09-14 17:23:4594 if (worker_thread_id == kMainThreadId)
lazyboye7847242017-06-07 23:29:1895 return false;
lazyboy8874f2d2017-05-08 15:07:0896 base::TaskRunner* runner = GetTaskRunnerFor(worker_thread_id);
97 bool task_posted = runner->PostTask(
98 FROM_HERE, base::Bind(&WorkerThreadDispatcher::ForwardIPC,
99 worker_thread_id, message));
100 DCHECK(task_posted) << "Could not PostTask IPC to worker thread.";
101 return true;
102 }
103 return false;
104}
105
106void WorkerThreadDispatcher::OnMessageReceivedOnWorkerThread(
107 int worker_thread_id,
108 const IPC::Message& message) {
109 CHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
lazyboyee4adef2016-05-24 00:55:16110 bool handled = true;
111 IPC_BEGIN_MESSAGE_MAP(WorkerThreadDispatcher, message)
112 IPC_MESSAGE_HANDLER(ExtensionMsg_ResponseWorker, OnResponseWorker)
lazyboye7847242017-06-07 23:29:18113 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchEvent, OnDispatchEvent)
lazyboyee4adef2016-05-24 00:55:16114 IPC_MESSAGE_UNHANDLED(handled = false)
115 IPC_END_MESSAGE_MAP()
lazyboy8874f2d2017-05-08 15:07:08116 CHECK(handled);
117}
118
119base::TaskRunner* WorkerThreadDispatcher::GetTaskRunnerFor(
120 int worker_thread_id) {
121 base::AutoLock lock(task_runner_map_lock_);
122 return task_runner_map_[worker_thread_id];
lazyboyee4adef2016-05-24 00:55:16123}
124
125bool WorkerThreadDispatcher::Send(IPC::Message* message) {
126 return message_filter_->Send(message);
127}
128
129void WorkerThreadDispatcher::OnResponseWorker(int worker_thread_id,
130 int request_id,
131 bool succeeded,
132 const base::ListValue& response,
133 const std::string& error) {
lazyboy8874f2d2017-05-08 15:07:08134 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
Devlin Cronin4607e322017-07-17 16:17:18135 data->bindings_system()->HandleResponse(request_id, succeeded, response,
136 error);
lazyboyee4adef2016-05-24 00:55:16137}
138
lazyboye7847242017-06-07 23:29:18139void WorkerThreadDispatcher::OnDispatchEvent(
140 const ExtensionMsg_DispatchEvent_Params& params,
141 const base::ListValue& event_args) {
142 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
143 DCHECK(data);
144 data->bindings_system()->DispatchEventInContext(
145 params.event_name, &event_args, &params.filtering_info, data->context());
146}
147
rdevlin.cronin9f338892016-11-21 19:37:00148void WorkerThreadDispatcher::AddWorkerData(
149 int64_t service_worker_version_id,
lazyboye7847242017-06-07 23:29:18150 ScriptContext* context,
rdevlin.cronin9f338892016-11-21 19:37:00151 ResourceBundleSourceMap* source_map) {
lazyboyee4adef2016-05-24 00:55:16152 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
153 if (!data) {
rdevlin.cronin71d78789e2016-11-22 19:49:27154 std::unique_ptr<ExtensionBindingsSystem> bindings_system;
Devlin Cronin4607e322017-07-17 16:17:18155 // QUESTION(lazyboy): Why is passing the WorkerThreadDispatcher to the
156 // IPCMessageSender (previously the ServiceWorkerRequestSender) safe? The
157 // WorkerThreadDispatcher is a process-wide singleton, but the
158 // IPCMessageSender is per-context (thus potentially many per process).
159 std::unique_ptr<IPCMessageSender> ipc_message_sender =
160 IPCMessageSender::CreateWorkerThreadIPCMessageSender(
161 this, service_worker_version_id);
Devlin Cronina3fe3d602017-11-22 04:47:43162 if (base::FeatureList::IsEnabled(features::kNativeCrxBindings)) {
Devlin Cronin4607e322017-07-17 16:17:18163 // The Unretained below is safe since the IPC message sender outlives the
164 // bindings system.
Jeremy Roman16529d0e2017-08-24 18:13:47165 bindings_system = std::make_unique<NativeExtensionBindingsSystem>(
Devlin Cronin2b2180c2017-07-19 00:04:01166 std::move(ipc_message_sender));
rdevlin.cronin71d78789e2016-11-22 19:49:27167 } else {
Jeremy Roman16529d0e2017-08-24 18:13:47168 bindings_system = std::make_unique<JsExtensionBindingsSystem>(
Devlin Cronin946720eb2017-07-17 23:58:08169 source_map, std::move(ipc_message_sender));
rdevlin.cronin71d78789e2016-11-22 19:49:27170 }
rdevlin.cronin9f338892016-11-21 19:37:00171 ServiceWorkerData* new_data = new ServiceWorkerData(
Devlin Cronin946720eb2017-07-17 23:58:08172 service_worker_version_id, context, std::move(bindings_system));
lazyboyee4adef2016-05-24 00:55:16173 g_data_tls.Pointer()->Set(new_data);
174 }
lazyboy8874f2d2017-05-08 15:07:08175
176 int worker_thread_id = base::PlatformThread::CurrentId();
177 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
178 {
179 base::AutoLock lock(task_runner_map_lock_);
180 auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
181 CHECK(task_runner);
182 task_runner_map_[worker_thread_id] = task_runner;
183 }
lazyboyee4adef2016-05-24 00:55:16184}
185
lazyboy4c82177a2016-10-18 00:04:09186void WorkerThreadDispatcher::RemoveWorkerData(
187 int64_t service_worker_version_id) {
lazyboyee4adef2016-05-24 00:55:16188 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
189 if (data) {
lazyboy4c82177a2016-10-18 00:04:09190 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
lazyboyee4adef2016-05-24 00:55:16191 delete data;
192 g_data_tls.Pointer()->Set(nullptr);
193 }
lazyboy8874f2d2017-05-08 15:07:08194
195 int worker_thread_id = base::PlatformThread::CurrentId();
196 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
197 {
198 base::AutoLock lock(task_runner_map_lock_);
199 task_runner_map_.erase(worker_thread_id);
200 }
lazyboyee4adef2016-05-24 00:55:16201}
202
203} // namespace extensions