blob: f338575218530f920d8bd0acc06c3db8409cf07c [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"
13#include "extensions/common/extension_messages.h"
rdevlin.cronin71d78789e2016-11-22 19:49:2714#include "extensions/common/feature_switch.h"
rdevlin.cronin9f338892016-11-21 19:37:0015#include "extensions/renderer/extension_bindings_system.h"
16#include "extensions/renderer/js_extension_bindings_system.h"
rdevlin.cronin71d78789e2016-11-22 19:49:2717#include "extensions/renderer/native_extension_bindings_system.h"
lazyboyee4adef2016-05-24 00:55:1618#include "extensions/renderer/service_worker_data.h"
19
20namespace extensions {
21
22namespace {
23
scottmg5e65e3a2017-03-08 08:48:4624base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit g_instance =
lazyboyee4adef2016-05-24 00:55:1625 LAZY_INSTANCE_INITIALIZER;
scottmg5e65e3a2017-03-08 08:48:4626base::LazyInstance<base::ThreadLocalPointer<extensions::ServiceWorkerData>>::
27 DestructorAtExit g_data_tls = LAZY_INSTANCE_INITIALIZER;
lazyboyee4adef2016-05-24 00:55:1628
rdevlin.cronin9f338892016-11-21 19:37:0029ServiceWorkerData* GetServiceWorkerData() {
30 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
31 DCHECK(data);
32 return data;
33}
34
rdevlin.cronin71d78789e2016-11-22 19:49:2735// Handler for sending IPCs with native extension bindings.
36void SendRequestIPC(ScriptContext* context,
rdevlin.cronin0e622d522017-03-31 01:19:0037 const ExtensionHostMsg_Request_Params& params,
38 binding::RequestThread thread) {
rdevlin.cronin71d78789e2016-11-22 19:49:2739 // TODO(devlin): This won't handle incrementing/decrementing service worker
40 // lifetime.
41 WorkerThreadDispatcher::Get()->Send(
42 new ExtensionHostMsg_RequestWorker(params));
43}
44
rdevlin.croninea496fd2017-01-13 18:22:1445void SendEventListenersIPC(binding::EventListenersChanged changed,
46 ScriptContext* context,
rdevlin.croninddc50bcb2017-03-23 00:55:5247 const std::string& event_name,
rdevlin.cronin707b7322017-03-30 20:56:2648 const base::DictionaryValue* filter,
49 bool was_manual) {
rdevlin.croninea496fd2017-01-13 18:22:1450 // TODO(devlin/lazyboy): Wire this up once extension workers support events.
51}
52
lazyboyee4adef2016-05-24 00:55:1653} // namespace
54
55WorkerThreadDispatcher::WorkerThreadDispatcher() {}
56WorkerThreadDispatcher::~WorkerThreadDispatcher() {}
57
58WorkerThreadDispatcher* WorkerThreadDispatcher::Get() {
59 return g_instance.Pointer();
60}
61
62void WorkerThreadDispatcher::Init(content::RenderThread* render_thread) {
63 DCHECK(render_thread);
64 DCHECK_EQ(content::RenderThread::Get(), render_thread);
65 DCHECK(!message_filter_);
66 message_filter_ = render_thread->GetSyncMessageFilter();
67 render_thread->AddObserver(this);
68}
69
rdevlin.cronin9f338892016-11-21 19:37:0070// static
71ExtensionBindingsSystem* WorkerThreadDispatcher::GetBindingsSystem() {
72 return GetServiceWorkerData()->bindings_system();
lazyboyee4adef2016-05-24 00:55:1673}
74
75// static
lazyboy4c82177a2016-10-18 00:04:0976ServiceWorkerRequestSender* WorkerThreadDispatcher::GetRequestSender() {
rdevlin.cronin9f338892016-11-21 19:37:0077 return static_cast<ServiceWorkerRequestSender*>(
78 GetBindingsSystem()->GetRequestSender());
79}
80
81// static
82V8SchemaRegistry* WorkerThreadDispatcher::GetV8SchemaRegistry() {
83 return GetServiceWorkerData()->v8_schema_registry();
lazyboyee4adef2016-05-24 00:55:1684}
85
lazyboy8874f2d2017-05-08 15:07:0886// static
87bool WorkerThreadDispatcher::HandlesMessageOnWorkerThread(
88 const IPC::Message& message) {
89 return message.type() == ExtensionMsg_ResponseWorker::ID;
90}
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
lazyboyee4adef2016-05-24 00:55:1699bool WorkerThreadDispatcher::OnControlMessageReceived(
100 const IPC::Message& message) {
lazyboy8874f2d2017-05-08 15:07:08101 if (HandlesMessageOnWorkerThread(message)) {
102 int worker_thread_id = base::kInvalidThreadId;
103 bool found = base::PickleIterator(message).ReadInt(&worker_thread_id);
104 CHECK(found && worker_thread_id > 0);
105 base::TaskRunner* runner = GetTaskRunnerFor(worker_thread_id);
106 bool task_posted = runner->PostTask(
107 FROM_HERE, base::Bind(&WorkerThreadDispatcher::ForwardIPC,
108 worker_thread_id, message));
109 DCHECK(task_posted) << "Could not PostTask IPC to worker thread.";
110 return true;
111 }
112 return false;
113}
114
115void WorkerThreadDispatcher::OnMessageReceivedOnWorkerThread(
116 int worker_thread_id,
117 const IPC::Message& message) {
118 CHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
lazyboyee4adef2016-05-24 00:55:16119 bool handled = true;
120 IPC_BEGIN_MESSAGE_MAP(WorkerThreadDispatcher, message)
121 IPC_MESSAGE_HANDLER(ExtensionMsg_ResponseWorker, OnResponseWorker)
122 IPC_MESSAGE_UNHANDLED(handled = false)
123 IPC_END_MESSAGE_MAP()
lazyboy8874f2d2017-05-08 15:07:08124 CHECK(handled);
125}
126
127base::TaskRunner* WorkerThreadDispatcher::GetTaskRunnerFor(
128 int worker_thread_id) {
129 base::AutoLock lock(task_runner_map_lock_);
130 return task_runner_map_[worker_thread_id];
lazyboyee4adef2016-05-24 00:55:16131}
132
133bool WorkerThreadDispatcher::Send(IPC::Message* message) {
134 return message_filter_->Send(message);
135}
136
137void WorkerThreadDispatcher::OnResponseWorker(int worker_thread_id,
138 int request_id,
139 bool succeeded,
140 const base::ListValue& response,
141 const std::string& error) {
lazyboy8874f2d2017-05-08 15:07:08142 // TODO(devlin): Using the RequestSender directly here won't work with
143 // NativeExtensionBindingsSystem (since there is no associated RequestSender
144 // in that case). We should instead be going
145 // ExtensionBindingsSystem::HandleResponse().
146 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
147 WorkerThreadDispatcher::GetRequestSender()->HandleWorkerResponse(
148 request_id, data->service_worker_version_id(), succeeded, response,
149 error);
lazyboyee4adef2016-05-24 00:55:16150}
151
rdevlin.cronin9f338892016-11-21 19:37:00152void WorkerThreadDispatcher::AddWorkerData(
153 int64_t service_worker_version_id,
154 ResourceBundleSourceMap* source_map) {
lazyboyee4adef2016-05-24 00:55:16155 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
156 if (!data) {
rdevlin.cronin71d78789e2016-11-22 19:49:27157 std::unique_ptr<ExtensionBindingsSystem> bindings_system;
158 if (FeatureSwitch::native_crx_bindings()->IsEnabled()) {
159 bindings_system = base::MakeUnique<NativeExtensionBindingsSystem>(
rdevlin.croninea496fd2017-01-13 18:22:14160 base::Bind(&SendRequestIPC), base::Bind(&SendEventListenersIPC));
rdevlin.cronin71d78789e2016-11-22 19:49:27161 } else {
162 bindings_system = base::MakeUnique<JsExtensionBindingsSystem>(
163 source_map, base::MakeUnique<ServiceWorkerRequestSender>(
164 this, service_worker_version_id));
165 }
rdevlin.cronin9f338892016-11-21 19:37:00166 ServiceWorkerData* new_data = new ServiceWorkerData(
167 service_worker_version_id, std::move(bindings_system));
lazyboyee4adef2016-05-24 00:55:16168 g_data_tls.Pointer()->Set(new_data);
169 }
lazyboy8874f2d2017-05-08 15:07:08170
171 int worker_thread_id = base::PlatformThread::CurrentId();
172 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
173 {
174 base::AutoLock lock(task_runner_map_lock_);
175 auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
176 CHECK(task_runner);
177 task_runner_map_[worker_thread_id] = task_runner;
178 }
lazyboyee4adef2016-05-24 00:55:16179}
180
lazyboy4c82177a2016-10-18 00:04:09181void WorkerThreadDispatcher::RemoveWorkerData(
182 int64_t service_worker_version_id) {
lazyboyee4adef2016-05-24 00:55:16183 ServiceWorkerData* data = g_data_tls.Pointer()->Get();
184 if (data) {
lazyboy4c82177a2016-10-18 00:04:09185 DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
lazyboyee4adef2016-05-24 00:55:16186 delete data;
187 g_data_tls.Pointer()->Set(nullptr);
188 }
lazyboy8874f2d2017-05-08 15:07:08189
190 int worker_thread_id = base::PlatformThread::CurrentId();
191 DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
192 {
193 base::AutoLock lock(task_runner_map_lock_);
194 task_runner_map_.erase(worker_thread_id);
195 }
lazyboyee4adef2016-05-24 00:55:16196}
197
198} // namespace extensions