blob: 03e10c847a9ee4a8679569f910bfaf125c742ac6 [file] [log] [blame]
[email protected]60aad9c2012-01-13 19:55:321// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]703e807a2009-03-28 19:56:512// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/extension_function.h"
6
[email protected]93d49d72009-10-23 20:00:207#include "base/json/json_writer.h"
[email protected]73404a372009-04-17 23:09:108#include "base/logging.h"
[email protected]07ad9622013-01-18 23:00:339#include "base/metrics/histogram.h"
[email protected]703e807a2009-03-28 19:56:5110#include "chrome/browser/extensions/extension_function_dispatcher.h"
[email protected]eaa7dd182010-12-14 11:09:0011#include "chrome/browser/extensions/extension_service.h"
[email protected]44f4b132012-07-17 20:36:5712#include "chrome/browser/extensions/window_controller.h"
13#include "chrome/browser/extensions/window_controller_list.h"
[email protected]8ecad5e2010-12-02 21:18:3314#include "chrome/browser/profiles/profile.h"
[email protected]c357acb42011-06-09 20:52:4215#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
[email protected]f34efa22013-03-05 19:14:2316#include "chrome/browser/ui/browser.h"
[email protected]d8748142012-05-16 21:13:4317#include "chrome/browser/ui/browser_finder.h"
[email protected]91e51d612012-10-21 23:03:0518#include "chrome/browser/ui/tabs/tab_strip_model.h"
[email protected]c5dbef02011-05-13 05:06:0919#include "chrome/common/extensions/extension_messages.h"
[email protected]86ab86b2011-10-19 03:07:5520#include "content/public/browser/notification_source.h"
[email protected]0d6e9bd2011-10-18 04:29:1621#include "content/public/browser/notification_types.h"
[email protected]f3b1a082011-11-18 00:34:3022#include "content/public/browser/render_process_host.h"
[email protected]9c1662b2012-03-06 15:44:3323#include "content/public/browser/render_view_host.h"
[email protected]7f6f44c2011-12-14 13:23:3824#include "content/public/browser/user_metrics.h"
[email protected]b39ef1cb2011-10-25 04:46:5525#include "content/public/common/result_codes.h"
[email protected]c5dbef02011-05-13 05:06:0926
[email protected]631bb742011-11-02 11:29:3927using content::BrowserThread;
[email protected]eaabba22012-03-07 15:02:1128using content::RenderViewHost;
[email protected]7f6f44c2011-12-14 13:23:3829using content::UserMetricsAction;
[email protected]631bb742011-11-02 11:29:3930
[email protected]a2aef2e2011-05-26 22:48:1231// static
32void ExtensionFunctionDeleteTraits::Destruct(const ExtensionFunction* x) {
33 x->Destruct();
34}
35
36UIThreadExtensionFunction::RenderViewHostTracker::RenderViewHostTracker(
[email protected]ce0e2602013-03-15 20:53:2737 UIThreadExtensionFunction* function)
38 : content::RenderViewHostObserver(function->render_view_host()),
[email protected]0f7daaa2011-11-22 18:34:5639 function_(function) {
[email protected]c5dbef02011-05-13 05:06:0940}
[email protected]942690b132010-05-11 06:42:1441
[email protected]0f7daaa2011-11-22 18:34:5642void UIThreadExtensionFunction::RenderViewHostTracker::RenderViewHostDestroyed(
43 RenderViewHost* render_view_host) {
44 // Overidding the default behavior of RenderViewHostObserver which is to
45 // delete this. In our case, we'll be deleted when the
46 // UIThreadExtensionFunction that contains us goes away.
[email protected]ce0e2602013-03-15 20:53:2747
48 function_->SetRenderViewHost(NULL);
[email protected]0f7daaa2011-11-22 18:34:5649}
50
51bool UIThreadExtensionFunction::RenderViewHostTracker::OnMessageReceived(
52 const IPC::Message& message) {
53 return function_->OnMessageReceivedFromRenderView(message);
54}
55
[email protected]3a3d47472010-07-15 21:03:5456ExtensionFunction::ExtensionFunction()
[email protected]9931fbfc2010-07-23 09:15:5157 : request_id_(-1),
[email protected]637bf322011-10-01 20:46:3258 profile_id_(NULL),
[email protected]9931fbfc2010-07-23 09:15:5159 has_callback_(false),
[email protected]6451e332010-10-05 00:14:5360 include_incognito_(false),
[email protected]a2aef2e2011-05-26 22:48:1261 user_gesture_(false),
62 args_(NULL),
[email protected]07ad9622013-01-18 23:00:3363 bad_message_(false),
64 histogram_value_(extensions::functions::UNKNOWN) {
[email protected]3a3d47472010-07-15 21:03:5465}
66
67ExtensionFunction::~ExtensionFunction() {
68}
69
[email protected]2ad65b32011-05-26 23:39:2070UIThreadExtensionFunction* ExtensionFunction::AsUIThreadExtensionFunction() {
71 return NULL;
72}
73
[email protected]c357acb42011-06-09 20:52:4274IOThreadExtensionFunction* ExtensionFunction::AsIOThreadExtensionFunction() {
75 return NULL;
76}
77
[email protected]3d0e2262012-08-02 15:32:1678bool ExtensionFunction::HasPermission() {
79 return extension_->HasAPIPermission(name_);
80}
81
[email protected]85231d72012-08-31 09:45:2982void ExtensionFunction::OnQuotaExceeded(const std::string& violation_error) {
83 error_ = violation_error;
[email protected]fd50e7b2011-11-03 09:20:2584 SendResponse(false);
85}
86
[email protected]602542d2012-04-20 02:48:0187void ExtensionFunction::SetArgs(const base::ListValue* args) {
[email protected]30294edf2009-11-10 00:24:3888 DCHECK(!args_.get()); // Should only be called once.
[email protected]16f47e082011-01-18 02:16:5989 args_.reset(args->DeepCopy());
[email protected]b83e4602009-05-15 22:58:3390}
91
[email protected]07ff5fd2012-07-12 22:39:0992void ExtensionFunction::SetResult(base::Value* result) {
93 results_.reset(new base::ListValue());
94 results_->Append(result);
95}
96
97const ListValue* ExtensionFunction::GetResultList() {
98 return results_.get();
[email protected]637bf322011-10-01 20:46:3299}
100
[email protected]a2aef2e2011-05-26 22:48:12101const std::string ExtensionFunction::GetError() {
[email protected]3a3d47472010-07-15 21:03:54102 return error_;
103}
104
[email protected]60aad9c2012-01-13 19:55:32105void ExtensionFunction::SetError(const std::string& error) {
106 error_ = error;
107}
108
[email protected]a2aef2e2011-05-26 22:48:12109void ExtensionFunction::Run() {
[email protected]07ad9622013-01-18 23:00:33110 UMA_HISTOGRAM_ENUMERATION("Extensions.FunctionCalls", histogram_value(),
111 extensions::functions::ENUM_BOUNDARY);
112
[email protected]3a3d47472010-07-15 21:03:54113 if (!RunImpl())
114 SendResponse(false);
115}
116
[email protected]712627bf2012-04-30 03:21:04117bool ExtensionFunction::ShouldSkipQuotaLimiting() const {
118 return false;
119}
120
[email protected]a2aef2e2011-05-26 22:48:12121bool ExtensionFunction::HasOptionalArgument(size_t index) {
122 Value* value;
123 return args_->Get(index, &value) && !value->IsType(Value::TYPE_NULL);
124}
125
[email protected]c357acb42011-06-09 20:52:42126void ExtensionFunction::SendResponseImpl(base::ProcessHandle process,
[email protected]b44f8ad2012-06-15 20:52:58127 IPC::Sender* ipc_sender,
[email protected]74e21e72012-07-09 21:20:53128 int routing_id,
[email protected]c357acb42011-06-09 20:52:42129 bool success) {
130 DCHECK(ipc_sender);
131 if (bad_message_) {
132 HandleBadMessage(process);
133 return;
134 }
135
[email protected]07ff5fd2012-07-12 22:39:09136 // If results were never set, we send an empty argument list.
[email protected]3eeddd892013-04-17 17:00:11137 if (!results_)
[email protected]07ff5fd2012-07-12 22:39:09138 results_.reset(new ListValue());
[email protected]602542d2012-04-20 02:48:01139
[email protected]c357acb42011-06-09 20:52:42140 ipc_sender->Send(new ExtensionMsg_Response(
[email protected]6add1942012-07-13 09:21:23141 routing_id, request_id_, success, *results_, GetError()));
[email protected]c357acb42011-06-09 20:52:42142}
143
144void ExtensionFunction::HandleBadMessage(base::ProcessHandle process) {
145 LOG(ERROR) << "bad extension message " << name_ << " : terminating renderer.";
[email protected]f3b1a082011-11-18 00:34:30146 if (content::RenderProcessHost::run_renderer_in_process()) {
[email protected]c357acb42011-06-09 20:52:42147 // In single process mode it is better if we don't suicide but just crash.
148 CHECK(false);
149 } else {
[email protected]7cb19b42012-05-07 21:46:36150 NOTREACHED();
[email protected]7f6f44c2011-12-14 13:23:38151 content::RecordAction(UserMetricsAction("BadMessageTerminate_EFD"));
[email protected]c357acb42011-06-09 20:52:42152 if (process)
[email protected]1fcfb202011-07-19 19:53:14153 base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE,
154 false);
[email protected]c357acb42011-06-09 20:52:42155 }
156}
[email protected]a2aef2e2011-05-26 22:48:12157UIThreadExtensionFunction::UIThreadExtensionFunction()
[email protected]bdfc03e2011-11-22 00:20:33158 : render_view_host_(NULL), profile_(NULL), delegate_(NULL) {
[email protected]a2aef2e2011-05-26 22:48:12159}
160
161UIThreadExtensionFunction::~UIThreadExtensionFunction() {
[email protected]7042b682012-04-19 22:57:51162 if (dispatcher() && render_view_host())
[email protected]720ad1312012-02-27 23:07:36163 dispatcher()->OnExtensionFunctionCompleted(GetExtension());
[email protected]a2aef2e2011-05-26 22:48:12164}
165
[email protected]2ad65b32011-05-26 23:39:20166UIThreadExtensionFunction*
167UIThreadExtensionFunction::AsUIThreadExtensionFunction() {
168 return this;
169}
170
[email protected]0f7daaa2011-11-22 18:34:56171bool UIThreadExtensionFunction::OnMessageReceivedFromRenderView(
172 const IPC::Message& message) {
173 return false;
174}
175
[email protected]a2aef2e2011-05-26 22:48:12176void UIThreadExtensionFunction::Destruct() const {
177 BrowserThread::DeleteOnUIThread::Destruct(this);
178}
179
180void UIThreadExtensionFunction::SetRenderViewHost(
181 RenderViewHost* render_view_host) {
182 render_view_host_ = render_view_host;
[email protected]ce0e2602013-03-15 20:53:27183 tracker_.reset(render_view_host ? new RenderViewHostTracker(this) : NULL);
[email protected]a2aef2e2011-05-26 22:48:12184}
185
[email protected]b51f35622012-05-05 22:01:43186// TODO(stevenjb): Replace this with GetExtensionWindowController().
[email protected]a2aef2e2011-05-26 22:48:12187Browser* UIThreadExtensionFunction::GetCurrentBrowser() {
[email protected]b51f35622012-05-05 22:01:43188 // If the delegate has an associated browser, return it.
[email protected]3d6ac9e2012-07-20 23:12:31189 if (dispatcher()) {
190 extensions::WindowController* window_controller =
191 dispatcher()->delegate()->GetExtensionWindowController();
192 if (window_controller) {
193 Browser* browser = window_controller->GetBrowser();
194 if (browser)
195 return browser;
196 }
[email protected]b51f35622012-05-05 22:01:43197 }
198
199 // Otherwise, try to default to a reasonable browser. If |include_incognito_|
200 // is true, we will also search browsers in the incognito version of this
201 // profile. Note that the profile may already be incognito, in which case
202 // we will search the incognito version only, regardless of the value of
[email protected]7f4a1d242012-12-05 05:55:57203 // |include_incognito|. Look only for browsers on the active desktop as it is
204 // preferable to pretend no browser is open then to return a browser on
205 // another desktop.
[email protected]7a689f02012-10-31 21:26:18206 if (render_view_host_) {
207 Profile* profile = Profile::FromBrowserContext(
208 render_view_host_->GetProcess()->GetBrowserContext());
[email protected]3c6a0952012-12-17 11:56:09209 Browser* browser = chrome::FindAnyBrowser(profile, include_incognito_,
210 chrome::GetActiveDesktop());
[email protected]7a689f02012-10-31 21:26:18211 if (browser)
212 return browser;
213 }
[email protected]b51f35622012-05-05 22:01:43214
215 // NOTE(rafaelw): This can return NULL in some circumstances. In particular,
216 // a background_page onload chrome.tabs api call can make it into here
[email protected]7a689f02012-10-31 21:26:18217 // before the browser is sufficiently initialized to return here, or
218 // all of this profile's browser windows may have been closed.
[email protected]b51f35622012-05-05 22:01:43219 // A similar situation may arise during shutdown.
220 // TODO(rafaelw): Delay creation of background_page until the browser
221 // is available. http://code.google.com/p/chromium/issues/detail?id=13284
[email protected]7a689f02012-10-31 21:26:18222 return NULL;
[email protected]b51f35622012-05-05 22:01:43223}
224
[email protected]91e51d612012-10-21 23:03:05225content::WebContents* UIThreadExtensionFunction::GetAssociatedWebContents() {
226 if (dispatcher()) {
227 content::WebContents* web_contents =
228 dispatcher()->delegate()->GetAssociatedWebContents();
229 if (web_contents)
230 return web_contents;
231 }
232
233 Browser* browser = GetCurrentBrowser();
234 if (!browser)
235 return NULL;
236 return browser->tab_strip_model()->GetActiveWebContents();
237}
238
[email protected]44f4b132012-07-17 20:36:57239extensions::WindowController*
[email protected]b51f35622012-05-05 22:01:43240UIThreadExtensionFunction::GetExtensionWindowController() {
241 // If the delegate has an associated window controller, return it.
[email protected]3d6ac9e2012-07-20 23:12:31242 if (dispatcher()) {
243 extensions::WindowController* window_controller =
244 dispatcher()->delegate()->GetExtensionWindowController();
245 if (window_controller)
246 return window_controller;
247 }
[email protected]b51f35622012-05-05 22:01:43248
[email protected]44f4b132012-07-17 20:36:57249 return extensions::WindowControllerList::GetInstance()->
250 CurrentWindowForFunction(this);
[email protected]31bdbfef2012-05-22 19:59:15251}
252
253bool UIThreadExtensionFunction::CanOperateOnWindow(
[email protected]44f4b132012-07-17 20:36:57254 const extensions::WindowController* window_controller) const {
[email protected]31bdbfef2012-05-22 19:59:15255 const extensions::Extension* extension = GetExtension();
256 // |extension| is NULL for unit tests only.
257 if (extension != NULL && !window_controller->IsVisibleToExtension(extension))
258 return false;
259
260 if (profile() == window_controller->profile())
261 return true;
262
263 if (!include_incognito())
264 return false;
265
266 return profile()->HasOffTheRecordProfile() &&
267 profile()->GetOffTheRecordProfile() == window_controller->profile();
[email protected]a2aef2e2011-05-26 22:48:12268}
269
270void UIThreadExtensionFunction::SendResponse(bool success) {
[email protected]bdfc03e2011-11-22 00:20:33271 if (delegate_) {
[email protected]ca6df682012-04-10 23:00:20272 delegate_->OnSendResponse(this, success, bad_message_);
[email protected]bdfc03e2011-11-22 00:20:33273 } else {
274 if (!render_view_host_ || !dispatcher())
275 return;
[email protected]c5dbef02011-05-13 05:06:09276
[email protected]9f76c1e2012-03-05 15:15:58277 SendResponseImpl(render_view_host_->GetProcess()->GetHandle(),
[email protected]bdfc03e2011-11-22 00:20:33278 render_view_host_,
[email protected]74e21e72012-07-09 21:20:53279 render_view_host_->GetRoutingID(),
[email protected]bdfc03e2011-11-22 00:20:33280 success);
281 }
[email protected]c5dbef02011-05-13 05:06:09282}
283
[email protected]c6970072013-01-10 02:59:43284void UIThreadExtensionFunction::WriteToConsole(
285 content::ConsoleMessageLevel level,
286 const std::string& message) {
287 render_view_host_->Send(new ExtensionMsg_AddMessageToConsole(
288 render_view_host_->GetRoutingID(), level, message));
289}
290
[email protected]74e21e72012-07-09 21:20:53291IOThreadExtensionFunction::IOThreadExtensionFunction()
292 : routing_id_(-1) {
[email protected]c357acb42011-06-09 20:52:42293}
294
295IOThreadExtensionFunction::~IOThreadExtensionFunction() {
296}
297
298IOThreadExtensionFunction*
299IOThreadExtensionFunction::AsIOThreadExtensionFunction() {
300 return this;
301}
302
303void IOThreadExtensionFunction::Destruct() const {
304 BrowserThread::DeleteOnIOThread::Destruct(this);
305}
306
307void IOThreadExtensionFunction::SendResponse(bool success) {
308 if (!ipc_sender())
309 return;
310
[email protected]74e21e72012-07-09 21:20:53311 SendResponseImpl(ipc_sender()->peer_handle(),
312 ipc_sender(), routing_id_, success);
[email protected]703e807a2009-03-28 19:56:51313}
[email protected]73404a372009-04-17 23:09:10314
[email protected]bdfc03e2011-11-22 00:20:33315AsyncExtensionFunction::AsyncExtensionFunction() {
[email protected]a2aef2e2011-05-26 22:48:12316}
317
318AsyncExtensionFunction::~AsyncExtensionFunction() {
[email protected]35213ce92010-04-08 19:06:15319}
[email protected]3a3d47472010-07-15 21:03:54320
321SyncExtensionFunction::SyncExtensionFunction() {
322}
323
324SyncExtensionFunction::~SyncExtensionFunction() {
325}
326
327void SyncExtensionFunction::Run() {
328 SendResponse(RunImpl());
329}
[email protected]c357acb42011-06-09 20:52:42330
331SyncIOThreadExtensionFunction::SyncIOThreadExtensionFunction() {
332}
333
334SyncIOThreadExtensionFunction::~SyncIOThreadExtensionFunction() {
335}
336
337void SyncIOThreadExtensionFunction::Run() {
338 SendResponse(RunImpl());
339}