Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / extensions / browser / extension_message_filter.cc
blobd35f2557315b9d1cfc5dc021ffc48db0666c81ac
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 {
29 namespace {
31 class ShutdownNotifierFactory
32 : public BrowserContextKeyedServiceShutdownNotifierFactory {
33 public:
34 static ShutdownNotifierFactory* GetInstance() {
35 return Singleton<ShutdownNotifierFactory>::get();
38 private:
39 friend struct 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);
52 } // namespace
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);
60 shutdown_notifier_ =
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;
99 break;
100 default:
101 break;
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_)
112 return true;
114 bool handled = true;
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()
138 return handled;
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_)
147 return;
149 RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
150 if (!process)
151 return;
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);
157 } else {
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_)
169 return;
171 RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
172 if (!process)
173 return;
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,
179 listener_url);
180 } else {
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_)
190 return;
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_)
199 return;
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,
208 bool lazy) {
209 DCHECK_CURRENTLY_ON(BrowserThread::UI);
210 if (!browser_context_)
211 return;
213 RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
214 if (!process)
215 return;
217 GetEventRouter()->AddFilteredEventListener(event_name, process, extension_id,
218 filter, lazy);
221 void ExtensionMessageFilter::OnExtensionRemoveFilteredListener(
222 const std::string& extension_id,
223 const std::string& event_name,
224 const base::DictionaryValue& filter,
225 bool lazy) {
226 DCHECK_CURRENTLY_ON(BrowserThread::UI);
227 if (!browser_context_)
228 return;
230 RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
231 if (!process)
232 return;
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_)
242 return;
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_)
252 return;
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_)
261 return;
263 RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
264 if (!process)
265 return;
267 BlobHolder::FromRenderProcessHost(process)->DropBlobs(blob_uuids);
270 void ExtensionMessageFilter::OnExtensionWakeEventPage(
271 int request_id,
272 const std::string& extension_id) {
273 DCHECK_CURRENTLY_ON(BrowserThread::UI);
274 if (!browser_context_)
275 return;
277 const Extension* extension = ExtensionRegistry::Get(browser_context_)
278 ->enabled_extensions()
279 .GetByID(extension_id);
280 if (!extension) {
281 // Don't kill the renderer, it might just be some context which hasn't
282 // caught up to extension having been uninstalled.
283 return;
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(
293 extension_id,
294 base::Bind(&ExtensionMessageFilter::SendWakeEventPageResponse, this,
295 request_id));
296 } else {
297 SendWakeEventPageResponse(request_id, true);
299 return;
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);
308 return;
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,
316 bool success) {
317 Send(new ExtensionMsg_WakeEventPageResponse(request_id, success));
320 } // namespace extensions