blob: 5a48537f8629eed38776cc23e8afbef702b37945 [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"
rdevlin.cronin9f338892016-11-21 19:37:0021#include "extensions/renderer/extension_bindings_system.h"
Devlin Cronin0a240222017-12-01 23:17:5122#include "extensions/renderer/extensions_renderer_client.h"
rdevlin.cronin9f338892016-11-21 19:37:0023#include "extensions/renderer/js_extension_bindings_system.h"
rdevlin.cronin71d78789e2016-11-22 19:49:2724#include "extensions/renderer/native_extension_bindings_system.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"
lazyboyee4adef2016-05-24 00:55:1627
28namespace extensions {
29
30namespace {
31
Jens Widellc71ec40a2018-01-04 09:55:1732base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit
33 g_worker_thread_dispatcher_instance = LAZY_INSTANCE_INITIALIZER;
scottmg5e65e3a2017-03-08 08:48:4634base::LazyInstance<base::ThreadLocalPointer<extensions::ServiceWorkerData>>::
35 DestructorAtExit g_data_tls = LAZY_INSTANCE_INITIALIZER;
lazyboyee4adef2016-05-24 00:55:1636
rdevlin.cronin9f338892016-11-21 19:37:0037ServiceWorkerData* GetServiceWorkerData() {
38 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
39 DCHECK(data);
40 return data;
41}
42
lazyboyee4adef2016-05-24 00:55:1643} // namespace
44
45WorkerThreadDispatcher::WorkerThreadDispatcher() {}
46WorkerThreadDispatcher::~WorkerThreadDispatcher() {}
47
48WorkerThreadDispatcher* WorkerThreadDispatcher::Get() {
Jens Widellc71ec40a2018-01-04 09:55:1749 return g_worker_thread_dispatcher_instance.Pointer();
lazyboyee4adef2016-05-24 00:55:1650}
51
52void WorkerThreadDispatcher::Init(content::RenderThread* render_thread) {
53 DCHECK(render_thread);
54 DCHECK_EQ(content::RenderThread::Get(), render_thread);
55 DCHECK(!message_filter_);
56 message_filter_ = render_thread->GetSyncMessageFilter();
57 render_thread->AddObserver(this);
58}
59
rdevlin.cronin9f338892016-11-21 19:37:0060// static
61ExtensionBindingsSystem* WorkerThreadDispatcher::GetBindingsSystem() {
62 return GetServiceWorkerData()->bindings_system();
lazyboyee4adef2016-05-24 00:55:1663}
64
65// static
rdevlin.cronin9f338892016-11-21 19:37:0066V8SchemaRegistry* WorkerThreadDispatcher::GetV8SchemaRegistry() {
67 return GetServiceWorkerData()->v8_schema_registry();
lazyboyee4adef2016-05-24 00:55:1668}
69
lazyboy8874f2d2017-05-08 15:07:0870// static
Devlin Cronin4f02ff0b2017-07-19 17:46:1071ScriptContext* WorkerThreadDispatcher::GetScriptContext() {
72 return GetServiceWorkerData()->context();
73}
74
75// static
lazyboy8874f2d2017-05-08 15:07:0876bool WorkerThreadDispatcher::HandlesMessageOnWorkerThread(
77 const IPC::Message& message) {
lazyboye7847242017-06-07 23:29:1878 return message.type() == ExtensionMsg_ResponseWorker::ID ||
Istiaque Ahmedee72f4952019-03-06 21:18:3679 message.type() == ExtensionMsg_DispatchEvent::ID ||
80 message.type() == ExtensionMsg_DispatchOnConnect::ID ||
81 message.type() == ExtensionMsg_DeliverMessage::ID ||
82 message.type() == ExtensionMsg_DispatchOnDisconnect::ID ||
83 message.type() == ExtensionMsg_ValidateMessagePort::ID;
lazyboy8874f2d2017-05-08 15:07:0884}
85
86// static
87void WorkerThreadDispatcher::ForwardIPC(int worker_thread_id,
88 const IPC::Message& message) {
89 WorkerThreadDispatcher::Get()->OnMessageReceivedOnWorkerThread(
90 worker_thread_id, message);
91}
92
lazyboyee4adef2016-05-24 00:55:1693bool WorkerThreadDispatcher::OnControlMessageReceived(
94 const IPC::Message& message) {
lazyboy8874f2d2017-05-08 15:07:0895 if (HandlesMessageOnWorkerThread(message)) {
96 int worker_thread_id = base::kInvalidThreadId;
lazyboye7847242017-06-07 23:29:1897 // TODO(lazyboy): Route |message| directly to the child thread using routed
98 // IPC. Probably using mojo?
lazyboy8874f2d2017-05-08 15:07:0899 bool found = base::PickleIterator(message).ReadInt(&worker_thread_id);
lazyboye7847242017-06-07 23:29:18100 CHECK(found);
Istiaque Ahmed461c4ed2017-09-14 17:23:45101 if (worker_thread_id == kMainThreadId)
lazyboye7847242017-06-07 23:29:18102 return false;
lazyboy8874f2d2017-05-08 15:07:08103 base::TaskRunner* runner = GetTaskRunnerFor(worker_thread_id);
104 bool task_posted = runner->PostTask(
kylechar0686a5232019-02-19 14:10:29105 FROM_HERE, base::BindOnce(&WorkerThreadDispatcher::ForwardIPC,
106 worker_thread_id, message));
lazyboy8874f2d2017-05-08 15:07:08107 DCHECK(task_posted) << "Could not PostTask IPC to worker thread.";
108 return true;
109 }
110 return false;
111}
112
113void WorkerThreadDispatcher::OnMessageReceivedOnWorkerThread(
114 int worker_thread_id,
115 const IPC::Message& message) {
116 CHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
lazyboyee4adef2016-05-24 00:55:16117 bool handled = true;
118 IPC_BEGIN_MESSAGE_MAP(WorkerThreadDispatcher, message)
119 IPC_MESSAGE_HANDLER(ExtensionMsg_ResponseWorker, OnResponseWorker)
lazyboye7847242017-06-07 23:29:18120 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchEvent, OnDispatchEvent)
Istiaque Ahmedee72f4952019-03-06 21:18:36121 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect)
122 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage)
123 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
124 OnDispatchOnDisconnect)
125 IPC_MESSAGE_HANDLER(ExtensionMsg_ValidateMessagePort, OnValidateMessagePort)
lazyboyee4adef2016-05-24 00:55:16126 IPC_MESSAGE_UNHANDLED(handled = false)
127 IPC_END_MESSAGE_MAP()
lazyboy8874f2d2017-05-08 15:07:08128 CHECK(handled);
129}
130
131base::TaskRunner* WorkerThreadDispatcher::GetTaskRunnerFor(
132 int worker_thread_id) {
133 base::AutoLock lock(task_runner_map_lock_);
134 return task_runner_map_[worker_thread_id];
lazyboyee4adef2016-05-24 00:55:16135}
136
137bool WorkerThreadDispatcher::Send(IPC::Message* message) {
138 return message_filter_->Send(message);
139}
140
141void WorkerThreadDispatcher::OnResponseWorker(int worker_thread_id,
142 int request_id,
143 bool succeeded,
144 const base::ListValue& response,
145 const std::string& error) {
lazyboy8874f2d2017-05-08 15:07:08146 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
Devlin Cronin4607e322017-07-17 16:17:18147 data->bindings_system()->HandleResponse(request_id, succeeded, response,
148 error);
lazyboyee4adef2016-05-24 00:55:16149}
150
lazyboye7847242017-06-07 23:29:18151void WorkerThreadDispatcher::OnDispatchEvent(
152 const ExtensionMsg_DispatchEvent_Params& params,
153 const base::ListValue& event_args) {
154 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
155 DCHECK(data);
156 data->bindings_system()->DispatchEventInContext(
157 params.event_name, &event_args, &params.filtering_info, data->context());
Istiaque Ahmeda14ec482018-08-25 01:02:18158 Send(new ExtensionHostMsg_EventAckWorker(data->service_worker_version_id(),
159 params.event_id));
lazyboye7847242017-06-07 23:29:18160}
161
Istiaque Ahmedee72f4952019-03-06 21:18:36162void WorkerThreadDispatcher::OnDispatchOnConnect(
163 int worker_thread_id,
164 const PortId& target_port_id,
165 const std::string& channel_name,
166 const ExtensionMsg_TabConnectionInfo& source,
167 const ExtensionMsg_ExternalConnectionInfo& info) {
168 DCHECK_EQ(worker_thread_id, content::WorkerThread::GetCurrentId());
169 WorkerThreadDispatcher::GetBindingsSystem()
170 ->GetMessagingService()
171 ->DispatchOnConnect(Dispatcher::GetWorkerScriptContextSet(),
172 target_port_id, channel_name, source, info,
173 // Render frames do not matter.
174 nullptr);
175}
176
177void WorkerThreadDispatcher::OnValidateMessagePort(int worker_thread_id,
178 const PortId& id) {
179 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
180 WorkerThreadDispatcher::GetBindingsSystem()
181 ->GetMessagingService()
182 ->ValidateMessagePort(Dispatcher::GetWorkerScriptContextSet(), id,
183 // Render frames do not matter.
184 nullptr);
185}
186
187void WorkerThreadDispatcher::OnDeliverMessage(int worker_thread_id,
188 const PortId& target_port_id,
189 const Message& message) {
190 WorkerThreadDispatcher::GetBindingsSystem()
191 ->GetMessagingService()
192 ->DeliverMessage(Dispatcher::GetWorkerScriptContextSet(), target_port_id,
193 message,
194 // Render frames do not matter.
195 nullptr);
196}
197
198void WorkerThreadDispatcher::OnDispatchOnDisconnect(
199 int worker_thread_id,
200 const PortId& port_id,
201 const std::string& error_message) {
202 WorkerThreadDispatcher::GetBindingsSystem()
203 ->GetMessagingService()
204 ->DispatchOnDisconnect(Dispatcher::GetWorkerScriptContextSet(), port_id,
205 error_message,
206 // Render frames do not matter.
207 nullptr);
208}
209
rdevlin.cronin9f338892016-11-21 19:37:00210void WorkerThreadDispatcher::AddWorkerData(
211 int64_t service_worker_version_id,
lazyboye7847242017-06-07 23:29:18212 ScriptContext* context,
Devlin Cronin0a240222017-12-01 23:17:51213 std::unique_ptr<ExtensionBindingsSystem> bindings_system) {
lazyboyee4adef2016-05-24 00:55:16214 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
215 if (!data) {
rdevlin.cronin9f338892016-11-21 19:37:00216 ServiceWorkerData* new_data = new ServiceWorkerData(
Devlin Cronin946720eb2017-07-17 23:58:08217 service_worker_version_id, context, std::move(bindings_system));
lazyboyee4adef2016-05-24 00:55:16218 g_data_tls.Pointer()->Set(new_data);
219 }
lazyboy8874f2d2017-05-08 15:07:08220
221 int worker_thread_id = base::PlatformThread::CurrentId();
222 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
223 {
224 base::AutoLock lock(task_runner_map_lock_);
225 auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
226 CHECK(task_runner);
227 task_runner_map_[worker_thread_id] = task_runner;
228 }
lazyboyee4adef2016-05-24 00:55:16229}
230
Istiaque Ahmedd4b67ee2019-03-02 10:53:20231void WorkerThreadDispatcher::DidInitializeContext(
232 int64_t service_worker_version_id) {
233 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
234 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
235 const int thread_id = content::WorkerThread::GetCurrentId();
236 DCHECK_NE(thread_id, kMainThreadId);
237 Send(new ExtensionHostMsg_DidInitializeServiceWorkerContext(
238 data->context()->GetExtensionID(), service_worker_version_id, thread_id));
239}
240
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25241void WorkerThreadDispatcher::DidStartContext(
Istiaque Ahmed4b70a70d2019-02-28 01:36:57242 const GURL& service_worker_scope,
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25243 int64_t service_worker_version_id) {
244 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
245 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
Istiaque Ahmed4b70a70d2019-02-28 01:36:57246 const int thread_id = content::WorkerThread::GetCurrentId();
247 DCHECK_NE(thread_id, kMainThreadId);
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25248 Send(new ExtensionHostMsg_DidStartServiceWorkerContext(
Istiaque Ahmed4b70a70d2019-02-28 01:36:57249 data->context()->GetExtensionID(), service_worker_scope,
250 service_worker_version_id, thread_id));
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25251}
252
Istiaque Ahmed4b70a70d2019-02-28 01:36:57253void WorkerThreadDispatcher::DidStopContext(const GURL& service_worker_scope,
254 int64_t service_worker_version_id) {
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25255 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
Istiaque Ahmed4b70a70d2019-02-28 01:36:57256 const int thread_id = content::WorkerThread::GetCurrentId();
257 DCHECK_NE(thread_id, kMainThreadId);
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25258 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
259 Send(new ExtensionHostMsg_DidStopServiceWorkerContext(
Istiaque Ahmed4b70a70d2019-02-28 01:36:57260 data->context()->GetExtensionID(), service_worker_scope,
261 service_worker_version_id, thread_id));
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25262}
263
lazyboy4c82177a2016-10-18 00:04:09264void WorkerThreadDispatcher::RemoveWorkerData(
265 int64_t service_worker_version_id) {
lazyboyee4adef2016-05-24 00:55:16266 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
267 if (data) {
lazyboy4c82177a2016-10-18 00:04:09268 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
lazyboyee4adef2016-05-24 00:55:16269 delete data;
270 g_data_tls.Pointer()->Set(nullptr);
271 }
lazyboy8874f2d2017-05-08 15:07:08272
273 int worker_thread_id = base::PlatformThread::CurrentId();
274 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
275 {
276 base::AutoLock lock(task_runner_map_lock_);
277 task_runner_map_.erase(worker_thread_id);
278 }
lazyboyee4adef2016-05-24 00:55:16279}
280
281} // namespace extensions