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/api/management/management_api.h" 6 7 #include <map> 8 #include <string> 9 #include <vector> 10 11 #include "base/basictypes.h" 12 #include "base/bind.h" 13 #include "base/json/json_writer.h" 14 #include "base/lazy_instance.h" 15 #include "base/memory/linked_ptr.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/metrics/histogram.h" 18 #include "base/strings/string_number_conversions.h" 19 #include "base/strings/string_util.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "chrome/browser/chrome_notification_types.h" 22 #include "chrome/browser/extensions/api/management/management_api_constants.h" 23 #include "chrome/browser/extensions/event_names.h" 24 #include "chrome/browser/extensions/event_router.h" 25 #include "chrome/browser/extensions/extension_service.h" 26 #include "chrome/browser/extensions/extension_system.h" 27 #include "chrome/browser/extensions/extension_uninstall_dialog.h" 28 #include "chrome/browser/extensions/management_policy.h" 29 #include "chrome/browser/profiles/profile.h" 30 #include "chrome/browser/ui/extensions/application_launch.h" 31 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 32 #include "chrome/common/chrome_utility_messages.h" 33 #include "chrome/common/extensions/api/management.h" 34 #include "chrome/common/extensions/extension.h" 35 #include "chrome/common/extensions/extension_constants.h" 36 #include "chrome/common/extensions/extension_icon_set.h" 37 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 38 #include "chrome/common/extensions/manifest_handlers/icons_handler.h" 39 #include "chrome/common/extensions/manifest_handlers/offline_enabled_info.h" 40 #include "chrome/common/extensions/manifest_url_handler.h" 41 #include "chrome/common/extensions/permissions/permission_set.h" 42 #include "chrome/common/extensions/permissions/permissions_data.h" 43 #include "content/public/browser/notification_details.h" 44 #include "content/public/browser/notification_source.h" 45 #include "content/public/browser/utility_process_host.h" 46 #include "content/public/browser/utility_process_host_client.h" 47 #include "extensions/common/error_utils.h" 48 #include "extensions/common/url_pattern.h" 49 50 #if !defined(OS_ANDROID) 51 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h" 52 #endif 53 54 using base::IntToString; 55 using content::BrowserThread; 56 using content::UtilityProcessHost; 57 using content::UtilityProcessHostClient; 58 59 namespace keys = extension_management_api_constants; 60 61 namespace extensions { 62 63 namespace events = event_names; 64 namespace management = api::management; 65 66 namespace { 67 68 typedef std::vector<linked_ptr<management::ExtensionInfo> > ExtensionInfoList; 69 typedef std::vector<linked_ptr<management::IconInfo> > IconInfoList; 70 71 enum AutoConfirmForTest { 72 DO_NOT_SKIP = 0, 73 PROCEED, 74 ABORT 75 }; 76 77 AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP; 78 79 std::vector<std::string> CreateWarningsList(const Extension* extension) { 80 std::vector<std::string> warnings_list; 81 PermissionMessages warnings = 82 PermissionsData::GetPermissionMessages(extension); 83 for (PermissionMessages::const_iterator iter = warnings.begin(); 84 iter != warnings.end(); ++iter) { 85 warnings_list.push_back(UTF16ToUTF8(iter->message())); 86 } 87 88 return warnings_list; 89 } 90 91 scoped_ptr<management::ExtensionInfo> CreateExtensionInfo( 92 const Extension& extension, 93 ExtensionSystem* system) { 94 scoped_ptr<management::ExtensionInfo> info(new management::ExtensionInfo()); 95 ExtensionService* service = system->extension_service(); 96 97 info->id = extension.id(); 98 info->name = extension.name(); 99 info->enabled = service->IsExtensionEnabled(info->id); 100 info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension); 101 info->version = extension.VersionString(); 102 info->description = extension.description(); 103 info->options_url = ManifestURL::GetOptionsPage(&extension).spec(); 104 info->homepage_url.reset(new std::string( 105 ManifestURL::GetHomepageURL(&extension).spec())); 106 info->may_disable = system->management_policy()-> 107 UserMayModifySettings(&extension, NULL); 108 info->is_app = extension.is_app(); 109 if (info->is_app) { 110 if (extension.is_legacy_packaged_app()) 111 info->type = management::ExtensionInfo::TYPE_LEGACY_PACKAGED_APP; 112 else if (extension.is_hosted_app()) 113 info->type = management::ExtensionInfo::TYPE_HOSTED_APP; 114 else 115 info->type = management::ExtensionInfo::TYPE_PACKAGED_APP; 116 } else if (extension.is_theme()) { 117 info->type = management::ExtensionInfo::TYPE_THEME; 118 } else { 119 info->type = management::ExtensionInfo::TYPE_EXTENSION; 120 } 121 122 if (info->enabled) { 123 info->disabled_reason = management::ExtensionInfo::DISABLED_REASON_NONE; 124 } else { 125 ExtensionPrefs* prefs = service->extension_prefs(); 126 if (prefs->DidExtensionEscalatePermissions(extension.id())) { 127 info->disabled_reason = 128 management::ExtensionInfo::DISABLED_REASON_PERMISSIONS_INCREASE; 129 } else { 130 info->disabled_reason = 131 management::ExtensionInfo::DISABLED_REASON_UNKNOWN; 132 } 133 } 134 135 if (!ManifestURL::GetUpdateURL(&extension).is_empty()) { 136 info->update_url.reset(new std::string( 137 ManifestURL::GetUpdateURL(&extension).spec())); 138 } 139 140 if (extension.is_app()) { 141 info->app_launch_url.reset(new std::string( 142 AppLaunchInfo::GetFullLaunchURL(&extension).spec())); 143 } 144 145 const ExtensionIconSet::IconMap& icons = 146 IconsInfo::GetIcons(&extension).map(); 147 if (!icons.empty()) { 148 info->icons.reset(new IconInfoList()); 149 ExtensionIconSet::IconMap::const_iterator icon_iter; 150 for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) { 151 management::IconInfo* icon_info = new management::IconInfo(); 152 icon_info->size = icon_iter->first; 153 GURL url = ExtensionIconSource::GetIconURL( 154 &extension, icon_info->size, ExtensionIconSet::MATCH_EXACTLY, false, 155 NULL); 156 icon_info->url = url.spec(); 157 info->icons->push_back(make_linked_ptr<management::IconInfo>(icon_info)); 158 } 159 } 160 161 const std::set<std::string> perms = 162 extension.GetActivePermissions()->GetAPIsAsStrings(); 163 if (!perms.empty()) { 164 std::set<std::string>::const_iterator perms_iter; 165 for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter) 166 info->permissions.push_back(*perms_iter); 167 } 168 169 if (!extension.is_hosted_app()) { 170 // Skip host permissions for hosted apps. 171 const URLPatternSet host_perms = 172 extension.GetActivePermissions()->explicit_hosts(); 173 if (!host_perms.is_empty()) { 174 for (URLPatternSet::const_iterator iter = host_perms.begin(); 175 iter != host_perms.end(); ++iter) { 176 info->host_permissions.push_back(iter->GetAsString()); 177 } 178 } 179 } 180 181 switch (extension.location()) { 182 case Manifest::INTERNAL: 183 info->install_type = management::ExtensionInfo::INSTALL_TYPE_NORMAL; 184 break; 185 case Manifest::UNPACKED: 186 case Manifest::COMMAND_LINE: 187 info->install_type = management::ExtensionInfo::INSTALL_TYPE_DEVELOPMENT; 188 break; 189 case Manifest::EXTERNAL_PREF: 190 case Manifest::EXTERNAL_REGISTRY: 191 case Manifest::EXTERNAL_PREF_DOWNLOAD: 192 info->install_type = management::ExtensionInfo::INSTALL_TYPE_SIDELOAD; 193 break; 194 case Manifest::EXTERNAL_POLICY_DOWNLOAD: 195 info->install_type = management::ExtensionInfo::INSTALL_TYPE_ADMIN; 196 break; 197 default: 198 info->install_type = management::ExtensionInfo::INSTALL_TYPE_OTHER; 199 break; 200 } 201 202 return info.Pass(); 203 } 204 205 void AddExtensionInfo(const ExtensionSet& extensions, 206 ExtensionSystem* system, 207 ExtensionInfoList* extension_list) { 208 for (ExtensionSet::const_iterator iter = extensions.begin(); 209 iter != extensions.end(); ++iter) { 210 const Extension& extension = *iter->get(); 211 212 if (extension.ShouldNotBeVisible()) 213 continue; // Skip built-in extensions/apps. 214 215 extension_list->push_back(make_linked_ptr<management::ExtensionInfo>( 216 CreateExtensionInfo(extension, system).release())); 217 } 218 } 219 220 } // namespace 221 222 ExtensionService* ManagementFunction::service() { 223 return profile()->GetExtensionService(); 224 } 225 226 ExtensionService* AsyncManagementFunction::service() { 227 return profile()->GetExtensionService(); 228 } 229 230 bool ManagementGetAllFunction::RunImpl() { 231 ExtensionInfoList extensions; 232 ExtensionSystem* system = ExtensionSystem::Get(profile()); 233 234 AddExtensionInfo(*service()->extensions(), system, &extensions); 235 AddExtensionInfo(*service()->disabled_extensions(), system, &extensions); 236 AddExtensionInfo(*service()->terminated_extensions(), system, &extensions); 237 238 results_ = management::GetAll::Results::Create(extensions); 239 return true; 240 } 241 242 bool ManagementGetFunction::RunImpl() { 243 scoped_ptr<management::Get::Params> params( 244 management::Get::Params::Create(*args_)); 245 EXTENSION_FUNCTION_VALIDATE(params.get()); 246 247 const Extension* extension = service()->GetExtensionById(params->id, true); 248 if (!extension) { 249 error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, 250 params->id); 251 return false; 252 } 253 254 scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo( 255 *extension, ExtensionSystem::Get(profile())); 256 results_ = management::Get::Results::Create(*info); 257 258 return true; 259 } 260 261 bool ManagementGetPermissionWarningsByIdFunction::RunImpl() { 262 scoped_ptr<management::GetPermissionWarningsById::Params> params( 263 management::GetPermissionWarningsById::Params::Create(*args_)); 264 EXTENSION_FUNCTION_VALIDATE(params.get()); 265 266 const Extension* extension = service()->GetExtensionById(params->id, true); 267 if (!extension) { 268 error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, 269 params->id); 270 return false; 271 } 272 273 std::vector<std::string> warnings = CreateWarningsList(extension); 274 results_ = management::GetPermissionWarningsById::Results::Create(warnings); 275 return true; 276 } 277 278 namespace { 279 280 // This class helps ManagementGetPermissionWarningsByManifestFunction manage 281 // sending manifest JSON strings to the utility process for parsing. 282 class SafeManifestJSONParser : public UtilityProcessHostClient { 283 public: 284 SafeManifestJSONParser( 285 ManagementGetPermissionWarningsByManifestFunction* client, 286 const std::string& manifest) 287 : client_(client), 288 manifest_(manifest) {} 289 290 void Start() { 291 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 292 BrowserThread::PostTask( 293 BrowserThread::IO, 294 FROM_HERE, 295 base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this)); 296 } 297 298 void StartWorkOnIOThread() { 299 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 300 UtilityProcessHost* host = UtilityProcessHost::Create( 301 this, base::MessageLoopProxy::current().get()); 302 host->EnableZygote(); 303 host->Send(new ChromeUtilityMsg_ParseJSON(manifest_)); 304 } 305 306 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 307 bool handled = true; 308 IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message) 309 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded, 310 OnJSONParseSucceeded) 311 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed, 312 OnJSONParseFailed) 313 IPC_MESSAGE_UNHANDLED(handled = false) 314 IPC_END_MESSAGE_MAP() 315 return handled; 316 } 317 318 void OnJSONParseSucceeded(const base::ListValue& wrapper) { 319 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 320 const Value* value = NULL; 321 CHECK(wrapper.Get(0, &value)); 322 if (value->IsType(Value::TYPE_DICTIONARY)) 323 parsed_manifest_.reset( 324 static_cast<const base::DictionaryValue*>(value)->DeepCopy()); 325 else 326 error_ = keys::kManifestParseError; 327 328 BrowserThread::PostTask( 329 BrowserThread::UI, 330 FROM_HERE, 331 base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this)); 332 } 333 334 void OnJSONParseFailed(const std::string& error) { 335 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 336 error_ = error; 337 BrowserThread::PostTask( 338 BrowserThread::UI, 339 FROM_HERE, 340 base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this)); 341 } 342 343 void ReportResultFromUIThread() { 344 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 345 if (error_.empty() && parsed_manifest_.get()) 346 client_->OnParseSuccess(parsed_manifest_.release()); 347 else 348 client_->OnParseFailure(error_); 349 } 350 351 private: 352 virtual ~SafeManifestJSONParser() {} 353 354 // The client who we'll report results back to. 355 ManagementGetPermissionWarningsByManifestFunction* client_; 356 357 // Data to parse. 358 std::string manifest_; 359 360 // Results of parsing. 361 scoped_ptr<base::DictionaryValue> parsed_manifest_; 362 363 std::string error_; 364 }; 365 366 } // namespace 367 368 bool ManagementGetPermissionWarningsByManifestFunction::RunImpl() { 369 scoped_ptr<management::GetPermissionWarningsByManifest::Params> params( 370 management::GetPermissionWarningsByManifest::Params::Create(*args_)); 371 EXTENSION_FUNCTION_VALIDATE(params.get()); 372 373 scoped_refptr<SafeManifestJSONParser> parser = 374 new SafeManifestJSONParser(this, params->manifest_str); 375 parser->Start(); 376 377 // Matched with a Release() in OnParseSuccess/Failure(). 378 AddRef(); 379 380 // Response is sent async in OnParseSuccess/Failure(). 381 return true; 382 } 383 384 void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess( 385 base::DictionaryValue* parsed_manifest) { 386 CHECK(parsed_manifest); 387 388 scoped_refptr<Extension> extension = Extension::Create( 389 base::FilePath(), Manifest::INVALID_LOCATION, *parsed_manifest, 390 Extension::NO_FLAGS, &error_); 391 if (!extension.get()) { 392 OnParseFailure(keys::kExtensionCreateError); 393 return; 394 } 395 396 std::vector<std::string> warnings = CreateWarningsList(extension.get()); 397 results_ = 398 management::GetPermissionWarningsByManifest::Results::Create(warnings); 399 SendResponse(true); 400 401 // Matched with AddRef() in RunImpl(). 402 Release(); 403 } 404 405 void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure( 406 const std::string& error) { 407 error_ = error; 408 SendResponse(false); 409 410 // Matched with AddRef() in RunImpl(). 411 Release(); 412 } 413 414 bool ManagementLaunchAppFunction::RunImpl() { 415 scoped_ptr<management::LaunchApp::Params> params( 416 management::LaunchApp::Params::Create(*args_)); 417 EXTENSION_FUNCTION_VALIDATE(params.get()); 418 const Extension* extension = service()->GetExtensionById(params->id, true); 419 if (!extension) { 420 error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, 421 params->id); 422 return false; 423 } 424 if (!extension->is_app()) { 425 error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, 426 params->id); 427 return false; 428 } 429 430 // Look at prefs to find the right launch container. 431 // |default_pref_value| is set to LAUNCH_DEFAULT so that if 432 // the user has not set a preference, we open the app in a tab. 433 extension_misc::LaunchContainer launch_container = 434 service()->extension_prefs()->GetLaunchContainer( 435 extension, ExtensionPrefs::LAUNCH_DEFAULT); 436 chrome::OpenApplication(chrome::AppLaunchParams(profile(), extension, 437 launch_container, 438 NEW_FOREGROUND_TAB)); 439 #if !defined(OS_ANDROID) 440 CoreAppLauncherHandler::RecordAppLaunchType( 441 extension_misc::APP_LAUNCH_EXTENSION_API, 442 extension->GetType()); 443 #endif 444 445 return true; 446 } 447 448 ManagementSetEnabledFunction::ManagementSetEnabledFunction() { 449 } 450 451 ManagementSetEnabledFunction::~ManagementSetEnabledFunction() { 452 } 453 454 bool ManagementSetEnabledFunction::RunImpl() { 455 scoped_ptr<management::SetEnabled::Params> params( 456 management::SetEnabled::Params::Create(*args_)); 457 EXTENSION_FUNCTION_VALIDATE(params.get()); 458 459 extension_id_ = params->id; 460 461 const Extension* extension = service()->GetInstalledExtension(extension_id_); 462 if (!extension || extension->ShouldNotBeVisible()) { 463 error_ = ErrorUtils::FormatErrorMessage( 464 keys::kNoExtensionError, extension_id_); 465 return false; 466 } 467 468 const ManagementPolicy* policy = ExtensionSystem::Get(profile())-> 469 management_policy(); 470 if (!policy->UserMayModifySettings(extension, NULL)) { 471 error_ = ErrorUtils::FormatErrorMessage( 472 keys::kUserCantModifyError, extension_id_); 473 return false; 474 } 475 476 bool currently_enabled = service()->IsExtensionEnabled(extension_id_); 477 478 if (!currently_enabled && params->enabled) { 479 ExtensionPrefs* prefs = service()->extension_prefs(); 480 if (prefs->DidExtensionEscalatePermissions(extension_id_)) { 481 if (!user_gesture()) { 482 error_ = keys::kGestureNeededForEscalationError; 483 return false; 484 } 485 AddRef(); // Matched in InstallUIProceed/InstallUIAbort 486 install_prompt_.reset( 487 new ExtensionInstallPrompt(GetAssociatedWebContents())); 488 install_prompt_->ConfirmReEnable(this, extension); 489 return true; 490 } 491 service()->EnableExtension(extension_id_); 492 } else if (currently_enabled && !params->enabled) { 493 service()->DisableExtension(extension_id_, Extension::DISABLE_USER_ACTION); 494 } 495 496 BrowserThread::PostTask( 497 BrowserThread::UI, 498 FROM_HERE, 499 base::Bind(&ManagementSetEnabledFunction::SendResponse, this, true)); 500 501 return true; 502 } 503 504 void ManagementSetEnabledFunction::InstallUIProceed() { 505 service()->EnableExtension(extension_id_); 506 SendResponse(true); 507 Release(); 508 } 509 510 void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) { 511 error_ = keys::kUserDidNotReEnableError; 512 SendResponse(false); 513 Release(); 514 } 515 516 ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() { 517 } 518 519 ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() { 520 } 521 522 bool ManagementUninstallFunctionBase::Uninstall( 523 const std::string& extension_id, 524 bool show_confirm_dialog) { 525 extension_id_ = extension_id; 526 const Extension* extension = service()->GetExtensionById(extension_id_, true); 527 if (!extension || extension->ShouldNotBeVisible()) { 528 error_ = ErrorUtils::FormatErrorMessage( 529 keys::kNoExtensionError, extension_id_); 530 return false; 531 } 532 533 if (!ExtensionSystem::Get(profile())->management_policy()-> 534 UserMayModifySettings(extension, NULL)) { 535 error_ = ErrorUtils::FormatErrorMessage( 536 keys::kUserCantModifyError, extension_id_); 537 return false; 538 } 539 540 if (auto_confirm_for_test == DO_NOT_SKIP) { 541 if (show_confirm_dialog) { 542 AddRef(); // Balanced in ExtensionUninstallAccepted/Canceled 543 extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create( 544 profile(), GetCurrentBrowser(), this)); 545 extension_uninstall_dialog_->ConfirmUninstall(extension); 546 } else { 547 Finish(true); 548 } 549 } else { 550 Finish(auto_confirm_for_test == PROCEED); 551 } 552 553 return true; 554 } 555 556 // static 557 void ManagementUninstallFunctionBase::SetAutoConfirmForTest( 558 bool should_proceed) { 559 auto_confirm_for_test = should_proceed ? PROCEED : ABORT; 560 } 561 562 void ManagementUninstallFunctionBase::Finish(bool should_uninstall) { 563 if (should_uninstall) { 564 bool success = service()->UninstallExtension( 565 extension_id_, 566 false, /* external uninstall */ 567 NULL); 568 569 // TODO set error_ if !success 570 SendResponse(success); 571 } else { 572 error_ = ErrorUtils::FormatErrorMessage( 573 keys::kUninstallCanceledError, extension_id_); 574 SendResponse(false); 575 } 576 577 } 578 579 void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() { 580 Finish(true); 581 Release(); 582 } 583 584 void ManagementUninstallFunctionBase::ExtensionUninstallCanceled() { 585 Finish(false); 586 Release(); 587 } 588 589 ManagementUninstallFunction::ManagementUninstallFunction() { 590 } 591 592 ManagementUninstallFunction::~ManagementUninstallFunction() { 593 } 594 595 bool ManagementUninstallFunction::RunImpl() { 596 scoped_ptr<management::Uninstall::Params> params( 597 management::Uninstall::Params::Create(*args_)); 598 EXTENSION_FUNCTION_VALIDATE(params.get()); 599 600 bool show_confirm_dialog = false; 601 if (params->options.get() && params->options->show_confirm_dialog.get()) 602 show_confirm_dialog = *params->options->show_confirm_dialog; 603 604 return Uninstall(params->id, show_confirm_dialog); 605 } 606 607 ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() { 608 } 609 610 ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() { 611 } 612 613 bool ManagementUninstallSelfFunction::RunImpl() { 614 scoped_ptr<management::UninstallSelf::Params> params( 615 management::UninstallSelf::Params::Create(*args_)); 616 EXTENSION_FUNCTION_VALIDATE(params.get()); 617 618 bool show_confirm_dialog = false; 619 if (params->options.get() && params->options->show_confirm_dialog.get()) 620 show_confirm_dialog = *params->options->show_confirm_dialog; 621 return Uninstall(extension_->id(), show_confirm_dialog); 622 } 623 624 ManagementEventRouter::ManagementEventRouter(Profile* profile) 625 : profile_(profile) { 626 int types[] = { 627 chrome::NOTIFICATION_EXTENSION_INSTALLED, 628 chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 629 chrome::NOTIFICATION_EXTENSION_LOADED, 630 chrome::NOTIFICATION_EXTENSION_UNLOADED 631 }; 632 633 CHECK(registrar_.IsEmpty()); 634 for (size_t i = 0; i < arraysize(types); i++) { 635 registrar_.Add(this, 636 types[i], 637 content::Source<Profile>(profile_)); 638 } 639 } 640 641 ManagementEventRouter::~ManagementEventRouter() {} 642 643 void ManagementEventRouter::Observe( 644 int type, 645 const content::NotificationSource& source, 646 const content::NotificationDetails& details) { 647 const char* event_name = NULL; 648 const Extension* extension = NULL; 649 Profile* profile = content::Source<Profile>(source).ptr(); 650 CHECK(profile); 651 CHECK(profile_->IsSameProfile(profile)); 652 653 switch (type) { 654 case chrome::NOTIFICATION_EXTENSION_INSTALLED: 655 event_name = events::kOnExtensionInstalled; 656 extension = 657 content::Details<const InstalledExtensionInfo>(details)->extension; 658 break; 659 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: 660 event_name = events::kOnExtensionUninstalled; 661 extension = content::Details<const Extension>(details).ptr(); 662 break; 663 case chrome::NOTIFICATION_EXTENSION_LOADED: 664 event_name = events::kOnExtensionEnabled; 665 extension = content::Details<const Extension>(details).ptr(); 666 break; 667 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 668 event_name = events::kOnExtensionDisabled; 669 extension = 670 content::Details<const UnloadedExtensionInfo>(details)->extension; 671 break; 672 default: 673 NOTREACHED(); 674 return; 675 } 676 DCHECK(event_name); 677 DCHECK(extension); 678 679 if (extension->ShouldNotBeVisible()) 680 return; // Don't dispatch events for built-in extensions. 681 682 scoped_ptr<base::ListValue> args(new base::ListValue()); 683 if (event_name == events::kOnExtensionUninstalled) { 684 args->Append(Value::CreateStringValue(extension->id())); 685 } else { 686 scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo( 687 *extension, ExtensionSystem::Get(profile)); 688 args->Append(info->ToValue().release()); 689 } 690 691 scoped_ptr<Event> event(new Event(event_name, args.Pass())); 692 ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass()); 693 } 694 695 ManagementAPI::ManagementAPI(Profile* profile) 696 : profile_(profile) { 697 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 698 this, events::kOnExtensionInstalled); 699 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 700 this, events::kOnExtensionUninstalled); 701 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 702 this, events::kOnExtensionEnabled); 703 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 704 this, events::kOnExtensionDisabled); 705 } 706 707 ManagementAPI::~ManagementAPI() { 708 } 709 710 void ManagementAPI::Shutdown() { 711 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); 712 } 713 714 static base::LazyInstance<ProfileKeyedAPIFactory<ManagementAPI> > 715 g_factory = LAZY_INSTANCE_INITIALIZER; 716 717 // static 718 ProfileKeyedAPIFactory<ManagementAPI>* ManagementAPI::GetFactoryInstance() { 719 return &g_factory.Get(); 720 } 721 722 void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) { 723 management_event_router_.reset(new ManagementEventRouter(profile_)); 724 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); 725 } 726 727 } // namespace extensions 728