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 "chrome/browser/renderer_host/chrome_extension_message_filter.h"
8 #include "base/bind_helpers.h"
9 #include "base/files/file_path.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
14 #include "chrome/browser/extensions/activity_log/activity_actions.h"
15 #include "chrome/browser/extensions/activity_log/activity_log.h"
16 #include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h"
17 #include "chrome/browser/extensions/api/messaging/message_service.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/common/extensions/api/i18n/default_locale_handler.h"
21 #include "chrome/common/extensions/chrome_extension_messages.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/render_process_host.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/common/api/messaging/message.h"
26 #include "extensions/common/extension_messages.h"
27 #include "extensions/common/file_util.h"
28 #include "extensions/common/message_bundle.h"
30 using content::BrowserThread;
34 const uint32 kFilteredMessageClasses[] = {
35 ChromeExtensionMsgStart,
39 // Logs an action to the extension activity log for the specified profile. Can
40 // be called from any thread.
41 void AddActionToExtensionActivityLog(
43 scoped_refptr<extensions::Action> action) {
44 // The ActivityLog can only be accessed from the main (UI) thread. If we're
45 // running on the wrong thread, re-dispatch from the main thread.
46 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
47 BrowserThread::PostTask(
48 BrowserThread::UI, FROM_HERE,
49 base::Bind(&AddActionToExtensionActivityLog, profile, action));
51 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
53 // If the action included a URL, check whether it is for an incognito
54 // profile. The check is performed here so that it can safely be done from
56 if (action->page_url().is_valid() || !action->page_title().empty())
57 action->set_page_incognito(profile->IsOffTheRecord());
58 extensions::ActivityLog* activity_log =
59 extensions::ActivityLog::GetInstance(profile);
60 activity_log->LogAction(action);
66 ChromeExtensionMessageFilter::ChromeExtensionMessageFilter(
67 int render_process_id,
69 : BrowserMessageFilter(kFilteredMessageClasses,
70 arraysize(kFilteredMessageClasses)),
71 render_process_id_(render_process_id),
74 extensions::ExtensionSystem::Get(profile)->info_map()) {
75 DCHECK_CURRENTLY_ON(BrowserThread::UI);
76 notification_registrar_.Add(this,
77 chrome::NOTIFICATION_PROFILE_DESTROYED,
78 content::Source<Profile>(profile));
81 ChromeExtensionMessageFilter::~ChromeExtensionMessageFilter() {
82 DCHECK_CURRENTLY_ON(BrowserThread::UI);
85 bool ChromeExtensionMessageFilter::OnMessageReceived(
86 const IPC::Message& message) {
88 IPC_BEGIN_MESSAGE_MAP(ChromeExtensionMessageFilter, message)
89 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToExtension,
90 OnOpenChannelToExtension)
91 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToTab, OnOpenChannelToTab)
92 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToNativeApp,
93 OnOpenChannelToNativeApp)
94 IPC_MESSAGE_HANDLER(ExtensionHostMsg_PostMessage, OnPostMessage)
95 IPC_MESSAGE_HANDLER_DELAY_REPLY(ExtensionHostMsg_GetMessageBundle,
96 OnGetExtMessageBundle)
97 IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseChannel, OnExtensionCloseChannel)
98 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddAPIActionToActivityLog,
99 OnAddAPIActionToExtensionActivityLog);
100 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddDOMActionToActivityLog,
101 OnAddDOMActionToExtensionActivityLog);
102 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddEventToActivityLog,
103 OnAddEventToExtensionActivityLog);
104 IPC_MESSAGE_UNHANDLED(handled = false)
105 IPC_END_MESSAGE_MAP()
110 void ChromeExtensionMessageFilter::OverrideThreadForMessage(
111 const IPC::Message& message, BrowserThread::ID* thread) {
112 switch (message.type()) {
113 case ExtensionHostMsg_PostMessage::ID:
114 case ExtensionHostMsg_CloseChannel::ID:
115 *thread = BrowserThread::UI;
122 void ChromeExtensionMessageFilter::OnDestruct() const {
123 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
126 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
130 void ChromeExtensionMessageFilter::OnOpenChannelToExtension(
132 const ExtensionMsg_ExternalConnectionInfo& info,
133 const std::string& channel_name,
134 bool include_tls_channel_id,
137 extensions::MessageService::AllocatePortIdPair(port_id, &port2_id);
139 BrowserThread::PostTask(
140 BrowserThread::UI, FROM_HERE,
142 &ChromeExtensionMessageFilter::OpenChannelToExtensionOnUIThread,
143 this, render_process_id_, routing_id, port2_id, info,
144 channel_name, include_tls_channel_id));
147 void ChromeExtensionMessageFilter::OpenChannelToExtensionOnUIThread(
148 int source_process_id, int source_routing_id,
149 int receiver_port_id,
150 const ExtensionMsg_ExternalConnectionInfo& info,
151 const std::string& channel_name,
152 bool include_tls_channel_id) {
153 DCHECK_CURRENTLY_ON(BrowserThread::UI);
155 extensions::MessageService::Get(profile_)
156 ->OpenChannelToExtension(source_process_id,
163 include_tls_channel_id);
167 void ChromeExtensionMessageFilter::OnOpenChannelToNativeApp(
169 const std::string& source_extension_id,
170 const std::string& native_app_name,
173 extensions::MessageService::AllocatePortIdPair(port_id, &port2_id);
175 BrowserThread::PostTask(
176 BrowserThread::UI, FROM_HERE,
178 &ChromeExtensionMessageFilter::OpenChannelToNativeAppOnUIThread,
179 this, routing_id, port2_id, source_extension_id, native_app_name));
182 void ChromeExtensionMessageFilter::OpenChannelToNativeAppOnUIThread(
183 int source_routing_id,
184 int receiver_port_id,
185 const std::string& source_extension_id,
186 const std::string& native_app_name) {
187 DCHECK_CURRENTLY_ON(BrowserThread::UI);
189 extensions::MessageService::Get(profile_)
190 ->OpenChannelToNativeApp(render_process_id_,
198 void ChromeExtensionMessageFilter::OnOpenChannelToTab(
199 int routing_id, int tab_id, const std::string& extension_id,
200 const std::string& channel_name, int* port_id) {
202 extensions::MessageService::AllocatePortIdPair(port_id, &port2_id);
204 BrowserThread::PostTask(
205 BrowserThread::UI, FROM_HERE,
206 base::Bind(&ChromeExtensionMessageFilter::OpenChannelToTabOnUIThread,
207 this, render_process_id_, routing_id, port2_id, tab_id,
208 extension_id, channel_name));
211 void ChromeExtensionMessageFilter::OpenChannelToTabOnUIThread(
212 int source_process_id, int source_routing_id,
213 int receiver_port_id,
215 const std::string& extension_id,
216 const std::string& channel_name) {
217 DCHECK_CURRENTLY_ON(BrowserThread::UI);
219 extensions::MessageService::Get(profile_)
220 ->OpenChannelToTab(source_process_id,
229 void ChromeExtensionMessageFilter::OnPostMessage(
231 const extensions::Message& message) {
235 extensions::MessageService::Get(profile_)->PostMessage(port_id, message);
238 void ChromeExtensionMessageFilter::OnGetExtMessageBundle(
239 const std::string& extension_id, IPC::Message* reply_msg) {
240 const extensions::Extension* extension =
241 extension_info_map_->extensions().GetByID(extension_id);
242 base::FilePath extension_path;
243 std::string default_locale;
245 extension_path = extension->path();
246 default_locale = extensions::LocaleInfo::GetDefaultLocale(extension);
249 BrowserThread::PostBlockingPoolTask(
252 &ChromeExtensionMessageFilter::OnGetExtMessageBundleOnBlockingPool,
253 this, extension_path, extension_id, default_locale, reply_msg));
256 void ChromeExtensionMessageFilter::OnGetExtMessageBundleOnBlockingPool(
257 const base::FilePath& extension_path,
258 const std::string& extension_id,
259 const std::string& default_locale,
260 IPC::Message* reply_msg) {
261 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
263 scoped_ptr<extensions::MessageBundle::SubstitutionMap> dictionary_map(
264 extensions::file_util::LoadMessageBundleSubstitutionMap(
265 extension_path, extension_id, default_locale));
267 ExtensionHostMsg_GetMessageBundle::WriteReplyParams(reply_msg,
272 void ChromeExtensionMessageFilter::OnExtensionCloseChannel(
274 const std::string& error_message) {
278 if (!content::RenderProcessHost::FromID(render_process_id_))
279 return; // To guard against crash in browser_tests shutdown.
281 extensions::MessageService* message_service =
282 extensions::MessageService::Get(profile_);
284 message_service->CloseChannel(port_id, error_message);
287 void ChromeExtensionMessageFilter::OnAddAPIActionToExtensionActivityLog(
288 const std::string& extension_id,
289 const ExtensionHostMsg_APIActionOrEvent_Params& params) {
290 scoped_refptr<extensions::Action> action = new extensions::Action(
291 extension_id, base::Time::Now(), extensions::Action::ACTION_API_CALL,
293 action->set_args(make_scoped_ptr(params.arguments.DeepCopy()));
294 if (!params.extra.empty()) {
295 action->mutable_other()->SetString(
296 activity_log_constants::kActionExtra, params.extra);
298 AddActionToExtensionActivityLog(profile_, action);
301 void ChromeExtensionMessageFilter::OnAddDOMActionToExtensionActivityLog(
302 const std::string& extension_id,
303 const ExtensionHostMsg_DOMAction_Params& params) {
304 scoped_refptr<extensions::Action> action = new extensions::Action(
305 extension_id, base::Time::Now(), extensions::Action::ACTION_DOM_ACCESS,
307 action->set_args(make_scoped_ptr(params.arguments.DeepCopy()));
308 action->set_page_url(params.url);
309 action->set_page_title(base::UTF16ToUTF8(params.url_title));
310 action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
312 AddActionToExtensionActivityLog(profile_, action);
315 void ChromeExtensionMessageFilter::OnAddEventToExtensionActivityLog(
316 const std::string& extension_id,
317 const ExtensionHostMsg_APIActionOrEvent_Params& params) {
318 scoped_refptr<extensions::Action> action = new extensions::Action(
319 extension_id, base::Time::Now(), extensions::Action::ACTION_API_EVENT,
321 action->set_args(make_scoped_ptr(params.arguments.DeepCopy()));
322 if (!params.extra.empty()) {
323 action->mutable_other()->SetString(activity_log_constants::kActionExtra,
326 AddActionToExtensionActivityLog(profile_, action);
329 void ChromeExtensionMessageFilter::Observe(
331 const content::NotificationSource& source,
332 const content::NotificationDetails& details) {
333 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);