1 // Copyright 2014 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.
5 #include "extensions/browser/extension_message_filter.h"
7 #include "base/memory/singleton.h"
8 #include "components/crx_file/id_util.h"
9 #include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/render_process_host.h"
12 #include "extensions/browser/blob_holder.h"
13 #include "extensions/browser/event_router.h"
14 #include "extensions/browser/event_router_factory.h"
15 #include "extensions/browser/extension_registry.h"
16 #include "extensions/browser/process_manager.h"
17 #include "extensions/browser/process_manager_factory.h"
18 #include "extensions/browser/process_map.h"
19 #include "extensions/common/extension.h"
20 #include "extensions/common/extension_messages.h"
21 #include "extensions/common/manifest_handlers/background_info.h"
22 #include "ipc/ipc_message_macros.h"
24 using content::BrowserThread
;
25 using content::RenderProcessHost
;
27 namespace extensions
{
31 class ShutdownNotifierFactory
32 : public BrowserContextKeyedServiceShutdownNotifierFactory
{
34 static ShutdownNotifierFactory
* GetInstance() {
35 return base::Singleton
<ShutdownNotifierFactory
>::get();
39 friend struct base::DefaultSingletonTraits
<ShutdownNotifierFactory
>;
41 ShutdownNotifierFactory()
42 : BrowserContextKeyedServiceShutdownNotifierFactory(
43 "ExtensionMessageFilter") {
44 DependsOn(EventRouterFactory::GetInstance());
45 DependsOn(ProcessManagerFactory::GetInstance());
47 ~ShutdownNotifierFactory() override
{}
49 DISALLOW_COPY_AND_ASSIGN(ShutdownNotifierFactory
);
54 ExtensionMessageFilter::ExtensionMessageFilter(int render_process_id
,
55 content::BrowserContext
* context
)
56 : BrowserMessageFilter(ExtensionMsgStart
),
57 render_process_id_(render_process_id
),
58 browser_context_(context
) {
59 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
61 ShutdownNotifierFactory::GetInstance()->Get(context
)->Subscribe(
62 base::Bind(&ExtensionMessageFilter::ShutdownOnUIThread
,
63 base::Unretained(this)));
66 void ExtensionMessageFilter::EnsureShutdownNotifierFactoryBuilt() {
67 ShutdownNotifierFactory::GetInstance();
70 ExtensionMessageFilter::~ExtensionMessageFilter() {
71 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
74 EventRouter
* ExtensionMessageFilter::GetEventRouter() {
75 DCHECK(browser_context_
);
76 return EventRouter::Get(browser_context_
);
79 void ExtensionMessageFilter::ShutdownOnUIThread() {
80 browser_context_
= nullptr;
81 shutdown_notifier_
.reset();
84 void ExtensionMessageFilter::OverrideThreadForMessage(
85 const IPC::Message
& message
,
86 BrowserThread::ID
* thread
) {
87 switch (message
.type()) {
88 case ExtensionHostMsg_AddListener::ID
:
89 case ExtensionHostMsg_RemoveListener::ID
:
90 case ExtensionHostMsg_AddLazyListener::ID
:
91 case ExtensionHostMsg_RemoveLazyListener::ID
:
92 case ExtensionHostMsg_AddFilteredListener::ID
:
93 case ExtensionHostMsg_RemoveFilteredListener::ID
:
94 case ExtensionHostMsg_ShouldSuspendAck::ID
:
95 case ExtensionHostMsg_SuspendAck::ID
:
96 case ExtensionHostMsg_TransferBlobsAck::ID
:
97 case ExtensionHostMsg_WakeEventPage::ID
:
98 *thread
= BrowserThread::UI
;
105 void ExtensionMessageFilter::OnDestruct() const {
106 BrowserThread::DeleteOnUIThread::Destruct(this);
109 bool ExtensionMessageFilter::OnMessageReceived(const IPC::Message
& message
) {
110 // If we have been shut down already, return.
111 if (!browser_context_
)
115 IPC_BEGIN_MESSAGE_MAP(ExtensionMessageFilter
, message
)
116 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddListener
,
117 OnExtensionAddListener
)
118 IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveListener
,
119 OnExtensionRemoveListener
)
120 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddLazyListener
,
121 OnExtensionAddLazyListener
)
122 IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveLazyListener
,
123 OnExtensionRemoveLazyListener
)
124 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddFilteredListener
,
125 OnExtensionAddFilteredListener
)
126 IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveFilteredListener
,
127 OnExtensionRemoveFilteredListener
)
128 IPC_MESSAGE_HANDLER(ExtensionHostMsg_ShouldSuspendAck
,
129 OnExtensionShouldSuspendAck
)
130 IPC_MESSAGE_HANDLER(ExtensionHostMsg_SuspendAck
,
131 OnExtensionSuspendAck
)
132 IPC_MESSAGE_HANDLER(ExtensionHostMsg_TransferBlobsAck
,
133 OnExtensionTransferBlobsAck
)
134 IPC_MESSAGE_HANDLER(ExtensionHostMsg_WakeEventPage
,
135 OnExtensionWakeEventPage
)
136 IPC_MESSAGE_UNHANDLED(handled
= false)
137 IPC_END_MESSAGE_MAP()
141 void ExtensionMessageFilter::OnExtensionAddListener(
142 const std::string
& extension_id
,
143 const GURL
& listener_url
,
144 const std::string
& event_name
) {
145 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
146 if (!browser_context_
)
149 RenderProcessHost
* process
= RenderProcessHost::FromID(render_process_id_
);
153 if (crx_file::id_util::IdIsValid(extension_id
)) {
154 GetEventRouter()->AddEventListener(event_name
, process
, extension_id
);
155 } else if (listener_url
.is_valid()) {
156 GetEventRouter()->AddEventListenerForURL(event_name
, process
, listener_url
);
158 NOTREACHED() << "Tried to add an event listener without a valid "
159 << "extension ID nor listener URL";
163 void ExtensionMessageFilter::OnExtensionRemoveListener(
164 const std::string
& extension_id
,
165 const GURL
& listener_url
,
166 const std::string
& event_name
) {
167 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
168 if (!browser_context_
)
171 RenderProcessHost
* process
= RenderProcessHost::FromID(render_process_id_
);
175 if (crx_file::id_util::IdIsValid(extension_id
)) {
176 GetEventRouter()->RemoveEventListener(event_name
, process
, extension_id
);
177 } else if (listener_url
.is_valid()) {
178 GetEventRouter()->RemoveEventListenerForURL(event_name
, process
,
181 NOTREACHED() << "Tried to remove an event listener without a valid "
182 << "extension ID nor listener URL";
186 void ExtensionMessageFilter::OnExtensionAddLazyListener(
187 const std::string
& extension_id
, const std::string
& event_name
) {
188 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
189 if (!browser_context_
)
192 GetEventRouter()->AddLazyEventListener(event_name
, extension_id
);
195 void ExtensionMessageFilter::OnExtensionRemoveLazyListener(
196 const std::string
& extension_id
, const std::string
& event_name
) {
197 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
198 if (!browser_context_
)
201 GetEventRouter()->RemoveLazyEventListener(event_name
, extension_id
);
204 void ExtensionMessageFilter::OnExtensionAddFilteredListener(
205 const std::string
& extension_id
,
206 const std::string
& event_name
,
207 const base::DictionaryValue
& filter
,
209 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
210 if (!browser_context_
)
213 RenderProcessHost
* process
= RenderProcessHost::FromID(render_process_id_
);
217 GetEventRouter()->AddFilteredEventListener(event_name
, process
, extension_id
,
221 void ExtensionMessageFilter::OnExtensionRemoveFilteredListener(
222 const std::string
& extension_id
,
223 const std::string
& event_name
,
224 const base::DictionaryValue
& filter
,
226 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
227 if (!browser_context_
)
230 RenderProcessHost
* process
= RenderProcessHost::FromID(render_process_id_
);
234 GetEventRouter()->RemoveFilteredEventListener(event_name
, process
,
235 extension_id
, filter
, lazy
);
238 void ExtensionMessageFilter::OnExtensionShouldSuspendAck(
239 const std::string
& extension_id
, int sequence_id
) {
240 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
241 if (!browser_context_
)
244 ProcessManager::Get(browser_context_
)
245 ->OnShouldSuspendAck(extension_id
, sequence_id
);
248 void ExtensionMessageFilter::OnExtensionSuspendAck(
249 const std::string
& extension_id
) {
250 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
251 if (!browser_context_
)
254 ProcessManager::Get(browser_context_
)->OnSuspendAck(extension_id
);
257 void ExtensionMessageFilter::OnExtensionTransferBlobsAck(
258 const std::vector
<std::string
>& blob_uuids
) {
259 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
260 if (!browser_context_
)
263 RenderProcessHost
* process
= RenderProcessHost::FromID(render_process_id_
);
267 BlobHolder::FromRenderProcessHost(process
)->DropBlobs(blob_uuids
);
270 void ExtensionMessageFilter::OnExtensionWakeEventPage(
272 const std::string
& extension_id
) {
273 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
274 if (!browser_context_
)
277 const Extension
* extension
= ExtensionRegistry::Get(browser_context_
)
278 ->enabled_extensions()
279 .GetByID(extension_id
);
281 // Don't kill the renderer, it might just be some context which hasn't
282 // caught up to extension having been uninstalled.
286 ProcessManager
* process_manager
= ProcessManager::Get(browser_context_
);
288 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
289 // Wake the event page if it's asleep, or immediately repond with success
290 // if it's already awake.
291 if (process_manager
->IsEventPageSuspended(extension_id
)) {
292 process_manager
->WakeEventPage(
294 base::Bind(&ExtensionMessageFilter::SendWakeEventPageResponse
, this,
297 SendWakeEventPageResponse(request_id
, true);
302 if (BackgroundInfo::HasPersistentBackgroundPage(extension
)) {
303 // No point in trying to wake a persistent background page. If it's open,
304 // immediately return and call it a success. If it's closed, fail.
305 SendWakeEventPageResponse(request_id
,
306 process_manager
->GetBackgroundHostForExtension(
307 extension_id
) != nullptr);
311 // The extension has no background page, so there is nothing to wake.
312 SendWakeEventPageResponse(request_id
, false);
315 void ExtensionMessageFilter::SendWakeEventPageResponse(int request_id
,
317 Send(new ExtensionMsg_WakeEventPageResponse(request_id
, success
));
320 } // namespace extensions