blob: 2949a158811cf973fdce08b0937dc50a0550c096 [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
fdorayba121422016-12-23 19:51:487#include "base/memory/ptr_util.h"
lazyboy8874f2d2017-05-08 15:07:088#include "base/threading/platform_thread.h"
lazyboyee4adef2016-05-24 00:55:169#include "base/threading/thread_local.h"
10#include "base/values.h"
11#include "content/public/child/worker_thread.h"
12#include "content/public/renderer/render_thread.h"
lazyboye7847242017-06-07 23:29:1813#include "extensions/common/constants.h"
lazyboyee4adef2016-05-24 00:55:1614#include "extensions/common/extension_messages.h"
rdevlin.cronin71d78789e2016-11-22 19:49:2715#include "extensions/common/feature_switch.h"
lazyboye7847242017-06-07 23:29:1816#include "extensions/renderer/dispatcher.h"
rdevlin.cronin9f338892016-11-21 19:37:0017#include "extensions/renderer/extension_bindings_system.h"
Devlin Cronin4607e322017-07-17 16:17:1818#include "extensions/renderer/ipc_message_sender.h"
rdevlin.cronin9f338892016-11-21 19:37:0019#include "extensions/renderer/js_extension_bindings_system.h"
rdevlin.cronin71d78789e2016-11-22 19:49:2720#include "extensions/renderer/native_extension_bindings_system.h"
lazyboyee4adef2016-05-24 00:55:1621#include "extensions/renderer/service_worker_data.h"
22
23namespace extensions {
24
25namespace {
26
scottmg5e65e3a2017-03-08 08:48:4627base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit g_instance =
lazyboyee4adef2016-05-24 00:55:1628 LAZY_INSTANCE_INITIALIZER;
scottmg5e65e3a2017-03-08 08:48:4629base::LazyInstance<base::ThreadLocalPointer<extensions::ServiceWorkerData>>::
30 DestructorAtExit g_data_tls = LAZY_INSTANCE_INITIALIZER;
lazyboyee4adef2016-05-24 00:55:1631
rdevlin.cronin9f338892016-11-21 19:37:0032ServiceWorkerData* GetServiceWorkerData() {
33 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
34 DCHECK(data);
35 return data;
36}
37
lazyboyee4adef2016-05-24 00:55:1638} // namespace
39
40WorkerThreadDispatcher::WorkerThreadDispatcher() {}
41WorkerThreadDispatcher::~WorkerThreadDispatcher() {}
42
43WorkerThreadDispatcher* WorkerThreadDispatcher::Get() {
44 return g_instance.Pointer();
45}
46
47void WorkerThreadDispatcher::Init(content::RenderThread* render_thread) {
48 DCHECK(render_thread);
49 DCHECK_EQ(content::RenderThread::Get(), render_thread);
50 DCHECK(!message_filter_);
51 message_filter_ = render_thread->GetSyncMessageFilter();
52 render_thread->AddObserver(this);
53}
54
rdevlin.cronin9f338892016-11-21 19:37:0055// static
56ExtensionBindingsSystem* WorkerThreadDispatcher::GetBindingsSystem() {
57 return GetServiceWorkerData()->bindings_system();
lazyboyee4adef2016-05-24 00:55:1658}
59
60// static
rdevlin.cronin9f338892016-11-21 19:37:0061V8SchemaRegistry* WorkerThreadDispatcher::GetV8SchemaRegistry() {
62 return GetServiceWorkerData()->v8_schema_registry();
lazyboyee4adef2016-05-24 00:55:1663}
64
lazyboy8874f2d2017-05-08 15:07:0865// static
Devlin Cronin4f02ff0b2017-07-19 17:46:1066ScriptContext* WorkerThreadDispatcher::GetScriptContext() {
67 return GetServiceWorkerData()->context();
68}
69
70// static
lazyboy8874f2d2017-05-08 15:07:0871bool WorkerThreadDispatcher::HandlesMessageOnWorkerThread(
72 const IPC::Message& message) {
lazyboye7847242017-06-07 23:29:1873 return message.type() == ExtensionMsg_ResponseWorker::ID ||
74 message.type() == ExtensionMsg_DispatchEvent::ID;
lazyboy8874f2d2017-05-08 15:07:0875}
76
77// static
78void WorkerThreadDispatcher::ForwardIPC(int worker_thread_id,
79 const IPC::Message& message) {
80 WorkerThreadDispatcher::Get()->OnMessageReceivedOnWorkerThread(
81 worker_thread_id, message);
82}
83
lazyboyee4adef2016-05-24 00:55:1684bool WorkerThreadDispatcher::OnControlMessageReceived(
85 const IPC::Message& message) {
lazyboy8874f2d2017-05-08 15:07:0886 if (HandlesMessageOnWorkerThread(message)) {
87 int worker_thread_id = base::kInvalidThreadId;
lazyboye7847242017-06-07 23:29:1888 // TODO(lazyboy): Route |message| directly to the child thread using routed
89 // IPC. Probably using mojo?
lazyboy8874f2d2017-05-08 15:07:0890 bool found = base::PickleIterator(message).ReadInt(&worker_thread_id);
lazyboye7847242017-06-07 23:29:1891 CHECK(found);
92 if (worker_thread_id == kNonWorkerThreadId)
93 return false;
lazyboy8874f2d2017-05-08 15:07:0894 base::TaskRunner* runner = GetTaskRunnerFor(worker_thread_id);
95 bool task_posted = runner->PostTask(
96 FROM_HERE, base::Bind(&WorkerThreadDispatcher::ForwardIPC,
97 worker_thread_id, message));
98 DCHECK(task_posted) << "Could not PostTask IPC to worker thread.";
99 return true;
100 }
101 return false;
102}
103
104void WorkerThreadDispatcher::OnMessageReceivedOnWorkerThread(
105 int worker_thread_id,
106 const IPC::Message& message) {
107 CHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
lazyboyee4adef2016-05-24 00:55:16108 bool handled = true;
109 IPC_BEGIN_MESSAGE_MAP(WorkerThreadDispatcher, message)
110 IPC_MESSAGE_HANDLER(ExtensionMsg_ResponseWorker, OnResponseWorker)
lazyboye7847242017-06-07 23:29:18111 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchEvent, OnDispatchEvent)
lazyboyee4adef2016-05-24 00:55:16112 IPC_MESSAGE_UNHANDLED(handled = false)
113 IPC_END_MESSAGE_MAP()
lazyboy8874f2d2017-05-08 15:07:08114 CHECK(handled);
115}
116
117base::TaskRunner* WorkerThreadDispatcher::GetTaskRunnerFor(
118 int worker_thread_id) {
119 base::AutoLock lock(task_runner_map_lock_);
120 return task_runner_map_[worker_thread_id];
lazyboyee4adef2016-05-24 00:55:16121}
122
123bool WorkerThreadDispatcher::Send(IPC::Message* message) {
124 return message_filter_->Send(message);
125}
126
127void WorkerThreadDispatcher::OnResponseWorker(int worker_thread_id,
128 int request_id,
129 bool succeeded,
130 const base::ListValue& response,
131 const std::string& error) {
lazyboy8874f2d2017-05-08 15:07:08132 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
Devlin Cronin4607e322017-07-17 16:17:18133 data->bindings_system()->HandleResponse(request_id, succeeded, response,
134 error);
lazyboyee4adef2016-05-24 00:55:16135}
136
lazyboye7847242017-06-07 23:29:18137void WorkerThreadDispatcher::OnDispatchEvent(
138 const ExtensionMsg_DispatchEvent_Params& params,
139 const base::ListValue& event_args) {
140 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
141 DCHECK(data);
142 data->bindings_system()->DispatchEventInContext(
143 params.event_name, &event_args, &params.filtering_info, data->context());
144}
145
rdevlin.cronin9f338892016-11-21 19:37:00146void WorkerThreadDispatcher::AddWorkerData(
147 int64_t service_worker_version_id,
lazyboye7847242017-06-07 23:29:18148 ScriptContext* context,
rdevlin.cronin9f338892016-11-21 19:37:00149 ResourceBundleSourceMap* source_map) {
lazyboyee4adef2016-05-24 00:55:16150 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
151 if (!data) {
rdevlin.cronin71d78789e2016-11-22 19:49:27152 std::unique_ptr<ExtensionBindingsSystem> bindings_system;
Devlin Cronin4607e322017-07-17 16:17:18153 // QUESTION(lazyboy): Why is passing the WorkerThreadDispatcher to the
154 // IPCMessageSender (previously the ServiceWorkerRequestSender) safe? The
155 // WorkerThreadDispatcher is a process-wide singleton, but the
156 // IPCMessageSender is per-context (thus potentially many per process).
157 std::unique_ptr<IPCMessageSender> ipc_message_sender =
158 IPCMessageSender::CreateWorkerThreadIPCMessageSender(
159 this, service_worker_version_id);
rdevlin.cronin71d78789e2016-11-22 19:49:27160 if (FeatureSwitch::native_crx_bindings()->IsEnabled()) {
Devlin Cronin4607e322017-07-17 16:17:18161 // The Unretained below is safe since the IPC message sender outlives the
162 // bindings system.
Jeremy Roman16529d0e2017-08-24 18:13:47163 bindings_system = std::make_unique<NativeExtensionBindingsSystem>(
Devlin Cronin2b2180c2017-07-19 00:04:01164 std::move(ipc_message_sender));
rdevlin.cronin71d78789e2016-11-22 19:49:27165 } else {
Jeremy Roman16529d0e2017-08-24 18:13:47166 bindings_system = std::make_unique<JsExtensionBindingsSystem>(
Devlin Cronin946720eb2017-07-17 23:58:08167 source_map, std::move(ipc_message_sender));
rdevlin.cronin71d78789e2016-11-22 19:49:27168 }
rdevlin.cronin9f338892016-11-21 19:37:00169 ServiceWorkerData* new_data = new ServiceWorkerData(
Devlin Cronin946720eb2017-07-17 23:58:08170 service_worker_version_id, context, std::move(bindings_system));
lazyboyee4adef2016-05-24 00:55:16171 g_data_tls.Pointer()->Set(new_data);
172 }
lazyboy8874f2d2017-05-08 15:07:08173
174 int worker_thread_id = base::PlatformThread::CurrentId();
175 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
176 {
177 base::AutoLock lock(task_runner_map_lock_);
178 auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
179 CHECK(task_runner);
180 task_runner_map_[worker_thread_id] = task_runner;
181 }
lazyboyee4adef2016-05-24 00:55:16182}
183
lazyboy4c82177a2016-10-18 00:04:09184void WorkerThreadDispatcher::RemoveWorkerData(
185 int64_t service_worker_version_id) {
lazyboyee4adef2016-05-24 00:55:16186 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
187 if (data) {
lazyboy4c82177a2016-10-18 00:04:09188 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
lazyboyee4adef2016-05-24 00:55:16189 delete data;
190 g_data_tls.Pointer()->Set(nullptr);
191 }
lazyboy8874f2d2017-05-08 15:07:08192
193 int worker_thread_id = base::PlatformThread::CurrentId();
194 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
195 {
196 base::AutoLock lock(task_runner_map_lock_);
197 task_runner_map_.erase(worker_thread_id);
198 }
lazyboyee4adef2016-05-24 00:55:16199}
200
201} // namespace extensions