PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/extensions/renderer/worker_thread_dispatcher.cc

http://github.com/chromium/chromium
C++ | 336 lines | 275 code | 41 blank | 20 comment | 16 complexity | 65f52be74e3baff82c2ccaf89e9b730f MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, BSD-2-Clause, LGPL-2.1, MPL-2.0, 0BSD, EPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BitTorrent-1.0, CPL-1.0, LGPL-3.0, Unlicense, BSD-3-Clause, CC0-1.0, JSON, MIT, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0
  1. // 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. #include "extensions/renderer/worker_thread_dispatcher.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/feature_list.h"
  8. #include "base/lazy_instance.h"
  9. #include "base/threading/platform_thread.h"
  10. #include "base/threading/thread_local.h"
  11. #include "base/values.h"
  12. #include "content/public/renderer/render_thread.h"
  13. #include "content/public/renderer/worker_thread.h"
  14. #include "extensions/common/constants.h"
  15. #include "extensions/common/extension_features.h"
  16. #include "extensions/common/extension_messages.h"
  17. #include "extensions/renderer/dispatcher.h"
  18. #include "extensions/renderer/extension_interaction_provider.h"
  19. #include "extensions/renderer/extensions_renderer_client.h"
  20. #include "extensions/renderer/native_extension_bindings_system.h"
  21. #include "extensions/renderer/native_renderer_messaging_service.h"
  22. #include "extensions/renderer/service_worker_data.h"
  23. #include "extensions/renderer/worker_script_context_set.h"
  24. #include "extensions/renderer/worker_thread_util.h"
  25. namespace extensions {
  26. namespace {
  27. base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit
  28. g_worker_thread_dispatcher_instance = LAZY_INSTANCE_INITIALIZER;
  29. base::LazyInstance<base::ThreadLocalPointer<extensions::ServiceWorkerData>>::
  30. DestructorAtExit g_data_tls = LAZY_INSTANCE_INITIALIZER;
  31. ServiceWorkerData* GetServiceWorkerDataChecked() {
  32. ServiceWorkerData* data = WorkerThreadDispatcher::GetServiceWorkerData();
  33. DCHECK(data);
  34. return data;
  35. }
  36. } // namespace
  37. WorkerThreadDispatcher::WorkerThreadDispatcher() {}
  38. WorkerThreadDispatcher::~WorkerThreadDispatcher() {}
  39. WorkerThreadDispatcher* WorkerThreadDispatcher::Get() {
  40. return g_worker_thread_dispatcher_instance.Pointer();
  41. }
  42. void WorkerThreadDispatcher::Init(content::RenderThread* render_thread) {
  43. DCHECK(render_thread);
  44. DCHECK_EQ(content::RenderThread::Get(), render_thread);
  45. DCHECK(!message_filter_);
  46. message_filter_ = render_thread->GetSyncMessageFilter();
  47. render_thread->AddObserver(this);
  48. }
  49. // static
  50. NativeExtensionBindingsSystem* WorkerThreadDispatcher::GetBindingsSystem() {
  51. return GetServiceWorkerDataChecked()->bindings_system();
  52. }
  53. // static
  54. V8SchemaRegistry* WorkerThreadDispatcher::GetV8SchemaRegistry() {
  55. return GetServiceWorkerDataChecked()->v8_schema_registry();
  56. }
  57. // static
  58. ScriptContext* WorkerThreadDispatcher::GetScriptContext() {
  59. return GetServiceWorkerDataChecked()->context();
  60. }
  61. // static
  62. ServiceWorkerData* WorkerThreadDispatcher::GetServiceWorkerData() {
  63. return g_data_tls.Pointer()->Get();
  64. }
  65. // static
  66. bool WorkerThreadDispatcher::HandlesMessageOnWorkerThread(
  67. const IPC::Message& message) {
  68. return message.type() == ExtensionMsg_ResponseWorker::ID ||
  69. message.type() == ExtensionMsg_DispatchEvent::ID ||
  70. message.type() == ExtensionMsg_DispatchOnConnect::ID ||
  71. message.type() == ExtensionMsg_DeliverMessage::ID ||
  72. message.type() == ExtensionMsg_DispatchOnDisconnect::ID ||
  73. message.type() == ExtensionMsg_ValidateMessagePort::ID;
  74. }
  75. // static
  76. void WorkerThreadDispatcher::ForwardIPC(int worker_thread_id,
  77. const IPC::Message& message) {
  78. WorkerThreadDispatcher::Get()->OnMessageReceivedOnWorkerThread(
  79. worker_thread_id, message);
  80. }
  81. // static
  82. void WorkerThreadDispatcher::UpdateBindingsOnWorkerThread(
  83. const ExtensionId& extension_id) {
  84. DCHECK(worker_thread_util::IsWorkerThread());
  85. DCHECK(!extension_id.empty());
  86. GetBindingsSystem()->UpdateBindings(extension_id,
  87. true /* permissions_changed */,
  88. Dispatcher::GetWorkerScriptContextSet());
  89. }
  90. bool WorkerThreadDispatcher::OnControlMessageReceived(
  91. const IPC::Message& message) {
  92. if (HandlesMessageOnWorkerThread(message)) {
  93. int worker_thread_id = content::WorkerThread::kInvalidWorkerThreadId;
  94. // TODO(lazyboy): Route |message| directly to the child thread using routed
  95. // IPC. Probably using mojo?
  96. bool found = base::PickleIterator(message).ReadInt(&worker_thread_id);
  97. CHECK(found);
  98. if (worker_thread_id == kMainThreadId)
  99. return false;
  100. return PostTaskToWorkerThread(
  101. worker_thread_id, base::BindOnce(&WorkerThreadDispatcher::ForwardIPC,
  102. worker_thread_id, message));
  103. }
  104. return false;
  105. }
  106. bool WorkerThreadDispatcher::UpdateBindingsForWorkers(
  107. const ExtensionId& extension_id) {
  108. bool success = true;
  109. base::AutoLock lock(task_runner_map_lock_);
  110. for (const auto& task_runner_info : task_runner_map_) {
  111. const int worker_thread_id = task_runner_info.first;
  112. base::TaskRunner* runner = task_runner_map_[worker_thread_id];
  113. bool posted = runner->PostTask(
  114. FROM_HERE,
  115. base::BindOnce(&WorkerThreadDispatcher::UpdateBindingsOnWorkerThread,
  116. extension_id));
  117. success &= posted;
  118. }
  119. return success;
  120. }
  121. void WorkerThreadDispatcher::OnMessageReceivedOnWorkerThread(
  122. int worker_thread_id,
  123. const IPC::Message& message) {
  124. CHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
  125. // If the worker state was already destroyed via
  126. // Dispatcher::WillDestroyServiceWorkerContextOnWorkerThread, then
  127. // drop this IPC. See https://crbug.com/1008143 for details.
  128. if (!GetServiceWorkerData())
  129. return;
  130. bool handled = true;
  131. IPC_BEGIN_MESSAGE_MAP(WorkerThreadDispatcher, message)
  132. IPC_MESSAGE_HANDLER(ExtensionMsg_ResponseWorker, OnResponseWorker)
  133. IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchEvent, OnDispatchEvent)
  134. IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect)
  135. IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage)
  136. IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
  137. OnDispatchOnDisconnect)
  138. IPC_MESSAGE_HANDLER(ExtensionMsg_ValidateMessagePort, OnValidateMessagePort)
  139. IPC_MESSAGE_UNHANDLED(handled = false)
  140. IPC_END_MESSAGE_MAP()
  141. CHECK(handled);
  142. }
  143. bool WorkerThreadDispatcher::PostTaskToWorkerThread(int worker_thread_id,
  144. base::OnceClosure task) {
  145. base::AutoLock lock(task_runner_map_lock_);
  146. auto it = task_runner_map_.find(worker_thread_id);
  147. if (it == task_runner_map_.end())
  148. return false;
  149. bool task_posted = it->second->PostTask(FROM_HERE, std::move(task));
  150. DCHECK(task_posted) << "Could not PostTask IPC to worker thread.";
  151. return task_posted;
  152. }
  153. bool WorkerThreadDispatcher::Send(IPC::Message* message) {
  154. return message_filter_->Send(message);
  155. }
  156. void WorkerThreadDispatcher::OnResponseWorker(int worker_thread_id,
  157. int request_id,
  158. bool succeeded,
  159. const base::ListValue& response,
  160. const std::string& error) {
  161. ServiceWorkerData* data = g_data_tls.Pointer()->Get();
  162. data->bindings_system()->HandleResponse(request_id, succeeded, response,
  163. error);
  164. }
  165. void WorkerThreadDispatcher::OnDispatchEvent(
  166. const ExtensionMsg_DispatchEvent_Params& params,
  167. const base::ListValue& event_args) {
  168. ServiceWorkerData* data = g_data_tls.Pointer()->Get();
  169. DCHECK(data);
  170. ScriptContext* script_context = data->context();
  171. // Note |scoped_extension_interaction| requires a HandleScope.
  172. v8::Isolate* isolate = script_context->isolate();
  173. v8::HandleScope handle_scope(isolate);
  174. std::unique_ptr<InteractionProvider::Scope> scoped_extension_interaction;
  175. if (params.is_user_gesture) {
  176. scoped_extension_interaction =
  177. ExtensionInteractionProvider::Scope::ForWorker(
  178. script_context->v8_context());
  179. }
  180. data->bindings_system()->DispatchEventInContext(
  181. params.event_name, &event_args, &params.filtering_info, data->context());
  182. const int worker_thread_id = content::WorkerThread::GetCurrentId();
  183. Send(new ExtensionHostMsg_EventAckWorker(data->context()->GetExtensionID(),
  184. data->service_worker_version_id(),
  185. worker_thread_id, params.event_id));
  186. }
  187. void WorkerThreadDispatcher::OnDispatchOnConnect(
  188. int worker_thread_id,
  189. const PortId& target_port_id,
  190. const std::string& channel_name,
  191. const ExtensionMsg_TabConnectionInfo& source,
  192. const ExtensionMsg_ExternalConnectionInfo& info) {
  193. DCHECK_EQ(worker_thread_id, content::WorkerThread::GetCurrentId());
  194. WorkerThreadDispatcher::GetBindingsSystem()
  195. ->messaging_service()
  196. ->DispatchOnConnect(Dispatcher::GetWorkerScriptContextSet(),
  197. target_port_id, channel_name, source, info,
  198. // Render frames do not matter.
  199. nullptr);
  200. }
  201. void WorkerThreadDispatcher::OnValidateMessagePort(int worker_thread_id,
  202. const PortId& id) {
  203. DCHECK_EQ(content::WorkerThread::GetCurrentId(), worker_thread_id);
  204. WorkerThreadDispatcher::GetBindingsSystem()
  205. ->messaging_service()
  206. ->ValidateMessagePort(Dispatcher::GetWorkerScriptContextSet(), id,
  207. // Render frames do not matter.
  208. nullptr);
  209. }
  210. void WorkerThreadDispatcher::OnDeliverMessage(int worker_thread_id,
  211. const PortId& target_port_id,
  212. const Message& message) {
  213. WorkerThreadDispatcher::GetBindingsSystem()
  214. ->messaging_service()
  215. ->DeliverMessage(Dispatcher::GetWorkerScriptContextSet(), target_port_id,
  216. message,
  217. // Render frames do not matter.
  218. nullptr);
  219. }
  220. void WorkerThreadDispatcher::OnDispatchOnDisconnect(
  221. int worker_thread_id,
  222. const PortId& port_id,
  223. const std::string& error_message) {
  224. WorkerThreadDispatcher::GetBindingsSystem()
  225. ->messaging_service()
  226. ->DispatchOnDisconnect(Dispatcher::GetWorkerScriptContextSet(), port_id,
  227. error_message,
  228. // Render frames do not matter.
  229. nullptr);
  230. }
  231. void WorkerThreadDispatcher::AddWorkerData(
  232. int64_t service_worker_version_id,
  233. ActivationSequence activation_sequence,
  234. ScriptContext* script_context,
  235. std::unique_ptr<NativeExtensionBindingsSystem> bindings_system) {
  236. ServiceWorkerData* data = g_data_tls.Pointer()->Get();
  237. if (!data) {
  238. ServiceWorkerData* new_data =
  239. new ServiceWorkerData(service_worker_version_id, activation_sequence,
  240. script_context, std::move(bindings_system));
  241. g_data_tls.Pointer()->Set(new_data);
  242. }
  243. int worker_thread_id = content::WorkerThread::GetCurrentId();
  244. {
  245. base::AutoLock lock(task_runner_map_lock_);
  246. auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
  247. CHECK(task_runner);
  248. task_runner_map_[worker_thread_id] = task_runner;
  249. }
  250. }
  251. void WorkerThreadDispatcher::DidInitializeContext(
  252. int64_t service_worker_version_id) {
  253. ServiceWorkerData* data = g_data_tls.Pointer()->Get();
  254. DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
  255. const int thread_id = content::WorkerThread::GetCurrentId();
  256. DCHECK_NE(thread_id, kMainThreadId);
  257. Send(new ExtensionHostMsg_DidInitializeServiceWorkerContext(
  258. data->context()->GetExtensionID(), service_worker_version_id, thread_id));
  259. }
  260. void WorkerThreadDispatcher::DidStartContext(
  261. const GURL& service_worker_scope,
  262. int64_t service_worker_version_id) {
  263. ServiceWorkerData* data = g_data_tls.Pointer()->Get();
  264. DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
  265. const int thread_id = content::WorkerThread::GetCurrentId();
  266. DCHECK_NE(thread_id, kMainThreadId);
  267. Send(new ExtensionHostMsg_DidStartServiceWorkerContext(
  268. data->context()->GetExtensionID(), data->activation_sequence(),
  269. service_worker_scope, service_worker_version_id, thread_id));
  270. }
  271. void WorkerThreadDispatcher::DidStopContext(const GURL& service_worker_scope,
  272. int64_t service_worker_version_id) {
  273. ServiceWorkerData* data = g_data_tls.Pointer()->Get();
  274. const int thread_id = content::WorkerThread::GetCurrentId();
  275. DCHECK_NE(thread_id, kMainThreadId);
  276. DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
  277. Send(new ExtensionHostMsg_DidStopServiceWorkerContext(
  278. data->context()->GetExtensionID(), data->activation_sequence(),
  279. service_worker_scope, service_worker_version_id, thread_id));
  280. }
  281. void WorkerThreadDispatcher::RemoveWorkerData(
  282. int64_t service_worker_version_id) {
  283. ServiceWorkerData* data = g_data_tls.Pointer()->Get();
  284. if (data) {
  285. DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
  286. delete data;
  287. g_data_tls.Pointer()->Set(nullptr);
  288. }
  289. int worker_thread_id = content::WorkerThread::GetCurrentId();
  290. {
  291. base::AutoLock lock(task_runner_map_lock_);
  292. task_runner_map_.erase(worker_thread_id);
  293. }
  294. }
  295. } // namespace extensions