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_function_dispatcher.h"
8 #include "base/json/json_string_value_serializer.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/metrics/sparse_histogram.h"
13 #include "base/process/process.h"
14 #include "base/values.h"
15 #include "build/build_config.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/user_metrics.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_observer.h"
23 #include "content/public/common/result_codes.h"
24 #include "extensions/browser/api_activity_monitor.h"
25 #include "extensions/browser/extension_function_registry.h"
26 #include "extensions/browser/extension_message_filter.h"
27 #include "extensions/browser/extension_registry.h"
28 #include "extensions/browser/extension_system.h"
29 #include "extensions/browser/extensions_browser_client.h"
30 #include "extensions/browser/process_manager.h"
31 #include "extensions/browser/process_map.h"
32 #include "extensions/browser/quota_service.h"
33 #include "extensions/common/extension_api.h"
34 #include "extensions/common/extension_messages.h"
35 #include "extensions/common/extension_set.h"
36 #include "ipc/ipc_message.h"
37 #include "ipc/ipc_message_macros.h"
39 using content::BrowserThread;
40 using content::RenderViewHost;
42 namespace extensions {
45 // Notifies the ApiActivityMonitor that an extension API function has been
46 // called. May be called from any thread.
47 void NotifyApiFunctionCalled(const std::string& extension_id,
48 const std::string& api_name,
49 scoped_ptr<base::ListValue> args,
50 content::BrowserContext* browser_context) {
51 // The ApiActivityMonitor can only be accessed from the main (UI) thread. If
52 // we're running on the wrong thread, re-dispatch from the main thread.
53 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
54 BrowserThread::PostTask(BrowserThread::UI,
56 base::Bind(&NotifyApiFunctionCalled,
63 // The BrowserContext may become invalid after the task above is posted.
64 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
67 ApiActivityMonitor* monitor =
68 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(browser_context);
70 monitor->OnApiFunctionCalled(extension_id, api_name, args.Pass());
73 // Separate copy of ExtensionAPI used for IO thread extension functions. We need
74 // this because ExtensionAPI has mutable data. It should be possible to remove
75 // this once all the extension APIs are updated to the feature system.
77 Static() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {}
78 scoped_ptr<ExtensionAPI> api;
80 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER;
82 // Kills the specified process because it sends us a malformed message.
83 void KillBadMessageSender(base::ProcessHandle process) {
85 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD"));
87 base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
90 void CommonResponseCallback(IPC::Sender* ipc_sender,
92 base::ProcessHandle peer_process,
94 ExtensionFunction::ResponseType type,
95 const base::ListValue& results,
96 const std::string& error) {
99 if (type == ExtensionFunction::BAD_MESSAGE) {
100 // The renderer has done validation before sending extension api requests.
101 // Therefore, we should never receive a request that is invalid in a way
102 // that JSON validation in the renderer should have caught. It could be an
103 // attacker trying to exploit the browser, so we crash the renderer instead.
105 "Terminating renderer because of malformed extension message.";
106 if (content::RenderProcessHost::run_renderer_in_process()) {
107 // In single process mode it is better if we don't suicide but just crash.
110 KillBadMessageSender(peer_process);
116 ipc_sender->Send(new ExtensionMsg_Response(
117 routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results,
121 void IOThreadResponseCallback(
122 const base::WeakPtr<ExtensionMessageFilter>& ipc_sender,
125 ExtensionFunction::ResponseType type,
126 const base::ListValue& results,
127 const std::string& error) {
128 if (!ipc_sender.get())
131 CommonResponseCallback(ipc_sender.get(),
133 ipc_sender->PeerHandle(),
142 class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
143 : public content::WebContentsObserver {
145 UIThreadResponseCallbackWrapper(
146 const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher,
147 RenderViewHost* render_view_host)
148 : content::WebContentsObserver(
149 content::WebContents::FromRenderViewHost(render_view_host)),
150 dispatcher_(dispatcher),
151 render_view_host_(render_view_host),
152 weak_ptr_factory_(this) {
155 virtual ~UIThreadResponseCallbackWrapper() {
158 // content::WebContentsObserver overrides.
159 virtual void RenderViewDeleted(
160 RenderViewHost* render_view_host) OVERRIDE {
161 DCHECK_CURRENTLY_ON(BrowserThread::UI);
162 if (render_view_host != render_view_host_)
165 if (dispatcher_.get()) {
166 dispatcher_->ui_thread_response_callback_wrappers_
167 .erase(render_view_host);
173 ExtensionFunction::ResponseCallback CreateCallback(int request_id) {
175 &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted,
176 weak_ptr_factory_.GetWeakPtr(),
181 void OnExtensionFunctionCompleted(int request_id,
182 ExtensionFunction::ResponseType type,
183 const base::ListValue& results,
184 const std::string& error) {
185 CommonResponseCallback(
186 render_view_host_, render_view_host_->GetRoutingID(),
187 render_view_host_->GetProcess()->GetHandle(), request_id, type,
191 base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_;
192 content::RenderViewHost* render_view_host_;
193 base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_;
195 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper);
199 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const {
203 content::WebContents*
204 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const {
208 content::WebContents*
209 ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const {
210 return GetAssociatedWebContents();
213 void ExtensionFunctionDispatcher::GetAllFunctionNames(
214 std::vector<std::string>* names) {
215 ExtensionFunctionRegistry::GetInstance()->GetAllNames(names);
218 bool ExtensionFunctionDispatcher::OverrideFunction(
219 const std::string& name, ExtensionFunctionFactory factory) {
220 return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name,
225 void ExtensionFunctionDispatcher::DispatchOnIOThread(
226 InfoMap* extension_info_map,
228 int render_process_id,
229 base::WeakPtr<ExtensionMessageFilter> ipc_sender,
231 const ExtensionHostMsg_Request_Params& params) {
232 const Extension* extension =
233 extension_info_map->extensions().GetByID(params.extension_id);
237 ExtensionFunction::ResponseCallback callback(
238 base::Bind(&IOThreadResponseCallback, ipc_sender, routing_id,
241 scoped_refptr<ExtensionFunction> function(
242 CreateExtensionFunction(params,
245 extension_info_map->process_map(),
246 g_global_io_data.Get().api.get(),
252 IOThreadExtensionFunction* function_io =
253 function->AsIOThreadExtensionFunction();
258 function_io->set_ipc_sender(ipc_sender, routing_id);
259 function_io->set_extension_info_map(extension_info_map);
260 function->set_include_incognito(
261 extension_info_map->IsIncognitoEnabled(extension->id()));
263 if (!CheckPermissions(function.get(), params, callback))
266 QuotaService* quota = extension_info_map->GetQuotaService();
267 std::string violation_error = quota->Assess(extension->id(),
270 base::TimeTicks::Now());
271 if (violation_error.empty()) {
272 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy());
273 NotifyApiFunctionCalled(extension->id(),
276 static_cast<content::BrowserContext*>(profile_id));
277 UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls",
278 function->histogram_value());
279 function->Run()->Execute();
281 function->OnQuotaExceeded(violation_error);
285 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
286 content::BrowserContext* browser_context,
288 : browser_context_(browser_context),
289 delegate_(delegate) {
292 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
295 void ExtensionFunctionDispatcher::Dispatch(
296 const ExtensionHostMsg_Request_Params& params,
297 RenderViewHost* render_view_host) {
298 UIThreadResponseCallbackWrapperMap::const_iterator
299 iter = ui_thread_response_callback_wrappers_.find(render_view_host);
300 UIThreadResponseCallbackWrapper* callback_wrapper = NULL;
301 if (iter == ui_thread_response_callback_wrappers_.end()) {
302 callback_wrapper = new UIThreadResponseCallbackWrapper(AsWeakPtr(),
304 ui_thread_response_callback_wrappers_[render_view_host] = callback_wrapper;
306 callback_wrapper = iter->second;
309 DispatchWithCallbackInternal(
310 params, render_view_host, NULL,
311 callback_wrapper->CreateCallback(params.request_id));
314 void ExtensionFunctionDispatcher::DispatchWithCallbackInternal(
315 const ExtensionHostMsg_Request_Params& params,
316 RenderViewHost* render_view_host,
317 content::RenderFrameHost* render_frame_host,
318 const ExtensionFunction::ResponseCallback& callback) {
319 DCHECK(render_view_host || render_frame_host);
320 // TODO(yzshen): There is some shared logic between this method and
321 // DispatchOnIOThread(). It is nice to deduplicate.
322 ProcessMap* process_map = ProcessMap::Get(browser_context_);
326 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
327 const Extension* extension =
328 registry->enabled_extensions().GetByID(params.extension_id);
331 registry->enabled_extensions().GetHostedAppByURL(params.source_url);
334 int process_id = render_view_host ? render_view_host->GetProcess()->GetID() :
335 render_frame_host->GetProcess()->GetID();
336 scoped_refptr<ExtensionFunction> function(
337 CreateExtensionFunction(params,
341 ExtensionAPI::GetSharedInstance(),
347 UIThreadExtensionFunction* function_ui =
348 function->AsUIThreadExtensionFunction();
353 if (render_view_host) {
354 function_ui->SetRenderViewHost(render_view_host);
356 function_ui->SetRenderFrameHost(render_frame_host);
358 function_ui->set_dispatcher(AsWeakPtr());
359 function_ui->set_browser_context(browser_context_);
361 ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
362 extension, browser_context_)) {
363 function->set_include_incognito(true);
366 if (!CheckPermissions(function.get(), params, callback))
370 // Skip all of the UMA, quota, event page, activity logging stuff if there
371 // isn't an extension, e.g. if the function call was from WebUI.
372 function->Run()->Execute();
376 ExtensionSystem* extension_system = ExtensionSystem::Get(browser_context_);
377 QuotaService* quota = extension_system->quota_service();
378 std::string violation_error = quota->Assess(extension->id(),
381 base::TimeTicks::Now());
383 if (violation_error.empty()) {
384 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy());
386 // See crbug.com/39178.
387 ExtensionsBrowserClient::Get()->PermitExternalProtocolHandler();
388 NotifyApiFunctionCalled(
389 extension->id(), params.name, args.Pass(), browser_context_);
390 UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls",
391 function->histogram_value());
392 function->Run()->Execute();
394 function->OnQuotaExceeded(violation_error);
397 // Note: do not access |this| after this point. We may have been deleted
398 // if function->Run() ended up closing the tab that owns us.
400 // Check if extension was uninstalled by management.uninstall.
401 if (!registry->enabled_extensions().GetByID(params.extension_id))
404 // We only adjust the keepalive count for UIThreadExtensionFunction for
405 // now, largely for simplicity's sake. This is OK because currently, only
406 // the webRequest API uses IOThreadExtensionFunction, and that API is not
407 // compatible with lazy background pages.
408 extension_system->process_manager()->IncrementLazyKeepaliveCount(extension);
411 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted(
412 const Extension* extension) {
414 ExtensionSystem::Get(browser_context_)
416 ->DecrementLazyKeepaliveCount(extension);
421 bool ExtensionFunctionDispatcher::CheckPermissions(
422 ExtensionFunction* function,
423 const ExtensionHostMsg_Request_Params& params,
424 const ExtensionFunction::ResponseCallback& callback) {
425 if (!function->HasPermission()) {
426 LOG(ERROR) << "Permission denied for " << params.name;
427 SendAccessDenied(callback);
434 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction(
435 const ExtensionHostMsg_Request_Params& params,
436 const Extension* extension,
437 int requesting_process_id,
438 const ProcessMap& process_map,
441 const ExtensionFunction::ResponseCallback& callback) {
442 ExtensionFunction* function =
443 ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name);
445 LOG(ERROR) << "Unknown Extension API - " << params.name;
446 SendAccessDenied(callback);
450 function->SetArgs(¶ms.arguments);
451 function->set_source_url(params.source_url);
452 function->set_request_id(params.request_id);
453 function->set_has_callback(params.has_callback);
454 function->set_user_gesture(params.user_gesture);
455 function->set_extension(extension);
456 function->set_profile_id(profile_id);
457 function->set_response_callback(callback);
458 function->set_source_tab_id(params.source_tab_id);
459 function->set_source_context_type(
460 process_map.GetMostLikelyContextType(extension, requesting_process_id));
466 void ExtensionFunctionDispatcher::SendAccessDenied(
467 const ExtensionFunction::ResponseCallback& callback) {
468 base::ListValue empty_list;
469 callback.Run(ExtensionFunction::FAILED, empty_list,
470 "Access to extension API denied.");
473 } // namespace extensions