extension_service_worker_message_filter.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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/browser/extension_service_worker_message_filter.h"
  5. #include "base/bind.h"
  6. #include "base/memory/singleton.h"
  7. #include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h"
  8. #include "components/keyed_service/core/keyed_service_shutdown_notifier.h"
  9. #include "content/public/browser/service_worker_context.h"
  10. #include "content/public/browser/service_worker_external_request_result.h"
  11. #include "extensions/browser/bad_message.h"
  12. #include "extensions/browser/event_router.h"
  13. #include "extensions/browser/event_router_factory.h"
  14. #include "extensions/browser/events/event_ack_data.h"
  15. #include "extensions/browser/extension_function_dispatcher.h"
  16. #include "extensions/browser/extension_registry.h"
  17. #include "extensions/browser/extension_registry_factory.h"
  18. #include "extensions/browser/process_manager.h"
  19. #include "extensions/browser/process_manager_factory.h"
  20. #include "extensions/browser/process_map.h"
  21. #include "extensions/browser/service_worker_task_queue.h"
  22. #include "extensions/common/extension_messages.h"
  23. #include "extensions/common/mojom/frame.mojom.h"
  24. namespace extensions {
  25. namespace {
  26. class ShutdownNotifierFactory
  27. : public BrowserContextKeyedServiceShutdownNotifierFactory {
  28. public:
  29. ShutdownNotifierFactory(const ShutdownNotifierFactory&) = delete;
  30. ShutdownNotifierFactory& operator=(const ShutdownNotifierFactory&) = delete;
  31. static ShutdownNotifierFactory* GetInstance() {
  32. return base::Singleton<ShutdownNotifierFactory>::get();
  33. }
  34. private:
  35. friend struct base::DefaultSingletonTraits<ShutdownNotifierFactory>;
  36. ShutdownNotifierFactory()
  37. : BrowserContextKeyedServiceShutdownNotifierFactory(
  38. "ExtensionServiceWorkerMessageFilter") {
  39. DependsOn(ExtensionRegistryFactory::GetInstance());
  40. DependsOn(EventRouterFactory::GetInstance());
  41. DependsOn(ProcessManagerFactory::GetInstance());
  42. }
  43. ~ShutdownNotifierFactory() override = default;
  44. };
  45. } // namespace
  46. ExtensionServiceWorkerMessageFilter::ExtensionServiceWorkerMessageFilter(
  47. int render_process_id,
  48. content::BrowserContext* context,
  49. content::ServiceWorkerContext* service_worker_context)
  50. : content::BrowserMessageFilter(ExtensionWorkerMsgStart),
  51. browser_context_(context),
  52. render_process_id_(render_process_id),
  53. service_worker_context_(service_worker_context),
  54. dispatcher_(new ExtensionFunctionDispatcher(context)) {
  55. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  56. shutdown_notifier_subscription_ =
  57. ShutdownNotifierFactory::GetInstance()->Get(context)->Subscribe(
  58. base::BindRepeating(
  59. &ExtensionServiceWorkerMessageFilter::ShutdownOnUIThread,
  60. base::Unretained(this)));
  61. }
  62. void ExtensionServiceWorkerMessageFilter::ShutdownOnUIThread() {
  63. browser_context_ = nullptr;
  64. shutdown_notifier_subscription_ = {};
  65. }
  66. void ExtensionServiceWorkerMessageFilter::OnDestruct() const {
  67. content::BrowserThread::DeleteOnUIThread::Destruct(this);
  68. }
  69. void ExtensionServiceWorkerMessageFilter::EnsureShutdownNotifierFactoryBuilt() {
  70. ShutdownNotifierFactory::GetInstance();
  71. }
  72. ExtensionServiceWorkerMessageFilter::~ExtensionServiceWorkerMessageFilter() {}
  73. void ExtensionServiceWorkerMessageFilter::OverrideThreadForMessage(
  74. const IPC::Message& message,
  75. content::BrowserThread::ID* thread) {
  76. if (message.type() == ExtensionHostMsg_RequestWorker::ID ||
  77. message.type() == ExtensionHostMsg_EventAckWorker::ID ||
  78. message.type() ==
  79. ExtensionHostMsg_DidInitializeServiceWorkerContext::ID ||
  80. message.type() == ExtensionHostMsg_DidStartServiceWorkerContext::ID ||
  81. message.type() == ExtensionHostMsg_DidStopServiceWorkerContext::ID ||
  82. message.type() == ExtensionHostMsg_WorkerResponseAck::ID) {
  83. *thread = content::BrowserThread::UI;
  84. }
  85. if (message.type() == ExtensionHostMsg_IncrementServiceWorkerActivity::ID ||
  86. message.type() == ExtensionHostMsg_DecrementServiceWorkerActivity::ID) {
  87. *thread = content::BrowserThread::UI;
  88. }
  89. }
  90. bool ExtensionServiceWorkerMessageFilter::OnMessageReceived(
  91. const IPC::Message& message) {
  92. bool handled = true;
  93. IPC_BEGIN_MESSAGE_MAP(ExtensionServiceWorkerMessageFilter, message)
  94. IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestWorker, OnRequestWorker)
  95. IPC_MESSAGE_HANDLER(ExtensionHostMsg_IncrementServiceWorkerActivity,
  96. OnIncrementServiceWorkerActivity)
  97. IPC_MESSAGE_HANDLER(ExtensionHostMsg_DecrementServiceWorkerActivity,
  98. OnDecrementServiceWorkerActivity)
  99. IPC_MESSAGE_HANDLER(ExtensionHostMsg_EventAckWorker, OnEventAckWorker)
  100. IPC_MESSAGE_HANDLER(ExtensionHostMsg_DidInitializeServiceWorkerContext,
  101. OnDidInitializeServiceWorkerContext)
  102. IPC_MESSAGE_HANDLER(ExtensionHostMsg_DidStartServiceWorkerContext,
  103. OnDidStartServiceWorkerContext)
  104. IPC_MESSAGE_HANDLER(ExtensionHostMsg_DidStopServiceWorkerContext,
  105. OnDidStopServiceWorkerContext)
  106. IPC_MESSAGE_HANDLER(ExtensionHostMsg_WorkerResponseAck, OnResponseWorker)
  107. IPC_MESSAGE_UNHANDLED(handled = false)
  108. IPC_END_MESSAGE_MAP()
  109. return handled;
  110. }
  111. void ExtensionServiceWorkerMessageFilter::OnRequestWorker(
  112. const mojom::RequestParams& params) {
  113. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  114. if (!browser_context_)
  115. return;
  116. dispatcher_->DispatchForServiceWorker(params, render_process_id_);
  117. }
  118. void ExtensionServiceWorkerMessageFilter::OnResponseWorker(
  119. int request_id,
  120. int64_t service_worker_version_id) {
  121. if (!browser_context_)
  122. return;
  123. dispatcher_->ProcessServiceWorkerResponse(request_id,
  124. service_worker_version_id);
  125. }
  126. void ExtensionServiceWorkerMessageFilter::OnIncrementServiceWorkerActivity(
  127. int64_t service_worker_version_id,
  128. const std::string& request_uuid) {
  129. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  130. if (!browser_context_)
  131. return;
  132. active_request_uuids_.insert(request_uuid);
  133. // The worker might have already stopped before we got here, so the increment
  134. // below might fail legitimately. Therefore, we do not send bad_message to the
  135. // worker even if it fails.
  136. service_worker_context_->StartingExternalRequest(
  137. service_worker_version_id,
  138. content::ServiceWorkerExternalRequestTimeoutType::kDefault, request_uuid);
  139. }
  140. void ExtensionServiceWorkerMessageFilter::OnDecrementServiceWorkerActivity(
  141. int64_t service_worker_version_id,
  142. const std::string& request_uuid) {
  143. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  144. if (!browser_context_)
  145. return;
  146. content::ServiceWorkerExternalRequestResult result =
  147. service_worker_context_->FinishedExternalRequest(
  148. service_worker_version_id, request_uuid);
  149. if (result != content::ServiceWorkerExternalRequestResult::kOk) {
  150. LOG(ERROR) << "ServiceWorkerContext::FinishedExternalRequest failed: "
  151. << static_cast<int>(result);
  152. }
  153. bool erased = active_request_uuids_.erase(request_uuid) == 1;
  154. // The worker may have already stopped before we got here, so only report
  155. // a bad message if we didn't have an increment for the UUID.
  156. if (!erased) {
  157. bad_message::ReceivedBadMessage(
  158. this, bad_message::ESWMF_INVALID_DECREMENT_ACTIVITY);
  159. }
  160. }
  161. void ExtensionServiceWorkerMessageFilter::OnEventAckWorker(
  162. const ExtensionId& extension_id,
  163. int64_t service_worker_version_id,
  164. int worker_thread_id,
  165. int event_id) {
  166. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  167. if (!browser_context_)
  168. return;
  169. const bool worker_stopped =
  170. !ProcessManager::Get(browser_context_)
  171. ->HasServiceWorker({extension_id, render_process_id_,
  172. service_worker_version_id, worker_thread_id});
  173. EventRouter::Get(browser_context_)
  174. ->event_ack_data()
  175. ->DecrementInflightEvent(
  176. service_worker_context_, render_process_id_,
  177. service_worker_version_id, event_id, worker_stopped,
  178. base::BindOnce(&ExtensionServiceWorkerMessageFilter::
  179. DidFailDecrementInflightEvent,
  180. this));
  181. }
  182. void ExtensionServiceWorkerMessageFilter::OnDidInitializeServiceWorkerContext(
  183. const ExtensionId& extension_id,
  184. int64_t service_worker_version_id,
  185. int thread_id) {
  186. if (!browser_context_)
  187. return;
  188. ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
  189. DCHECK(registry);
  190. if (!registry->enabled_extensions().GetByID(extension_id)) {
  191. // This can happen if the extension is unloaded at this point. Just
  192. // checking the extension process (as below) is insufficient because
  193. // tearing down processes is async and happens after extension unload.
  194. return;
  195. }
  196. if (!ProcessMap::Get(browser_context_)
  197. ->Contains(extension_id, render_process_id_)) {
  198. // We check the process in addition to the registry to guard against
  199. // situations in which an extension may still be enabled, but no longer
  200. // running in a given process.
  201. return;
  202. }
  203. ServiceWorkerTaskQueue::Get(browser_context_)
  204. ->DidInitializeServiceWorkerContext(render_process_id_, extension_id,
  205. service_worker_version_id, thread_id);
  206. }
  207. void ExtensionServiceWorkerMessageFilter::OnDidStartServiceWorkerContext(
  208. const ExtensionId& extension_id,
  209. ActivationSequence activation_sequence,
  210. const GURL& service_worker_scope,
  211. int64_t service_worker_version_id,
  212. int thread_id) {
  213. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  214. if (!browser_context_)
  215. return;
  216. DCHECK_NE(kMainThreadId, thread_id);
  217. if (!ProcessMap::Get(browser_context_)
  218. ->Contains(extension_id, render_process_id_)) {
  219. // We can legitimately get here if the extension was already unloaded.
  220. return;
  221. }
  222. CHECK(service_worker_scope.SchemeIs(kExtensionScheme) &&
  223. extension_id == service_worker_scope.host_piece());
  224. ServiceWorkerTaskQueue::Get(browser_context_)
  225. ->DidStartServiceWorkerContext(render_process_id_, extension_id,
  226. activation_sequence, service_worker_scope,
  227. service_worker_version_id, thread_id);
  228. }
  229. void ExtensionServiceWorkerMessageFilter::OnDidStopServiceWorkerContext(
  230. const ExtensionId& extension_id,
  231. ActivationSequence activation_sequence,
  232. const GURL& service_worker_scope,
  233. int64_t service_worker_version_id,
  234. int thread_id) {
  235. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  236. if (!browser_context_)
  237. return;
  238. DCHECK_NE(kMainThreadId, thread_id);
  239. if (!ProcessMap::Get(browser_context_)
  240. ->Contains(extension_id, render_process_id_)) {
  241. // We can legitimately get here if the extension was already unloaded.
  242. return;
  243. }
  244. CHECK(service_worker_scope.SchemeIs(kExtensionScheme) &&
  245. extension_id == service_worker_scope.host_piece());
  246. ServiceWorkerTaskQueue::Get(browser_context_)
  247. ->DidStopServiceWorkerContext(render_process_id_, extension_id,
  248. activation_sequence, service_worker_scope,
  249. service_worker_version_id, thread_id);
  250. }
  251. void ExtensionServiceWorkerMessageFilter::DidFailDecrementInflightEvent() {
  252. bad_message::ReceivedBadMessage(this, bad_message::ESWMF_BAD_EVENT_ACK);
  253. }
  254. } // namespace extensions