blob: 47b79e0f90fc00afb1dc9df3cd9c240a66bf2f7b [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"
Devlin Cronin0a240222017-12-01 23:17:5121#include "extensions/renderer/extensions_renderer_client.h"
Devlin Cronin095dc132019-03-29 19:43:3022#include "extensions/renderer/native_extension_bindings_system.h"
Devlin Cronin613ebffa2019-04-17 21:04:1723#include "extensions/renderer/native_renderer_messaging_service.h"
lazyboyee4adef2016-05-24 00:55:1624#include "extensions/renderer/service_worker_data.h"
Istiaque Ahmedee72f4952019-03-06 21:18:3625#include "extensions/renderer/worker_script_context_set.h"
lazyboyee4adef2016-05-24 00:55:1626
27namespace extensions {
28
29namespace {
30
Jens Widellc71ec40a2018-01-04 09:55:1731base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit
32 g_worker_thread_dispatcher_instance = LAZY_INSTANCE_INITIALIZER;
scottmg5e65e3a2017-03-08 08:48:4633base::LazyInstance<base::ThreadLocalPointer<extensions::ServiceWorkerData>>::
34 DestructorAtExit g_data_tls = LAZY_INSTANCE_INITIALIZER;
lazyboyee4adef2016-05-24 00:55:1635
rdevlin.cronin9f338892016-11-21 19:37:0036ServiceWorkerData* GetServiceWorkerData() {
37 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
38 DCHECK(data);
39 return data;
40}
41
lazyboyee4adef2016-05-24 00:55:1642} // namespace
43
44WorkerThreadDispatcher::WorkerThreadDispatcher() {}
45WorkerThreadDispatcher::~WorkerThreadDispatcher() {}
46
47WorkerThreadDispatcher* WorkerThreadDispatcher::Get() {
Jens Widellc71ec40a2018-01-04 09:55:1748 return g_worker_thread_dispatcher_instance.Pointer();
lazyboyee4adef2016-05-24 00:55:1649}
50
51void WorkerThreadDispatcher::Init(content::RenderThread* render_thread) {
52 DCHECK(render_thread);
53 DCHECK_EQ(content::RenderThread::Get(), render_thread);
54 DCHECK(!message_filter_);
55 message_filter_ = render_thread->GetSyncMessageFilter();
56 render_thread->AddObserver(this);
57}
58
rdevlin.cronin9f338892016-11-21 19:37:0059// static
Devlin Cronin095dc132019-03-29 19:43:3060NativeExtensionBindingsSystem* WorkerThreadDispatcher::GetBindingsSystem() {
rdevlin.cronin9f338892016-11-21 19:37:0061 return GetServiceWorkerData()->bindings_system();
lazyboyee4adef2016-05-24 00:55:1662}
63
64// static
rdevlin.cronin9f338892016-11-21 19:37:0065V8SchemaRegistry* WorkerThreadDispatcher::GetV8SchemaRegistry() {
66 return GetServiceWorkerData()->v8_schema_registry();
lazyboyee4adef2016-05-24 00:55:1667}
68
lazyboy8874f2d2017-05-08 15:07:0869// static
Devlin Cronin4f02ff0b2017-07-19 17:46:1070ScriptContext* WorkerThreadDispatcher::GetScriptContext() {
71 return GetServiceWorkerData()->context();
72}
73
74// static
lazyboy8874f2d2017-05-08 15:07:0875bool WorkerThreadDispatcher::HandlesMessageOnWorkerThread(
76 const IPC::Message& message) {
lazyboye7847242017-06-07 23:29:1877 return message.type() == ExtensionMsg_ResponseWorker::ID ||
Istiaque Ahmedee72f4952019-03-06 21:18:3678 message.type() == ExtensionMsg_DispatchEvent::ID ||
79 message.type() == ExtensionMsg_DispatchOnConnect::ID ||
80 message.type() == ExtensionMsg_DeliverMessage::ID ||
81 message.type() == ExtensionMsg_DispatchOnDisconnect::ID ||
82 message.type() == ExtensionMsg_ValidateMessagePort::ID;
lazyboy8874f2d2017-05-08 15:07:0883}
84
85// static
86void WorkerThreadDispatcher::ForwardIPC(int worker_thread_id,
87 const IPC::Message& message) {
88 WorkerThreadDispatcher::Get()->OnMessageReceivedOnWorkerThread(
89 worker_thread_id, message);
90}
91
lazyboyee4adef2016-05-24 00:55:1692bool WorkerThreadDispatcher::OnControlMessageReceived(
93 const IPC::Message& message) {
lazyboy8874f2d2017-05-08 15:07:0894 if (HandlesMessageOnWorkerThread(message)) {
95 int worker_thread_id = base::kInvalidThreadId;
lazyboye7847242017-06-07 23:29:1896 // TODO(lazyboy): Route |message| directly to the child thread using routed
97 // IPC. Probably using mojo?
lazyboy8874f2d2017-05-08 15:07:0898 bool found = base::PickleIterator(message).ReadInt(&worker_thread_id);
lazyboye7847242017-06-07 23:29:1899 CHECK(found);
Istiaque Ahmed461c4ed2017-09-14 17:23:45100 if (worker_thread_id == kMainThreadId)
lazyboye7847242017-06-07 23:29:18101 return false;
lazyboy8874f2d2017-05-08 15:07:08102 base::TaskRunner* runner = GetTaskRunnerFor(worker_thread_id);
103 bool task_posted = runner->PostTask(
kylechar0686a5232019-02-19 14:10:29104 FROM_HERE, base::BindOnce(&WorkerThreadDispatcher::ForwardIPC,
105 worker_thread_id, message));
lazyboy8874f2d2017-05-08 15:07:08106 DCHECK(task_posted) << "Could not PostTask IPC to worker thread.";
107 return true;
108 }
109 return false;
110}
111
112void WorkerThreadDispatcher::OnMessageReceivedOnWorkerThread(
113 int worker_thread_id,
114 const IPC::Message& message) {
115 CHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
lazyboyee4adef2016-05-24 00:55:16116 bool handled = true;
117 IPC_BEGIN_MESSAGE_MAP(WorkerThreadDispatcher, message)
118 IPC_MESSAGE_HANDLER(ExtensionMsg_ResponseWorker, OnResponseWorker)
lazyboye7847242017-06-07 23:29:18119 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchEvent, OnDispatchEvent)
Istiaque Ahmedee72f4952019-03-06 21:18:36120 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect)
121 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage)
122 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
123 OnDispatchOnDisconnect)
124 IPC_MESSAGE_HANDLER(ExtensionMsg_ValidateMessagePort, OnValidateMessagePort)
lazyboyee4adef2016-05-24 00:55:16125 IPC_MESSAGE_UNHANDLED(handled = false)
126 IPC_END_MESSAGE_MAP()
lazyboy8874f2d2017-05-08 15:07:08127 CHECK(handled);
128}
129
130base::TaskRunner* WorkerThreadDispatcher::GetTaskRunnerFor(
131 int worker_thread_id) {
132 base::AutoLock lock(task_runner_map_lock_);
133 return task_runner_map_[worker_thread_id];
lazyboyee4adef2016-05-24 00:55:16134}
135
136bool WorkerThreadDispatcher::Send(IPC::Message* message) {
137 return message_filter_->Send(message);
138}
139
140void WorkerThreadDispatcher::OnResponseWorker(int worker_thread_id,
141 int request_id,
142 bool succeeded,
143 const base::ListValue& response,
144 const std::string& error) {
lazyboy8874f2d2017-05-08 15:07:08145 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
Devlin Cronin4607e322017-07-17 16:17:18146 data->bindings_system()->HandleResponse(request_id, succeeded, response,
147 error);
lazyboyee4adef2016-05-24 00:55:16148}
149
lazyboye7847242017-06-07 23:29:18150void WorkerThreadDispatcher::OnDispatchEvent(
151 const ExtensionMsg_DispatchEvent_Params& params,
152 const base::ListValue& event_args) {
153 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
154 DCHECK(data);
155 data->bindings_system()->DispatchEventInContext(
156 params.event_name, &event_args, &params.filtering_info, data->context());
Istiaque Ahmeda14ec482018-08-25 01:02:18157 Send(new ExtensionHostMsg_EventAckWorker(data->service_worker_version_id(),
158 params.event_id));
lazyboye7847242017-06-07 23:29:18159}
160
Istiaque Ahmedee72f4952019-03-06 21:18:36161void WorkerThreadDispatcher::OnDispatchOnConnect(
162 int worker_thread_id,
163 const PortId& target_port_id,
164 const std::string& channel_name,
165 const ExtensionMsg_TabConnectionInfo& source,
166 const ExtensionMsg_ExternalConnectionInfo& info) {
167 DCHECK_EQ(worker_thread_id, content::WorkerThread::GetCurrentId());
168 WorkerThreadDispatcher::GetBindingsSystem()
Devlin Cronin613ebffa2019-04-17 21:04:17169 ->messaging_service()
Istiaque Ahmedee72f4952019-03-06 21:18:36170 ->DispatchOnConnect(Dispatcher::GetWorkerScriptContextSet(),
171 target_port_id, channel_name, source, info,
172 // Render frames do not matter.
173 nullptr);
174}
175
176void WorkerThreadDispatcher::OnValidateMessagePort(int worker_thread_id,
177 const PortId& id) {
178 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
179 WorkerThreadDispatcher::GetBindingsSystem()
Devlin Cronin613ebffa2019-04-17 21:04:17180 ->messaging_service()
Istiaque Ahmedee72f4952019-03-06 21:18:36181 ->ValidateMessagePort(Dispatcher::GetWorkerScriptContextSet(), id,
182 // Render frames do not matter.
183 nullptr);
184}
185
186void WorkerThreadDispatcher::OnDeliverMessage(int worker_thread_id,
187 const PortId& target_port_id,
188 const Message& message) {
189 WorkerThreadDispatcher::GetBindingsSystem()
Devlin Cronin613ebffa2019-04-17 21:04:17190 ->messaging_service()
Istiaque Ahmedee72f4952019-03-06 21:18:36191 ->DeliverMessage(Dispatcher::GetWorkerScriptContextSet(), target_port_id,
192 message,
193 // Render frames do not matter.
194 nullptr);
195}
196
197void WorkerThreadDispatcher::OnDispatchOnDisconnect(
198 int worker_thread_id,
199 const PortId& port_id,
200 const std::string& error_message) {
201 WorkerThreadDispatcher::GetBindingsSystem()
Devlin Cronin613ebffa2019-04-17 21:04:17202 ->messaging_service()
Istiaque Ahmedee72f4952019-03-06 21:18:36203 ->DispatchOnDisconnect(Dispatcher::GetWorkerScriptContextSet(), port_id,
204 error_message,
205 // Render frames do not matter.
206 nullptr);
207}
208
rdevlin.cronin9f338892016-11-21 19:37:00209void WorkerThreadDispatcher::AddWorkerData(
210 int64_t service_worker_version_id,
lazyboye7847242017-06-07 23:29:18211 ScriptContext* context,
Devlin Cronin095dc132019-03-29 19:43:30212 std::unique_ptr<NativeExtensionBindingsSystem> bindings_system) {
lazyboyee4adef2016-05-24 00:55:16213 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
214 if (!data) {
rdevlin.cronin9f338892016-11-21 19:37:00215 ServiceWorkerData* new_data = new ServiceWorkerData(
Devlin Cronin946720eb2017-07-17 23:58:08216 service_worker_version_id, context, std::move(bindings_system));
lazyboyee4adef2016-05-24 00:55:16217 g_data_tls.Pointer()->Set(new_data);
218 }
lazyboy8874f2d2017-05-08 15:07:08219
220 int worker_thread_id = base::PlatformThread::CurrentId();
221 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
222 {
223 base::AutoLock lock(task_runner_map_lock_);
224 auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
225 CHECK(task_runner);
226 task_runner_map_[worker_thread_id] = task_runner;
227 }
lazyboyee4adef2016-05-24 00:55:16228}
229
Istiaque Ahmedd4b67ee2019-03-02 10:53:20230void WorkerThreadDispatcher::DidInitializeContext(
231 int64_t service_worker_version_id) {
232 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
233 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
234 const int thread_id = content::WorkerThread::GetCurrentId();
235 DCHECK_NE(thread_id, kMainThreadId);
236 Send(new ExtensionHostMsg_DidInitializeServiceWorkerContext(
237 data->context()->GetExtensionID(), service_worker_version_id, thread_id));
238}
239
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25240void WorkerThreadDispatcher::DidStartContext(
Istiaque Ahmed4b70a70d2019-02-28 01:36:57241 const GURL& service_worker_scope,
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25242 int64_t service_worker_version_id) {
243 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
244 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
Istiaque Ahmed4b70a70d2019-02-28 01:36:57245 const int thread_id = content::WorkerThread::GetCurrentId();
246 DCHECK_NE(thread_id, kMainThreadId);
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25247 Send(new ExtensionHostMsg_DidStartServiceWorkerContext(
Istiaque Ahmed4b70a70d2019-02-28 01:36:57248 data->context()->GetExtensionID(), service_worker_scope,
249 service_worker_version_id, thread_id));
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25250}
251
Istiaque Ahmed4b70a70d2019-02-28 01:36:57252void WorkerThreadDispatcher::DidStopContext(const GURL& service_worker_scope,
253 int64_t service_worker_version_id) {
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25254 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
Istiaque Ahmed4b70a70d2019-02-28 01:36:57255 const int thread_id = content::WorkerThread::GetCurrentId();
256 DCHECK_NE(thread_id, kMainThreadId);
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25257 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
258 Send(new ExtensionHostMsg_DidStopServiceWorkerContext(
Istiaque Ahmed4b70a70d2019-02-28 01:36:57259 data->context()->GetExtensionID(), service_worker_scope,
260 service_worker_version_id, thread_id));
Istiaque Ahmedb8e24bdb2018-09-13 15:17:25261}
262
lazyboy4c82177a2016-10-18 00:04:09263void WorkerThreadDispatcher::RemoveWorkerData(
264 int64_t service_worker_version_id) {
lazyboyee4adef2016-05-24 00:55:16265 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
266 if (data) {
lazyboy4c82177a2016-10-18 00:04:09267 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
lazyboyee4adef2016-05-24 00:55:16268 delete data;
269 g_data_tls.Pointer()->Set(nullptr);
270 }
lazyboy8874f2d2017-05-08 15:07:08271
272 int worker_thread_id = base::PlatformThread::CurrentId();
273 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
274 {
275 base::AutoLock lock(task_runner_map_lock_);
276 task_runner_map_.erase(worker_thread_id);
277 }
lazyboyee4adef2016-05-24 00:55:16278}
279
280} // namespace extensions