1 // Copyright (c) 2012 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. 4 5 #include "chrome/browser/extensions/extension_function.h" 6 7 #include "base/logging.h" 8 #include "base/metrics/histogram.h" 9 #include "chrome/browser/extensions/extension_function_dispatcher.h" 10 #include "chrome/browser/extensions/extension_service.h" 11 #include "chrome/browser/extensions/window_controller.h" 12 #include "chrome/browser/extensions/window_controller_list.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" 15 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/browser_finder.h" 17 #include "chrome/browser/ui/tabs/tab_strip_model.h" 18 #include "chrome/common/extensions/api/extension_api.h" 19 #include "chrome/common/extensions/extension_messages.h" 20 #include "content/public/browser/notification_source.h" 21 #include "content/public/browser/notification_types.h" 22 #include "content/public/browser/render_process_host.h" 23 #include "content/public/browser/render_view_host.h" 24 25 using content::BrowserThread; 26 using content::RenderViewHost; 27 using extensions::ExtensionAPI; 28 using extensions::Feature; 29 30 // static 31 void ExtensionFunctionDeleteTraits::Destruct(const ExtensionFunction* x) { 32 x->Destruct(); 33 } 34 35 UIThreadExtensionFunction::RenderViewHostTracker::RenderViewHostTracker( 36 UIThreadExtensionFunction* function) 37 : content::RenderViewHostObserver(function->render_view_host()), 38 function_(function) { 39 } 40 41 void UIThreadExtensionFunction::RenderViewHostTracker::RenderViewHostDestroyed( 42 RenderViewHost* render_view_host) { 43 // Overidding the default behavior of RenderViewHostObserver which is to 44 // delete this. In our case, we'll be deleted when the 45 // UIThreadExtensionFunction that contains us goes away. 46 47 function_->SetRenderViewHost(NULL); 48 } 49 50 bool UIThreadExtensionFunction::RenderViewHostTracker::OnMessageReceived( 51 const IPC::Message& message) { 52 return function_->OnMessageReceivedFromRenderView(message); 53 } 54 55 ExtensionFunction::ExtensionFunction() 56 : request_id_(-1), 57 profile_id_(NULL), 58 has_callback_(false), 59 include_incognito_(false), 60 user_gesture_(false), 61 bad_message_(false), 62 histogram_value_(extensions::functions::UNKNOWN) {} 63 64 ExtensionFunction::~ExtensionFunction() { 65 } 66 67 UIThreadExtensionFunction* ExtensionFunction::AsUIThreadExtensionFunction() { 68 return NULL; 69 } 70 71 IOThreadExtensionFunction* ExtensionFunction::AsIOThreadExtensionFunction() { 72 return NULL; 73 } 74 75 bool ExtensionFunction::HasPermission() { 76 Feature::Availability availability = 77 ExtensionAPI::GetSharedInstance()->IsAvailable( 78 name_, extension_, Feature::BLESSED_EXTENSION_CONTEXT, source_url()); 79 return availability.is_available(); 80 } 81 82 void ExtensionFunction::OnQuotaExceeded(const std::string& violation_error) { 83 error_ = violation_error; 84 SendResponse(false); 85 } 86 87 void ExtensionFunction::SetArgs(const base::ListValue* args) { 88 DCHECK(!args_.get()); // Should only be called once. 89 args_.reset(args->DeepCopy()); 90 } 91 92 void ExtensionFunction::SetResult(base::Value* result) { 93 results_.reset(new base::ListValue()); 94 results_->Append(result); 95 } 96 97 const base::ListValue* ExtensionFunction::GetResultList() { 98 return results_.get(); 99 } 100 101 const std::string ExtensionFunction::GetError() { 102 return error_; 103 } 104 105 void ExtensionFunction::SetError(const std::string& error) { 106 error_ = error; 107 } 108 109 void ExtensionFunction::Run() { 110 UMA_HISTOGRAM_ENUMERATION("Extensions.FunctionCalls", histogram_value(), 111 extensions::functions::ENUM_BOUNDARY); 112 113 if (!RunImpl()) 114 SendResponse(false); 115 } 116 117 bool ExtensionFunction::ShouldSkipQuotaLimiting() const { 118 return false; 119 } 120 121 bool ExtensionFunction::HasOptionalArgument(size_t index) { 122 Value* value; 123 return args_->Get(index, &value) && !value->IsType(Value::TYPE_NULL); 124 } 125 126 void ExtensionFunction::SendResponseImpl(bool success) { 127 DCHECK(!response_callback_.is_null()); 128 129 ResponseType type = success ? SUCCEEDED : FAILED; 130 if (bad_message_) { 131 type = BAD_MESSAGE; 132 LOG(ERROR) << "Bad extension message " << name_; 133 } 134 135 // If results were never set, we send an empty argument list. 136 if (!results_) 137 results_.reset(new base::ListValue()); 138 139 response_callback_.Run(type, *results_, GetError()); 140 } 141 142 UIThreadExtensionFunction::UIThreadExtensionFunction() 143 : render_view_host_(NULL), 144 profile_(NULL), 145 delegate_(NULL) { 146 } 147 148 UIThreadExtensionFunction::~UIThreadExtensionFunction() { 149 if (dispatcher() && render_view_host()) 150 dispatcher()->OnExtensionFunctionCompleted(GetExtension()); 151 } 152 153 UIThreadExtensionFunction* 154 UIThreadExtensionFunction::AsUIThreadExtensionFunction() { 155 return this; 156 } 157 158 bool UIThreadExtensionFunction::OnMessageReceivedFromRenderView( 159 const IPC::Message& message) { 160 return false; 161 } 162 163 void UIThreadExtensionFunction::Destruct() const { 164 BrowserThread::DeleteOnUIThread::Destruct(this); 165 } 166 167 void UIThreadExtensionFunction::SetRenderViewHost( 168 RenderViewHost* render_view_host) { 169 render_view_host_ = render_view_host; 170 tracker_.reset(render_view_host ? new RenderViewHostTracker(this) : NULL); 171 } 172 173 // TODO(stevenjb): Replace this with GetExtensionWindowController(). 174 Browser* UIThreadExtensionFunction::GetCurrentBrowser() { 175 // If the delegate has an associated browser, return it. 176 if (dispatcher()) { 177 extensions::WindowController* window_controller = 178 dispatcher()->delegate()->GetExtensionWindowController(); 179 if (window_controller) { 180 Browser* browser = window_controller->GetBrowser(); 181 if (browser) 182 return browser; 183 } 184 } 185 186 // Otherwise, try to default to a reasonable browser. If |include_incognito_| 187 // is true, we will also search browsers in the incognito version of this 188 // profile. Note that the profile may already be incognito, in which case 189 // we will search the incognito version only, regardless of the value of 190 // |include_incognito|. Look only for browsers on the active desktop as it is 191 // preferable to pretend no browser is open then to return a browser on 192 // another desktop. 193 if (render_view_host_) { 194 Profile* profile = Profile::FromBrowserContext( 195 render_view_host_->GetProcess()->GetBrowserContext()); 196 Browser* browser = chrome::FindAnyBrowser(profile, include_incognito_, 197 chrome::GetActiveDesktop()); 198 if (browser) 199 return browser; 200 } 201 202 // NOTE(rafaelw): This can return NULL in some circumstances. In particular, 203 // a background_page onload chrome.tabs api call can make it into here 204 // before the browser is sufficiently initialized to return here, or 205 // all of this profile's browser windows may have been closed. 206 // A similar situation may arise during shutdown. 207 // TODO(rafaelw): Delay creation of background_page until the browser 208 // is available. http://code.google.com/p/chromium/issues/detail?id=13284 209 return NULL; 210 } 211 212 content::WebContents* UIThreadExtensionFunction::GetAssociatedWebContents() { 213 if (dispatcher()) { 214 content::WebContents* web_contents = 215 dispatcher()->delegate()->GetAssociatedWebContents(); 216 if (web_contents) 217 return web_contents; 218 } 219 220 Browser* browser = GetCurrentBrowser(); 221 if (!browser) 222 return NULL; 223 return browser->tab_strip_model()->GetActiveWebContents(); 224 } 225 226 extensions::WindowController* 227 UIThreadExtensionFunction::GetExtensionWindowController() { 228 // If the delegate has an associated window controller, return it. 229 if (dispatcher()) { 230 extensions::WindowController* window_controller = 231 dispatcher()->delegate()->GetExtensionWindowController(); 232 if (window_controller) 233 return window_controller; 234 } 235 236 return extensions::WindowControllerList::GetInstance()-> 237 CurrentWindowForFunction(this); 238 } 239 240 bool UIThreadExtensionFunction::CanOperateOnWindow( 241 const extensions::WindowController* window_controller) const { 242 const extensions::Extension* extension = GetExtension(); 243 // |extension| is NULL for unit tests only. 244 if (extension != NULL && !window_controller->IsVisibleToExtension(extension)) 245 return false; 246 247 if (profile() == window_controller->profile()) 248 return true; 249 250 if (!include_incognito()) 251 return false; 252 253 return profile()->HasOffTheRecordProfile() && 254 profile()->GetOffTheRecordProfile() == window_controller->profile(); 255 } 256 257 void UIThreadExtensionFunction::SendResponse(bool success) { 258 if (delegate_) 259 delegate_->OnSendResponse(this, success, bad_message_); 260 else 261 SendResponseImpl(success); 262 } 263 264 void UIThreadExtensionFunction::WriteToConsole( 265 content::ConsoleMessageLevel level, 266 const std::string& message) { 267 render_view_host_->Send(new ExtensionMsg_AddMessageToConsole( 268 render_view_host_->GetRoutingID(), level, message)); 269 } 270 271 IOThreadExtensionFunction::IOThreadExtensionFunction() 272 : routing_id_(MSG_ROUTING_NONE) { 273 } 274 275 IOThreadExtensionFunction::~IOThreadExtensionFunction() { 276 } 277 278 IOThreadExtensionFunction* 279 IOThreadExtensionFunction::AsIOThreadExtensionFunction() { 280 return this; 281 } 282 283 void IOThreadExtensionFunction::Destruct() const { 284 BrowserThread::DeleteOnIOThread::Destruct(this); 285 } 286 287 void IOThreadExtensionFunction::SendResponse(bool success) { 288 SendResponseImpl(success); 289 } 290 291 AsyncExtensionFunction::AsyncExtensionFunction() { 292 } 293 294 AsyncExtensionFunction::~AsyncExtensionFunction() { 295 } 296 297 SyncExtensionFunction::SyncExtensionFunction() { 298 } 299 300 SyncExtensionFunction::~SyncExtensionFunction() { 301 } 302 303 void SyncExtensionFunction::Run() { 304 SendResponse(RunImpl()); 305 } 306 307 SyncIOThreadExtensionFunction::SyncIOThreadExtensionFunction() { 308 } 309 310 SyncIOThreadExtensionFunction::~SyncIOThreadExtensionFunction() { 311 } 312 313 void SyncIOThreadExtensionFunction::Run() { 314 SendResponse(RunImpl()); 315 } 316