blob: 55698dd573eb8dd6f29f806d4635a9355b82a27f [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
Brett Wilson27e878c2017-09-08 21:32:217#include "base/lazy_instance.h"
fdorayba121422016-12-23 19:51:488#include "base/memory/ptr_util.h"
lazyboy8874f2d2017-05-08 15:07:089#include "base/threading/platform_thread.h"
lazyboyee4adef2016-05-24 00:55:1610#include "base/threading/thread_local.h"
11#include "base/values.h"
12#include "content/public/child/worker_thread.h"
13#include "content/public/renderer/render_thread.h"
lazyboye7847242017-06-07 23:29:1814#include "extensions/common/constants.h"
lazyboyee4adef2016-05-24 00:55:1615#include "extensions/common/extension_messages.h"
rdevlin.cronin71d78789e2016-11-22 19:49:2716#include "extensions/common/feature_switch.h"
lazyboye7847242017-06-07 23:29:1817#include "extensions/renderer/dispatcher.h"
rdevlin.cronin9f338892016-11-21 19:37:0018#include "extensions/renderer/extension_bindings_system.h"
Devlin Cronin4607e322017-07-17 16:17:1819#include "extensions/renderer/ipc_message_sender.h"
rdevlin.cronin9f338892016-11-21 19:37:0020#include "extensions/renderer/js_extension_bindings_system.h"
rdevlin.cronin71d78789e2016-11-22 19:49:2721#include "extensions/renderer/native_extension_bindings_system.h"
lazyboyee4adef2016-05-24 00:55:1622#include "extensions/renderer/service_worker_data.h"
23
24namespace extensions {
25
26namespace {
27
scottmg5e65e3a2017-03-08 08:48:4628base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit g_instance =
lazyboyee4adef2016-05-24 00:55:1629 LAZY_INSTANCE_INITIALIZER;
scottmg5e65e3a2017-03-08 08:48:4630base::LazyInstance<base::ThreadLocalPointer<extensions::ServiceWorkerData>>::
31 DestructorAtExit g_data_tls = LAZY_INSTANCE_INITIALIZER;
lazyboyee4adef2016-05-24 00:55:1632
rdevlin.cronin9f338892016-11-21 19:37:0033ServiceWorkerData* GetServiceWorkerData() {
34 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
35 DCHECK(data);
36 return data;
37}
38
lazyboyee4adef2016-05-24 00:55:1639} // namespace
40
41WorkerThreadDispatcher::WorkerThreadDispatcher() {}
42WorkerThreadDispatcher::~WorkerThreadDispatcher() {}
43
44WorkerThreadDispatcher* WorkerThreadDispatcher::Get() {
45 return g_instance.Pointer();
46}
47
48void WorkerThreadDispatcher::Init(content::RenderThread* render_thread) {
49 DCHECK(render_thread);
50 DCHECK_EQ(content::RenderThread::Get(), render_thread);
51 DCHECK(!message_filter_);
52 message_filter_ = render_thread->GetSyncMessageFilter();
53 render_thread->AddObserver(this);
54}
55
rdevlin.cronin9f338892016-11-21 19:37:0056// static
57ExtensionBindingsSystem* WorkerThreadDispatcher::GetBindingsSystem() {
58 return GetServiceWorkerData()->bindings_system();
lazyboyee4adef2016-05-24 00:55:1659}
60
61// static
rdevlin.cronin9f338892016-11-21 19:37:0062V8SchemaRegistry* WorkerThreadDispatcher::GetV8SchemaRegistry() {
63 return GetServiceWorkerData()->v8_schema_registry();
lazyboyee4adef2016-05-24 00:55:1664}
65
lazyboy8874f2d2017-05-08 15:07:0866// static
Devlin Cronin4f02ff0b2017-07-19 17:46:1067ScriptContext* WorkerThreadDispatcher::GetScriptContext() {
68 return GetServiceWorkerData()->context();
69}
70
71// static
lazyboy8874f2d2017-05-08 15:07:0872bool WorkerThreadDispatcher::HandlesMessageOnWorkerThread(
73 const IPC::Message& message) {
lazyboye7847242017-06-07 23:29:1874 return message.type() == ExtensionMsg_ResponseWorker::ID ||
75 message.type() == ExtensionMsg_DispatchEvent::ID;
lazyboy8874f2d2017-05-08 15:07:0876}
77
78// static
79void WorkerThreadDispatcher::ForwardIPC(int worker_thread_id,
80 const IPC::Message& message) {
81 WorkerThreadDispatcher::Get()->OnMessageReceivedOnWorkerThread(
82 worker_thread_id, message);
83}
84
lazyboyee4adef2016-05-24 00:55:1685bool WorkerThreadDispatcher::OnControlMessageReceived(
86 const IPC::Message& message) {
lazyboy8874f2d2017-05-08 15:07:0887 if (HandlesMessageOnWorkerThread(message)) {
88 int worker_thread_id = base::kInvalidThreadId;
lazyboye7847242017-06-07 23:29:1889 // TODO(lazyboy): Route |message| directly to the child thread using routed
90 // IPC. Probably using mojo?
lazyboy8874f2d2017-05-08 15:07:0891 bool found = base::PickleIterator(message).ReadInt(&worker_thread_id);
lazyboye7847242017-06-07 23:29:1892 CHECK(found);
Istiaque Ahmed461c4ed2017-09-14 17:23:4593 if (worker_thread_id == kMainThreadId)
lazyboye7847242017-06-07 23:29:1894 return false;
lazyboy8874f2d2017-05-08 15:07:0895 base::TaskRunner* runner = GetTaskRunnerFor(worker_thread_id);
96 bool task_posted = runner->PostTask(
97 FROM_HERE, base::Bind(&WorkerThreadDispatcher::ForwardIPC,
98 worker_thread_id, message));
99 DCHECK(task_posted) << "Could not PostTask IPC to worker thread.";
100 return true;
101 }
102 return false;
103}
104
105void WorkerThreadDispatcher::OnMessageReceivedOnWorkerThread(
106 int worker_thread_id,
107 const IPC::Message& message) {
108 CHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
lazyboyee4adef2016-05-24 00:55:16109 bool handled = true;
110 IPC_BEGIN_MESSAGE_MAP(WorkerThreadDispatcher, message)
111 IPC_MESSAGE_HANDLER(ExtensionMsg_ResponseWorker, OnResponseWorker)
lazyboye7847242017-06-07 23:29:18112 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchEvent, OnDispatchEvent)
lazyboyee4adef2016-05-24 00:55:16113 IPC_MESSAGE_UNHANDLED(handled = false)
114 IPC_END_MESSAGE_MAP()
lazyboy8874f2d2017-05-08 15:07:08115 CHECK(handled);
116}
117
118base::TaskRunner* WorkerThreadDispatcher::GetTaskRunnerFor(
119 int worker_thread_id) {
120 base::AutoLock lock(task_runner_map_lock_);
121 return task_runner_map_[worker_thread_id];
lazyboyee4adef2016-05-24 00:55:16122}
123
124bool WorkerThreadDispatcher::Send(IPC::Message* message) {
125 return message_filter_->Send(message);
126}
127
128void WorkerThreadDispatcher::OnResponseWorker(int worker_thread_id,
129 int request_id,
130 bool succeeded,
131 const base::ListValue& response,
132 const std::string& error) {
lazyboy8874f2d2017-05-08 15:07:08133 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
Devlin Cronin4607e322017-07-17 16:17:18134 data->bindings_system()->HandleResponse(request_id, succeeded, response,
135 error);
lazyboyee4adef2016-05-24 00:55:16136}
137
lazyboye7847242017-06-07 23:29:18138void WorkerThreadDispatcher::OnDispatchEvent(
139 const ExtensionMsg_DispatchEvent_Params& params,
140 const base::ListValue& event_args) {
141 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
142 DCHECK(data);
143 data->bindings_system()->DispatchEventInContext(
144 params.event_name, &event_args, &params.filtering_info, data->context());
145}
146
rdevlin.cronin9f338892016-11-21 19:37:00147void WorkerThreadDispatcher::AddWorkerData(
148 int64_t service_worker_version_id,
lazyboye7847242017-06-07 23:29:18149 ScriptContext* context,
rdevlin.cronin9f338892016-11-21 19:37:00150 ResourceBundleSourceMap* source_map) {
lazyboyee4adef2016-05-24 00:55:16151 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
152 if (!data) {
rdevlin.cronin71d78789e2016-11-22 19:49:27153 std::unique_ptr<ExtensionBindingsSystem> bindings_system;
Devlin Cronin4607e322017-07-17 16:17:18154 // QUESTION(lazyboy): Why is passing the WorkerThreadDispatcher to the
155 // IPCMessageSender (previously the ServiceWorkerRequestSender) safe? The
156 // WorkerThreadDispatcher is a process-wide singleton, but the
157 // IPCMessageSender is per-context (thus potentially many per process).
158 std::unique_ptr<IPCMessageSender> ipc_message_sender =
159 IPCMessageSender::CreateWorkerThreadIPCMessageSender(
160 this, service_worker_version_id);
rdevlin.cronin71d78789e2016-11-22 19:49:27161 if (FeatureSwitch::native_crx_bindings()->IsEnabled()) {
Devlin Cronin4607e322017-07-17 16:17:18162 // The Unretained below is safe since the IPC message sender outlives the
163 // bindings system.
Jeremy Roman16529d0e2017-08-24 18:13:47164 bindings_system = std::make_unique<NativeExtensionBindingsSystem>(
Devlin Cronin2b2180c2017-07-19 00:04:01165 std::move(ipc_message_sender));
rdevlin.cronin71d78789e2016-11-22 19:49:27166 } else {
Jeremy Roman16529d0e2017-08-24 18:13:47167 bindings_system = std::make_unique<JsExtensionBindingsSystem>(
Devlin Cronin946720eb2017-07-17 23:58:08168 source_map, std::move(ipc_message_sender));
rdevlin.cronin71d78789e2016-11-22 19:49:27169 }
rdevlin.cronin9f338892016-11-21 19:37:00170 ServiceWorkerData* new_data = new ServiceWorkerData(
Devlin Cronin946720eb2017-07-17 23:58:08171 service_worker_version_id, context, std::move(bindings_system));
lazyboyee4adef2016-05-24 00:55:16172 g_data_tls.Pointer()->Set(new_data);
173 }
lazyboy8874f2d2017-05-08 15:07:08174
175 int worker_thread_id = base::PlatformThread::CurrentId();
176 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
177 {
178 base::AutoLock lock(task_runner_map_lock_);
179 auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
180 CHECK(task_runner);
181 task_runner_map_[worker_thread_id] = task_runner;
182 }
lazyboyee4adef2016-05-24 00:55:16183}
184
lazyboy4c82177a2016-10-18 00:04:09185void WorkerThreadDispatcher::RemoveWorkerData(
186 int64_t service_worker_version_id) {
lazyboyee4adef2016-05-24 00:55:16187 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
188 if (data) {
lazyboy4c82177a2016-10-18 00:04:09189 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
lazyboyee4adef2016-05-24 00:55:16190 delete data;
191 g_data_tls.Pointer()->Set(nullptr);
192 }
lazyboy8874f2d2017-05-08 15:07:08193
194 int worker_thread_id = base::PlatformThread::CurrentId();
195 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
196 {
197 base::AutoLock lock(task_runner_map_lock_);
198 task_runner_map_.erase(worker_thread_id);
199 }
lazyboyee4adef2016-05-24 00:55:16200}
201
202} // namespace extensions