management_api.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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/app_launcher_handler.h" 52#endif 53 54using base::IntToString; 55using content::BrowserThread; 56using content::UtilityProcessHost; 57using content::UtilityProcessHostClient; 58 59namespace keys = extension_management_api_constants; 60 61namespace extensions { 62 63namespace events = event_names; 64namespace management = api::management; 65 66namespace { 67 68typedef std::vector<linked_ptr<management::ExtensionInfo> > ExtensionInfoList; 69typedef std::vector<linked_ptr<management::IconInfo> > IconInfoList; 70 71enum AutoConfirmForTest { 72 DO_NOT_SKIP = 0, 73 PROCEED, 74 ABORT 75}; 76 77AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP; 78 79std::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 91scoped_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 205void 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.location() == Manifest::COMPONENT) 213 continue; // Skip built-in extensions. 214 215 extension_list->push_back(make_linked_ptr<management::ExtensionInfo>( 216 CreateExtensionInfo(extension, system).release())); 217 } 218} 219 220} // namespace 221 222ExtensionService* ManagementFunction::service() { 223 return profile()->GetExtensionService(); 224} 225 226ExtensionService* AsyncManagementFunction::service() { 227 return profile()->GetExtensionService(); 228} 229 230bool 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 242bool 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 261bool 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 278namespace { 279 280// This class helps ManagementGetPermissionWarningsByManifestFunction manage 281// sending manifest JSON strings to the utility process for parsing. 282class 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 368bool 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 384void 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 405void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure( 406 const std::string& error) { 407 error_ = error; 408 SendResponse(false); 409 410 // Matched with AddRef() in RunImpl(). 411 Release(); 412} 413 414bool 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 AppLauncherHandler::RecordAppLaunchType( 441 extension_misc::APP_LAUNCH_EXTENSION_API, 442 extension->GetType()); 443#endif 444 445 return true; 446} 447 448ManagementSetEnabledFunction::ManagementSetEnabledFunction() { 449} 450 451ManagementSetEnabledFunction::~ManagementSetEnabledFunction() { 452} 453 454bool 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) { 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 504void ManagementSetEnabledFunction::InstallUIProceed() { 505 service()->EnableExtension(extension_id_); 506 SendResponse(true); 507 Release(); 508} 509 510void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) { 511 error_ = keys::kUserDidNotReEnableError; 512 SendResponse(false); 513 Release(); 514} 515 516ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() { 517} 518 519ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() { 520} 521 522bool 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) { 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 557void ManagementUninstallFunctionBase::SetAutoConfirmForTest( 558 bool should_proceed) { 559 auto_confirm_for_test = should_proceed ? PROCEED : ABORT; 560} 561 562void 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 579void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() { 580 Finish(true); 581 Release(); 582} 583 584void ManagementUninstallFunctionBase::ExtensionUninstallCanceled() { 585 Finish(false); 586 Release(); 587} 588 589ManagementUninstallFunction::ManagementUninstallFunction() { 590} 591 592ManagementUninstallFunction::~ManagementUninstallFunction() { 593} 594 595bool 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 607ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() { 608} 609 610ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() { 611} 612 613bool 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 624ManagementEventRouter::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 641ManagementEventRouter::~ManagementEventRouter() {} 642 643void 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 scoped_ptr<base::ListValue> args(new base::ListValue()); 680 if (event_name == events::kOnExtensionUninstalled) { 681 args->Append(Value::CreateStringValue(extension->id())); 682 } else { 683 scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo( 684 *extension, ExtensionSystem::Get(profile)); 685 args->Append(info->ToValue().release()); 686 } 687 688 scoped_ptr<Event> event(new Event(event_name, args.Pass())); 689 ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass()); 690} 691 692ManagementAPI::ManagementAPI(Profile* profile) 693 : profile_(profile) { 694 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 695 this, events::kOnExtensionInstalled); 696 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 697 this, events::kOnExtensionUninstalled); 698 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 699 this, events::kOnExtensionEnabled); 700 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 701 this, events::kOnExtensionDisabled); 702} 703 704ManagementAPI::~ManagementAPI() { 705} 706 707void ManagementAPI::Shutdown() { 708 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); 709} 710 711static base::LazyInstance<ProfileKeyedAPIFactory<ManagementAPI> > 712g_factory = LAZY_INSTANCE_INITIALIZER; 713 714// static 715ProfileKeyedAPIFactory<ManagementAPI>* ManagementAPI::GetFactoryInstance() { 716 return &g_factory.Get(); 717} 718 719void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) { 720 management_event_router_.reset(new ManagementEventRouter(profile_)); 721 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); 722} 723 724} // namespace extensions 725