blob: 189907ec7be5ac676d0abe3bd9cbbffbe36e9dec [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
Istiaque Ahmedee72f4952019-03-06 21:18:367#include <utility>
8
Sebastien Marchand6d0558fd2019-01-25 16:49:379#include "base/bind.h"
Devlin Cronina3fe3d602017-11-22 04:47:4310#include "base/feature_list.h"
Brett Wilson27e878c2017-09-08 21:32:2111#include "base/lazy_instance.h"
lazyboy8874f2d2017-05-08 15:07:0812#include "base/threading/platform_thread.h"
lazyboyee4adef2016-05-24 00:55:1613#include "base/threading/thread_local.h"
14#include "base/values.h"
lazyboyee4adef2016-05-24 00:55:1615#include "content/public/renderer/render_thread.h"
John Abd-El-Malek383fc8f62017-10-23 00:08:4216#include "content/public/renderer/worker_thread.h"
lazyboye7847242017-06-07 23:29:1817#include "extensions/common/constants.h"
Devlin Cronina3fe3d602017-11-22 04:47:4318#include "extensions/common/extension_features.h"
lazyboyee4adef2016-05-24 00:55:1619#include "extensions/common/extension_messages.h"
lazyboye7847242017-06-07 23:29:1820#include "extensions/renderer/dispatcher.h"
Istiaque Ahmed96f506092019-07-08 23:40:5721#include "extensions/renderer/extension_interaction_provider.h"
Devlin Cronin0a240222017-12-01 23:17:5122#include "extensions/renderer/extensions_renderer_client.h"
Devlin Cronin095dc132019-03-29 19:43:3023#include "extensions/renderer/native_extension_bindings_system.h"
Devlin Cronin613ebffa2019-04-17 21:04:1724#include "extensions/renderer/native_renderer_messaging_service.h"
lazyboyee4adef2016-05-24 00:55:1625#include "extensions/renderer/service_worker_data.h"
Istiaque Ahmedee72f4952019-03-06 21:18:3626#include "extensions/renderer/worker_script_context_set.h"
Istiaque Ahmed3dd604232019-08-02 19:22:2127#include "extensions/renderer/worker_thread_util.h"
lazyboyee4adef2016-05-24 00:55:1628
29namespace extensions {
30
31namespace {
32
Jens Widellc71ec40a2018-01-04 09:55:1733base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit
34 g_worker_thread_dispatcher_instance = LAZY_INSTANCE_INITIALIZER;
scottmg5e65e3a2017-03-08 08:48:4635base::LazyInstance<base::ThreadLocalPointer<extensions::ServiceWorkerData>>::
36 DestructorAtExit g_data_tls = LAZY_INSTANCE_INITIALIZER;
lazyboyee4adef2016-05-24 00:55:1637
Istiaque Ahmedbe7c3d72019-09-25 21:25:2138ServiceWorkerData* GetServiceWorkerDataChecked() {
39 ServiceWorkerData* data = WorkerThreadDispatcher::GetServiceWorkerData();
40 DCHECK(data);
41 return data;
42}
43
lazyboyee4adef2016-05-24 00:55:1644} // namespace
45
46WorkerThreadDispatcher::WorkerThreadDispatcher() {}
47WorkerThreadDispatcher::~WorkerThreadDispatcher() {}
48
49WorkerThreadDispatcher* WorkerThreadDispatcher::Get() {
Jens Widellc71ec40a2018-01-04 09:55:1750 return g_worker_thread_dispatcher_instance.Pointer();
lazyboyee4adef2016-05-24 00:55:1651}
52
53void WorkerThreadDispatcher::Init(content::RenderThread* render_thread) {
54 DCHECK(render_thread);
55 DCHECK_EQ(content::RenderThread::Get(), render_thread);
56 DCHECK(!message_filter_);
57 message_filter_ = render_thread->GetSyncMessageFilter();
58 render_thread->AddObserver(this);
59}
60
rdevlin.cronin9f338892016-11-21 19:37:0061// static
Devlin Cronin095dc132019-03-29 19:43:3062NativeExtensionBindingsSystem* WorkerThreadDispatcher::GetBindingsSystem() {
Istiaque Ahmedbe7c3d72019-09-25 21:25:2163 return GetServiceWorkerDataChecked()->bindings_system();
lazyboyee4adef2016-05-24 00:55:1664}
65
66// static
rdevlin.cronin9f338892016-11-21 19:37:0067V8SchemaRegistry* WorkerThreadDispatcher::GetV8SchemaRegistry() {
Istiaque Ahmedbe7c3d72019-09-25 21:25:2168 return GetServiceWorkerDataChecked()->v8_schema_registry();
lazyboyee4adef2016-05-24 00:55:1669}
70
lazyboy8874f2d2017-05-08 15:07:0871// static
Devlin Cronin4f02ff0b2017-07-19 17:46:1072ScriptContext* WorkerThreadDispatcher::GetScriptContext() {
Istiaque Ahmedbe7c3d72019-09-25 21:25:2173 return GetServiceWorkerDataChecked()->context();
Devlin Cronin4f02ff0b2017-07-19 17:46:1074}
75
76// static
Istiaque Ahmed91d6987c2019-06-25 00:09:3377ServiceWorkerData* WorkerThreadDispatcher::GetServiceWorkerData() {
Istiaque Ahmedbe7c3d72019-09-25 21:25:2178 return g_data_tls.Pointer()->Get();
Istiaque Ahmed91d6987c2019-06-25 00:09:3379}
80
81// static
lazyboy8874f2d2017-05-08 15:07:0882bool WorkerThreadDispatcher::HandlesMessageOnWorkerThread(
83 const IPC::Message& message) {
lazyboye7847242017-06-07 23:29:1884 return message.type() == ExtensionMsg_ResponseWorker::ID ||
Istiaque Ahmedee72f4952019-03-06 21:18:3685 message.type() == ExtensionMsg_DispatchEvent::ID ||
86 message.type() == ExtensionMsg_DispatchOnConnect::ID ||
87 message.type() == ExtensionMsg_DeliverMessage::ID ||
88 message.type() == ExtensionMsg_DispatchOnDisconnect::ID ||
89 message.type() == ExtensionMsg_ValidateMessagePort::ID;
lazyboy8874f2d2017-05-08 15:07:0890}
91
92// static
93void WorkerThreadDispatcher::ForwardIPC(int worker_thread_id,
94 const IPC::Message& message) {
95 WorkerThreadDispatcher::Get()->OnMessageReceivedOnWorkerThread(
96 worker_thread_id, message);
97}
98
Istiaque Ahmed3dd604232019-08-02 19:22:2199// static
100void WorkerThreadDispatcher::UpdateBindingsOnWorkerThread(
101 const ExtensionId& extension_id) {
102 DCHECK(worker_thread_util::IsWorkerThread());
103 DCHECK(!extension_id.empty());
104 GetBindingsSystem()->UpdateBindings(extension_id,
105 true /* permissions_changed */,
106 Dispatcher::GetWorkerScriptContextSet());
107}
108
lazyboyee4adef2016-05-24 00:55:16109bool WorkerThreadDispatcher::OnControlMessageReceived(
110 const IPC::Message& message) {
lazyboy8874f2d2017-05-08 15:07:08111 if (HandlesMessageOnWorkerThread(message)) {
Kinuko Yasudab56fc92a2019-07-01 11:39:13112 int worker_thread_id = content::WorkerThread::kInvalidWorkerThreadId;
lazyboye7847242017-06-07 23:29:18113 // TODO(lazyboy): Route |message| directly to the child thread using routed
114 // IPC. Probably using mojo?
lazyboy8874f2d2017-05-08 15:07:08115 bool found = base::PickleIterator(message).ReadInt(&worker_thread_id);
lazyboye7847242017-06-07 23:29:18116 CHECK(found);
Istiaque Ahmed461c4ed2017-09-14 17:23:45117 if (worker_thread_id == kMainThreadId)
lazyboye7847242017-06-07 23:29:18118 return false;
Istiaque Ahmedb488bf42019-09-26 04:30:58119 return PostTaskToWorkerThread(
120 worker_thread_id, base::BindOnce(&WorkerThreadDispatcher::ForwardIPC,
121 worker_thread_id, message));
lazyboy8874f2d2017-05-08 15:07:08122 }
123 return false;
124}
125
Istiaque Ahmed3dd604232019-08-02 19:22:21126bool WorkerThreadDispatcher::UpdateBindingsForWorkers(
127 const ExtensionId& extension_id) {
128 bool success = true;
129 base::AutoLock lock(task_runner_map_lock_);
130 for (const auto& task_runner_info : task_runner_map_) {
131 const int worker_thread_id = task_runner_info.first;
132 base::TaskRunner* runner = task_runner_map_[worker_thread_id];
133 bool posted = runner->PostTask(
134 FROM_HERE,
135 base::BindOnce(&WorkerThreadDispatcher::UpdateBindingsOnWorkerThread,
136 extension_id));
137 success &= posted;
138 }
139 return success;
140}
141
lazyboy8874f2d2017-05-08 15:07:08142void WorkerThreadDispatcher::OnMessageReceivedOnWorkerThread(
143 int worker_thread_id,
144 const IPC::Message& message) {
145 CHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
Istiaque Ahmedb488bf42019-09-26 04:30:58146
147 // If the worker state was already destroyed via
148 // Dispatcher::WillDestroyServiceWorkerContextOnWorkerThread, then
149 // drop this IPC. See https://crbug.com/1008143 for details.
150 if (!GetServiceWorkerData())
151 return;
152
lazyboyee4adef2016-05-24 00:55:16153 bool handled = true;
154 IPC_BEGIN_MESSAGE_MAP(WorkerThreadDispatcher, message)
155 IPC_MESSAGE_HANDLER(ExtensionMsg_ResponseWorker, OnResponseWorker)
lazyboye7847242017-06-07 23:29:18156 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchEvent, OnDispatchEvent)
Istiaque Ahmedee72f4952019-03-06 21:18:36157 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect)
158 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage)
159 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
160 OnDispatchOnDisconnect)
161 IPC_MESSAGE_HANDLER(ExtensionMsg_ValidateMessagePort, OnValidateMessagePort)
lazyboyee4adef2016-05-24 00:55:16162 IPC_MESSAGE_UNHANDLED(handled = false)
163 IPC_END_MESSAGE_MAP()
lazyboy8874f2d2017-05-08 15:07:08164 CHECK(handled);
165}
166
Istiaque Ahmedb488bf42019-09-26 04:30:58167bool WorkerThreadDispatcher::PostTaskToWorkerThread(int worker_thread_id,
168 base::OnceClosure task) {
lazyboy8874f2d2017-05-08 15:07:08169 base::AutoLock lock(task_runner_map_lock_);
David Bertoni1dc1b7a2019-06-13 02:44:59170 auto it = task_runner_map_.find(worker_thread_id);
Istiaque Ahmedb488bf42019-09-26 04:30:58171 if (it == task_runner_map_.end())
172 return false;
173
174 bool task_posted = it->second->PostTask(FROM_HERE, std::move(task));
175 DCHECK(task_posted) << "Could not PostTask IPC to worker thread.";
176 return task_posted;
lazyboyee4adef2016-05-24 00:55:16177}
178
179bool WorkerThreadDispatcher::Send(IPC::Message* message) {
180 return message_filter_->Send(message);
181}
182
183void WorkerThreadDispatcher::OnResponseWorker(int worker_thread_id,
184 int request_id,
185 bool succeeded,
186 const base::ListValue& response,
187 const std::string& error) {
lazyboy8874f2d2017-05-08 15:07:08188 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
Devlin Cronin4607e322017-07-17 16:17:18189 data->bindings_system()->HandleResponse(request_id, succeeded, response,
190 error);
lazyboyee4adef2016-05-24 00:55:16191}
192
lazyboye7847242017-06-07 23:29:18193void WorkerThreadDispatcher::OnDispatchEvent(
194 const ExtensionMsg_DispatchEvent_Params& params,
195 const base::ListValue& event_args) {
196 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
197 DCHECK(data);
Istiaque Ahmed96f506092019-07-08 23:40:57198
199 ScriptContext* script_context = data->context();
200 // Note |scoped_extension_interaction| requires a HandleScope.
201 v8::Isolate* isolate = script_context->isolate();
202 v8::HandleScope handle_scope(isolate);
203 std::unique_ptr<InteractionProvider::Scope> scoped_extension_interaction;
204 if (params.is_user_gesture) {
205 scoped_extension_interaction =
206 ExtensionInteractionProvider::Scope::ForWorker(
207 script_context->v8_context());
208 }
lazyboye7847242017-06-07 23:29:18209 data->bindings_system()->DispatchEventInContext(
210 params.event_name, &event_args, &params.filtering_info, data->context());
Istiaque Ahmed741f69e2019-10-15 19:43:36211 const int worker_thread_id = content::WorkerThread::GetCurrentId();
212 Send(new ExtensionHostMsg_EventAckWorker(data->context()->GetExtensionID(),
213 data->service_worker_version_id(),
214 worker_thread_id, params.event_id));
lazyboye7847242017-06-07 23:29:18215}
216
Istiaque Ahmedee72f4952019-03-06 21:18:36217void WorkerThreadDispatcher::OnDispatchOnConnect(
218 int worker_thread_id,
219 const PortId& target_port_id,
220 const std::string& channel_name,
221 const ExtensionMsg_TabConnectionInfo& source,
222 const ExtensionMsg_ExternalConnectionInfo& info) {
223 DCHECK_EQ(worker_thread_id, content::WorkerThread::GetCurrentId());
224 WorkerThreadDispatcher::GetBindingsSystem()
Devlin Cronin613ebffa2019-04-17 21:04:17225 ->messaging_service()
Istiaque Ahmedee72f4952019-03-06 21:18:36226 ->DispatchOnConnect(Dispatcher::GetWorkerScriptContextSet(),
227 target_port_id, channel_name, source, info,
228 // Render frames do not matter.
229 nullptr);
230}
231
232void WorkerThreadDispatcher::OnValidateMessagePort(int worker_thread_id,
233 const PortId& id) {
234 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
235 WorkerThreadDispatcher::GetBindingsSystem()
Devlin Cronin613ebffa2019-04-17 21:04:17236 ->messaging_service()
Istiaque Ahmedee72f4952019-03-06 21:18:36237 ->ValidateMessagePort(Dispatcher::GetWorkerScriptContextSet(), id,
238 // Render frames do not matter.
239 nullptr);
240}
241
242void WorkerThreadDispatcher::OnDeliverMessage(int worker_thread_id,
243 const PortId& target_port_id,
244 const Message& message) {
245 WorkerThreadDispatcher::GetBindingsSystem()
Devlin Cronin613ebffa2019-04-17 21:04:17246 ->messaging_service()
Istiaque Ahmedee72f4952019-03-06 21:18:36247 ->DeliverMessage(Dispatcher::GetWorkerScriptContextSet(), target_port_id,
248 message,
249 // Render frames do not matter.
250 nullptr);
251}
252
253void WorkerThreadDispatcher::OnDispatchOnDisconnect(
254 int worker_thread_id,
255 const PortId& port_id,
256 const std::string& error_message) {
257 WorkerThreadDispatcher::GetBindingsSystem()
Devlin Cronin613ebffa2019-04-17 21:04:17258 ->messaging_service()
Istiaque Ahmedee72f4952019-03-06 21:18:36259 ->DispatchOnDisconnect(Dispatcher::GetWorkerScriptContextSet(), port_id,
260 error_message,
261 // Render frames do not matter.
262 nullptr);
263}
264
rdevlin.cronin9f338892016-11-21 19:37:00265void WorkerThreadDispatcher::AddWorkerData(
266 int64_t service_worker_version_id,
Istiaque Ahmed9987ca892020-01-09 22:47:17267 ActivationSequence activation_sequence,
Istiaque Ahmed242a4102019-06-25 01:47:57268 ScriptContext* script_context,
Devlin Cronin095dc132019-03-29 19:43:30269 std::unique_ptr<NativeExtensionBindingsSystem> bindings_system) {
lazyboyee4adef2016-05-24 00:55:16270 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
271 if (!data) {
Istiaque Ahmedc92b1ea2019-12-31 00:32:49272 ServiceWorkerData* new_data =
273 new ServiceWorkerData(service_worker_version_id, activation_sequence,
274 script_context, std::move(bindings_system));
lazyboyee4adef2016-05-24 00:55:16275 g_data_tls.Pointer()->Set(new_data);
276 }
lazyboy8874f2d2017-05-08 15:07:08277
Kinuko Yasudab56fc92a2019-07-01 11:39:13278 int worker_thread_id = content::WorkerThread::GetCurrentId();
lazyboy8874f2d2017-05-08 15:07:08279 {
280 base::AutoLock lock(task_runner_map_lock_);
281 auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
282 CHECK(task_runner);
283 task_runner_map_[worker_thread_id] = task_runner;
284 }
lazyboyee4adef2016-05-24 00:55:16285}
286
Istiaque Ahmedd4b67ee2019-03-02 10:53:20287void WorkerThreadDispatcher::DidInitializeContext(
288 int64_t service_worker_version_id) {
289 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
290 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
291 const int thread_id = content::WorkerThread::GetCurrentId();
292 DCHECK_NE(thread_id, kMainThreadId);
293 Send(new ExtensionHostMsg_DidInitializeServiceWorkerContext(
294 data->context()->GetExtensionID(), service_worker_version_id, thread_id));
295}
296
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25297void WorkerThreadDispatcher::DidStartContext(
Istiaque Ahmed4b70a70d2019-02-28 01:36:57298 const GURL& service_worker_scope,
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25299 int64_t service_worker_version_id) {
300 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
301 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
Istiaque Ahmed4b70a70d2019-02-28 01:36:57302 const int thread_id = content::WorkerThread::GetCurrentId();
303 DCHECK_NE(thread_id, kMainThreadId);
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25304 Send(new ExtensionHostMsg_DidStartServiceWorkerContext(
Istiaque Ahmedc92b1ea2019-12-31 00:32:49305 data->context()->GetExtensionID(), data->activation_sequence(),
306 service_worker_scope, service_worker_version_id, thread_id));
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25307}
308
Istiaque Ahmed4b70a70d2019-02-28 01:36:57309void WorkerThreadDispatcher::DidStopContext(const GURL& service_worker_scope,
310 int64_t service_worker_version_id) {
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25311 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
Istiaque Ahmed4b70a70d2019-02-28 01:36:57312 const int thread_id = content::WorkerThread::GetCurrentId();
313 DCHECK_NE(thread_id, kMainThreadId);
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25314 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
315 Send(new ExtensionHostMsg_DidStopServiceWorkerContext(
Istiaque Ahmedc92b1ea2019-12-31 00:32:49316 data->context()->GetExtensionID(), data->activation_sequence(),
317 service_worker_scope, service_worker_version_id, thread_id));
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25318}
319
lazyboy4c82177a2016-10-18 00:04:09320void WorkerThreadDispatcher::RemoveWorkerData(
321 int64_t service_worker_version_id) {
lazyboyee4adef2016-05-24 00:55:16322 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
323 if (data) {
lazyboy4c82177a2016-10-18 00:04:09324 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
lazyboyee4adef2016-05-24 00:55:16325 delete data;
326 g_data_tls.Pointer()->Set(nullptr);
327 }
lazyboy8874f2d2017-05-08 15:07:08328
Kinuko Yasudab56fc92a2019-07-01 11:39:13329 int worker_thread_id = content::WorkerThread::GetCurrentId();
lazyboy8874f2d2017-05-08 15:07:08330 {
331 base::AutoLock lock(task_runner_map_lock_);
332 task_runner_map_.erase(worker_thread_id);
333 }
lazyboyee4adef2016-05-24 00:55:16334}
335
336} // namespace extensions