| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/extension_function_dispatcher.h" | 5 #include "chrome/browser/extensions/extension_function_dispatcher.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/json/json_string_value_serializer.h" | 8 #include "base/json/json_string_value_serializer.h" |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/process/process.h" | 12 #include "base/process/process.h" |
| 13 #include "base/values.h" | 13 #include "base/values.h" |
| 14 #include "build/build_config.h" | 14 #include "build/build_config.h" |
| 15 #include "chrome/browser/extensions/activity_log/activity_action_constants.h" | 15 #include "chrome/browser/extensions/activity_log/activity_action_constants.h" |
| 16 #include "chrome/browser/extensions/activity_log/activity_log.h" | 16 #include "chrome/browser/extensions/activity_log/activity_log.h" |
| 17 #include "chrome/browser/extensions/api/activity_log_private/activity_log_privat
e_api.h" | 17 #include "chrome/browser/extensions/api/activity_log_private/activity_log_privat
e_api.h" |
| 18 #include "chrome/browser/extensions/extension_function_registry.h" | 18 #include "chrome/browser/extensions/extension_function_registry.h" |
| 19 #include "chrome/browser/extensions/extension_service.h" | 19 #include "chrome/browser/extensions/extension_service.h" |
| 20 #include "chrome/browser/extensions/extension_system.h" | 20 #include "chrome/browser/extensions/extension_system.h" |
| 21 #include "chrome/browser/extensions/extension_util.h" | 21 #include "chrome/browser/extensions/extension_util.h" |
| 22 #include "chrome/browser/extensions/extension_web_ui.h" | 22 #include "chrome/browser/extensions/extension_web_ui.h" |
| 23 #include "chrome/browser/external_protocol/external_protocol_handler.h" | 23 #include "chrome/browser/external_protocol/external_protocol_handler.h" |
| 24 #include "chrome/browser/profiles/profile.h" | |
| 25 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" | 24 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
| 26 #include "chrome/common/extensions/extension_messages.h" | 25 #include "chrome/common/extensions/extension_messages.h" |
| 27 #include "chrome/common/extensions/extension_set.h" | 26 #include "chrome/common/extensions/extension_set.h" |
| 28 #include "chrome/common/url_constants.h" | 27 #include "chrome/common/url_constants.h" |
| 29 #include "content/public/browser/browser_thread.h" | 28 #include "content/public/browser/browser_thread.h" |
| 30 #include "content/public/browser/render_process_host.h" | 29 #include "content/public/browser/render_process_host.h" |
| 31 #include "content/public/browser/render_view_host.h" | 30 #include "content/public/browser/render_view_host.h" |
| 32 #include "content/public/browser/user_metrics.h" | 31 #include "content/public/browser/user_metrics.h" |
| 33 #include "content/public/browser/web_contents.h" | 32 #include "content/public/browser/web_contents.h" |
| 34 #include "content/public/browser/web_contents_observer.h" | 33 #include "content/public/browser/web_contents_observer.h" |
| 35 #include "content/public/common/result_codes.h" | 34 #include "content/public/common/result_codes.h" |
| 36 #include "extensions/browser/process_map.h" | 35 #include "extensions/browser/process_map.h" |
| 37 #include "extensions/browser/quota_service.h" | 36 #include "extensions/browser/quota_service.h" |
| 38 #include "extensions/common/extension_api.h" | 37 #include "extensions/common/extension_api.h" |
| 39 #include "ipc/ipc_message.h" | 38 #include "ipc/ipc_message.h" |
| 40 #include "ipc/ipc_message_macros.h" | 39 #include "ipc/ipc_message_macros.h" |
| 41 #include "webkit/common/resource_type.h" | 40 #include "webkit/common/resource_type.h" |
| 42 | 41 |
| 43 using extensions::Extension; | 42 using extensions::Extension; |
| 44 using extensions::ExtensionAPI; | 43 using extensions::ExtensionAPI; |
| 44 using extensions::ExtensionSystem; |
| 45 using extensions::Feature; | 45 using extensions::Feature; |
| 46 using content::RenderViewHost; | 46 using content::RenderViewHost; |
| 47 | 47 |
| 48 namespace { | 48 namespace { |
| 49 | 49 |
| 50 void LogSuccess(const std::string& extension_id, | 50 void LogSuccess(const std::string& extension_id, |
| 51 const std::string& api_name, | 51 const std::string& api_name, |
| 52 scoped_ptr<base::ListValue> args, | 52 scoped_ptr<base::ListValue> args, |
| 53 Profile* profile) { | 53 content::BrowserContext* browser_context) { |
| 54 // The ActivityLog can only be accessed from the main (UI) thread. If we're | 54 // The ActivityLog can only be accessed from the main (UI) thread. If we're |
| 55 // running on the wrong thread, re-dispatch from the main thread. | 55 // running on the wrong thread, re-dispatch from the main thread. |
| 56 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 56 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 57 BrowserThread::PostTask(BrowserThread::UI, | 57 BrowserThread::PostTask(BrowserThread::UI, |
| 58 FROM_HERE, | 58 FROM_HERE, |
| 59 base::Bind(&LogSuccess, | 59 base::Bind(&LogSuccess, |
| 60 extension_id, | 60 extension_id, |
| 61 api_name, | 61 api_name, |
| 62 base::Passed(&args), | 62 base::Passed(&args), |
| 63 profile)); | 63 browser_context)); |
| 64 } else { | 64 } else { |
| 65 extensions::ActivityLog* activity_log = | 65 extensions::ActivityLog* activity_log = |
| 66 extensions::ActivityLog::GetInstance(profile); | 66 extensions::ActivityLog::GetInstance(browser_context); |
| 67 scoped_refptr<extensions::Action> action = | 67 scoped_refptr<extensions::Action> action = |
| 68 new extensions::Action(extension_id, | 68 new extensions::Action(extension_id, |
| 69 base::Time::Now(), | 69 base::Time::Now(), |
| 70 extensions::Action::ACTION_API_CALL, | 70 extensions::Action::ACTION_API_CALL, |
| 71 api_name); | 71 api_name); |
| 72 action->set_args(args.Pass()); | 72 action->set_args(args.Pass()); |
| 73 activity_log->LogAction(action); | 73 activity_log->LogAction(action); |
| 74 } | 74 } |
| 75 } | 75 } |
| 76 | 76 |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 factory); | 228 factory); |
| 229 } | 229 } |
| 230 | 230 |
| 231 void ExtensionFunctionDispatcher::ResetFunctions() { | 231 void ExtensionFunctionDispatcher::ResetFunctions() { |
| 232 ExtensionFunctionRegistry::GetInstance()->ResetFunctions(); | 232 ExtensionFunctionRegistry::GetInstance()->ResetFunctions(); |
| 233 } | 233 } |
| 234 | 234 |
| 235 // static | 235 // static |
| 236 void ExtensionFunctionDispatcher::DispatchOnIOThread( | 236 void ExtensionFunctionDispatcher::DispatchOnIOThread( |
| 237 extensions::InfoMap* extension_info_map, | 237 extensions::InfoMap* extension_info_map, |
| 238 void* profile, | 238 void* browser_context, |
| 239 int render_process_id, | 239 int render_process_id, |
| 240 base::WeakPtr<ChromeRenderMessageFilter> ipc_sender, | 240 base::WeakPtr<ChromeRenderMessageFilter> ipc_sender, |
| 241 int routing_id, | 241 int routing_id, |
| 242 const ExtensionHostMsg_Request_Params& params) { | 242 const ExtensionHostMsg_Request_Params& params) { |
| 243 const Extension* extension = | 243 const Extension* extension = |
| 244 extension_info_map->extensions().GetByID(params.extension_id); | 244 extension_info_map->extensions().GetByID(params.extension_id); |
| 245 Profile* profile_cast = static_cast<Profile*>(profile); | |
| 246 | 245 |
| 247 ExtensionFunction::ResponseCallback callback( | 246 ExtensionFunction::ResponseCallback callback( |
| 248 base::Bind(&IOThreadResponseCallback, ipc_sender, routing_id, | 247 base::Bind(&IOThreadResponseCallback, ipc_sender, routing_id, |
| 249 params.request_id)); | 248 params.request_id)); |
| 250 | 249 |
| 251 scoped_refptr<ExtensionFunction> function( | 250 scoped_refptr<ExtensionFunction> function( |
| 252 CreateExtensionFunction(params, extension, render_process_id, | 251 CreateExtensionFunction(params, extension, render_process_id, |
| 253 extension_info_map->process_map(), | 252 extension_info_map->process_map(), |
| 254 g_global_io_data.Get().api.get(), | 253 g_global_io_data.Get().api.get(), |
| 255 profile, callback)); | 254 browser_context, callback)); |
| 256 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); | 255 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); |
| 257 | 256 |
| 258 if (!function.get()) | 257 if (!function.get()) |
| 259 return; | 258 return; |
| 260 | 259 |
| 261 IOThreadExtensionFunction* function_io = | 260 IOThreadExtensionFunction* function_io = |
| 262 function->AsIOThreadExtensionFunction(); | 261 function->AsIOThreadExtensionFunction(); |
| 263 if (!function_io) { | 262 if (!function_io) { |
| 264 NOTREACHED(); | 263 NOTREACHED(); |
| 265 return; | 264 return; |
| 266 } | 265 } |
| 267 function_io->set_ipc_sender(ipc_sender, routing_id); | 266 function_io->set_ipc_sender(ipc_sender, routing_id); |
| 268 function_io->set_extension_info_map(extension_info_map); | 267 function_io->set_extension_info_map(extension_info_map); |
| 269 function->set_include_incognito( | 268 function->set_include_incognito( |
| 270 extension_info_map->IsIncognitoEnabled(extension->id())); | 269 extension_info_map->IsIncognitoEnabled(extension->id())); |
| 271 | 270 |
| 272 if (!CheckPermissions(function.get(), extension, params, callback)) | 271 if (!CheckPermissions(function.get(), extension, params, callback)) |
| 273 return; | 272 return; |
| 274 | 273 |
| 275 extensions::QuotaService* quota = extension_info_map->GetQuotaService(); | 274 extensions::QuotaService* quota = extension_info_map->GetQuotaService(); |
| 276 std::string violation_error = quota->Assess(extension->id(), | 275 std::string violation_error = quota->Assess(extension->id(), |
| 277 function.get(), | 276 function.get(), |
| 278 ¶ms.arguments, | 277 ¶ms.arguments, |
| 279 base::TimeTicks::Now()); | 278 base::TimeTicks::Now()); |
| 280 if (violation_error.empty()) { | 279 if (violation_error.empty()) { |
| 281 LogSuccess(extension->id(), | 280 LogSuccess(extension->id(), |
| 282 params.name, | 281 params.name, |
| 283 args.Pass(), | 282 args.Pass(), |
| 284 profile_cast); | 283 static_cast<content::BrowserContext*>(browser_context)); |
| 285 function->Run(); | 284 function->Run(); |
| 286 } else { | 285 } else { |
| 287 function->OnQuotaExceeded(violation_error); | 286 function->OnQuotaExceeded(violation_error); |
| 288 } | 287 } |
| 289 } | 288 } |
| 290 | 289 |
| 291 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( | 290 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( |
| 292 content::BrowserContext* browser_context, | 291 content::BrowserContext* browser_context, |
| 293 Delegate* delegate) | 292 Delegate* delegate) |
| 294 : profile_(Profile::FromBrowserContext(browser_context)), | 293 : browser_context_(browser_context), |
| 295 delegate_(delegate) { | 294 delegate_(delegate) { |
| 296 } | 295 } |
| 297 | 296 |
| 298 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { | 297 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { |
| 299 } | 298 } |
| 300 | 299 |
| 301 void ExtensionFunctionDispatcher::Dispatch( | 300 void ExtensionFunctionDispatcher::Dispatch( |
| 302 const ExtensionHostMsg_Request_Params& params, | 301 const ExtensionHostMsg_Request_Params& params, |
| 303 RenderViewHost* render_view_host) { | 302 RenderViewHost* render_view_host) { |
| 304 UIThreadResponseCallbackWrapperMap::const_iterator | 303 UIThreadResponseCallbackWrapperMap::const_iterator |
| (...skipping 10 matching lines...) Expand all Loading... |
| 315 DispatchWithCallback(params, render_view_host, | 314 DispatchWithCallback(params, render_view_host, |
| 316 callback_wrapper->CreateCallback(params.request_id)); | 315 callback_wrapper->CreateCallback(params.request_id)); |
| 317 } | 316 } |
| 318 | 317 |
| 319 void ExtensionFunctionDispatcher::DispatchWithCallback( | 318 void ExtensionFunctionDispatcher::DispatchWithCallback( |
| 320 const ExtensionHostMsg_Request_Params& params, | 319 const ExtensionHostMsg_Request_Params& params, |
| 321 RenderViewHost* render_view_host, | 320 RenderViewHost* render_view_host, |
| 322 const ExtensionFunction::ResponseCallback& callback) { | 321 const ExtensionFunction::ResponseCallback& callback) { |
| 323 // TODO(yzshen): There is some shared logic between this method and | 322 // TODO(yzshen): There is some shared logic between this method and |
| 324 // DispatchOnIOThread(). It is nice to deduplicate. | 323 // DispatchOnIOThread(). It is nice to deduplicate. |
| 325 ExtensionService* service = profile()->GetExtensionService(); | 324 ExtensionSystem* extension_system = |
| 326 extensions::ProcessManager* process_manager = | 325 ExtensionSystem::GetForBrowserContext(browser_context_); |
| 327 extensions::ExtensionSystem::Get(profile())->process_manager(); | 326 ExtensionService* service = extension_system->extension_service(); |
| 328 extensions::ProcessMap* process_map = service->process_map(); | 327 extensions::ProcessMap* process_map = service->process_map(); |
| 329 if (!service || !process_map) | 328 if (!process_map) |
| 330 return; | 329 return; |
| 331 | 330 |
| 332 const Extension* extension = service->extensions()->GetByID( | 331 const Extension* extension = service->extensions()->GetByID( |
| 333 params.extension_id); | 332 params.extension_id); |
| 334 if (!extension) | 333 if (!extension) |
| 335 extension = service->extensions()->GetHostedAppByURL(params.source_url); | 334 extension = service->extensions()->GetHostedAppByURL(params.source_url); |
| 336 | 335 |
| 337 scoped_refptr<ExtensionFunction> function( | 336 scoped_refptr<ExtensionFunction> function( |
| 338 CreateExtensionFunction(params, extension, | 337 CreateExtensionFunction(params, |
| 338 extension, |
| 339 render_view_host->GetProcess()->GetID(), | 339 render_view_host->GetProcess()->GetID(), |
| 340 *(service->process_map()), | 340 *process_map, |
| 341 extensions::ExtensionAPI::GetSharedInstance(), | 341 extensions::ExtensionAPI::GetSharedInstance(), |
| 342 profile(), callback)); | 342 browser_context_, |
| 343 callback)); |
| 343 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); | 344 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); |
| 344 | 345 |
| 345 if (!function.get()) | 346 if (!function.get()) |
| 346 return; | 347 return; |
| 347 | 348 |
| 348 UIThreadExtensionFunction* function_ui = | 349 UIThreadExtensionFunction* function_ui = |
| 349 function->AsUIThreadExtensionFunction(); | 350 function->AsUIThreadExtensionFunction(); |
| 350 if (!function_ui) { | 351 if (!function_ui) { |
| 351 NOTREACHED(); | 352 NOTREACHED(); |
| 352 return; | 353 return; |
| 353 } | 354 } |
| 354 function_ui->SetRenderViewHost(render_view_host); | 355 function_ui->SetRenderViewHost(render_view_host); |
| 355 function_ui->set_dispatcher(AsWeakPtr()); | 356 function_ui->set_dispatcher(AsWeakPtr()); |
| 356 function_ui->set_context(profile_); | 357 function_ui->set_context(browser_context_); |
| 357 function->set_include_incognito(extension_util::CanCrossIncognito(extension, | 358 function->set_include_incognito(extension_util::CanCrossIncognito(extension, |
| 358 service)); | 359 service)); |
| 359 | 360 |
| 360 if (!CheckPermissions(function.get(), extension, params, callback)) | 361 if (!CheckPermissions(function.get(), extension, params, callback)) |
| 361 return; | 362 return; |
| 362 | 363 |
| 363 extensions::QuotaService* quota = service->quota_service(); | 364 extensions::QuotaService* quota = service->quota_service(); |
| 364 std::string violation_error = quota->Assess(extension->id(), | 365 std::string violation_error = quota->Assess(extension->id(), |
| 365 function.get(), | 366 function.get(), |
| 366 ¶ms.arguments, | 367 ¶ms.arguments, |
| 367 base::TimeTicks::Now()); | 368 base::TimeTicks::Now()); |
| 368 if (violation_error.empty()) { | 369 if (violation_error.empty()) { |
| 369 // See crbug.com/39178. | 370 // See crbug.com/39178. |
| 370 ExternalProtocolHandler::PermitLaunchUrl(); | 371 ExternalProtocolHandler::PermitLaunchUrl(); |
| 371 LogSuccess(extension->id(), params.name, args.Pass(), profile()); | 372 LogSuccess(extension->id(), params.name, args.Pass(), browser_context_); |
| 372 function->Run(); | 373 function->Run(); |
| 373 } else { | 374 } else { |
| 374 function->OnQuotaExceeded(violation_error); | 375 function->OnQuotaExceeded(violation_error); |
| 375 } | 376 } |
| 376 | 377 |
| 377 // Note: do not access |this| after this point. We may have been deleted | 378 // Note: do not access |this| after this point. We may have been deleted |
| 378 // if function->Run() ended up closing the tab that owns us. | 379 // if function->Run() ended up closing the tab that owns us. |
| 379 | 380 |
| 380 // Check if extension was uninstalled by management.uninstall. | 381 // Check if extension was uninstalled by management.uninstall. |
| 381 if (!service->extensions()->GetByID(params.extension_id)) | 382 if (!service->extensions()->GetByID(params.extension_id)) |
| 382 return; | 383 return; |
| 383 | 384 |
| 384 // We only adjust the keepalive count for UIThreadExtensionFunction for | 385 // We only adjust the keepalive count for UIThreadExtensionFunction for |
| 385 // now, largely for simplicity's sake. This is OK because currently, only | 386 // now, largely for simplicity's sake. This is OK because currently, only |
| 386 // the webRequest API uses IOThreadExtensionFunction, and that API is not | 387 // the webRequest API uses IOThreadExtensionFunction, and that API is not |
| 387 // compatible with lazy background pages. | 388 // compatible with lazy background pages. |
| 388 process_manager->IncrementLazyKeepaliveCount(extension); | 389 extension_system->process_manager()->IncrementLazyKeepaliveCount(extension); |
| 389 } | 390 } |
| 390 | 391 |
| 391 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted( | 392 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted( |
| 392 const Extension* extension) { | 393 const Extension* extension) { |
| 393 extensions::ExtensionSystem::Get(profile())->process_manager()-> | 394 ExtensionSystem::GetForBrowserContext(browser_context_)->process_manager()-> |
| 394 DecrementLazyKeepaliveCount(extension); | 395 DecrementLazyKeepaliveCount(extension); |
| 395 } | 396 } |
| 396 | 397 |
| 397 // static | 398 // static |
| 398 bool ExtensionFunctionDispatcher::CheckPermissions( | 399 bool ExtensionFunctionDispatcher::CheckPermissions( |
| 399 ExtensionFunction* function, | 400 ExtensionFunction* function, |
| 400 const Extension* extension, | 401 const Extension* extension, |
| 401 const ExtensionHostMsg_Request_Params& params, | 402 const ExtensionHostMsg_Request_Params& params, |
| 402 const ExtensionFunction::ResponseCallback& callback) { | 403 const ExtensionFunction::ResponseCallback& callback) { |
| 403 if (!function->HasPermission()) { | 404 if (!function->HasPermission()) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 489 return function; | 490 return function; |
| 490 } | 491 } |
| 491 | 492 |
| 492 // static | 493 // static |
| 493 void ExtensionFunctionDispatcher::SendAccessDenied( | 494 void ExtensionFunctionDispatcher::SendAccessDenied( |
| 494 const ExtensionFunction::ResponseCallback& callback) { | 495 const ExtensionFunction::ResponseCallback& callback) { |
| 495 ListValue empty_list; | 496 ListValue empty_list; |
| 496 callback.Run(ExtensionFunction::FAILED, empty_list, | 497 callback.Run(ExtensionFunction::FAILED, empty_list, |
| 497 "Access to extension API denied."); | 498 "Access to extension API denied."); |
| 498 } | 499 } |
| OLD | NEW |