- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / management / management_api.cc
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/logging.h"
16 #include "base/memory/linked_ptr.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/metrics/histogram.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/extensions/api/management/management_api_constants.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/permissions_data.h"
42 #include "content/public/browser/notification_details.h"
43 #include "content/public/browser/notification_source.h"
44 #include "content/public/browser/utility_process_host.h"
45 #include "content/public/browser/utility_process_host_client.h"
46 #include "extensions/common/error_utils.h"
47 #include "extensions/common/permissions/permission_set.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 management = api::management;
64
65 namespace {
66
67 typedef std::vector<linked_ptr<management::ExtensionInfo> > ExtensionInfoList;
68 typedef std::vector<linked_ptr<management::IconInfo> > IconInfoList;
69
70 enum AutoConfirmForTest {
71   DO_NOT_SKIP = 0,
72   PROCEED,
73   ABORT
74 };
75
76 AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
77
78 std::vector<std::string> CreateWarningsList(const Extension* extension) {
79   std::vector<std::string> warnings_list;
80   PermissionMessages warnings =
81       PermissionsData::GetPermissionMessages(extension);
82   for (PermissionMessages::const_iterator iter = warnings.begin();
83        iter != warnings.end(); ++iter) {
84     warnings_list.push_back(UTF16ToUTF8(iter->message()));
85   }
86
87   return warnings_list;
88 }
89
90 scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
91     const Extension& extension,
92     ExtensionSystem* system) {
93   scoped_ptr<management::ExtensionInfo> info(new management::ExtensionInfo());
94   ExtensionService* service = system->extension_service();
95
96   info->id = extension.id();
97   info->name = extension.name();
98   info->short_name = extension.short_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:
195     case Manifest::EXTERNAL_POLICY_DOWNLOAD:
196       info->install_type = management::ExtensionInfo::INSTALL_TYPE_ADMIN;
197       break;
198     case Manifest::NUM_LOCATIONS:
199       NOTREACHED();
200     case Manifest::INVALID_LOCATION:
201     case Manifest::COMPONENT:
202     case Manifest::EXTERNAL_COMPONENT:
203       info->install_type = management::ExtensionInfo::INSTALL_TYPE_OTHER;
204       break;
205   }
206
207   return info.Pass();
208 }
209
210 void AddExtensionInfo(const ExtensionSet& extensions,
211                             ExtensionSystem* system,
212                             ExtensionInfoList* extension_list) {
213   for (ExtensionSet::const_iterator iter = extensions.begin();
214        iter != extensions.end(); ++iter) {
215     const Extension& extension = *iter->get();
216
217     if (extension.ShouldNotBeVisible())
218       continue;  // Skip built-in extensions/apps.
219
220     extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
221         CreateExtensionInfo(extension, system).release()));
222   }
223 }
224
225 } // namespace
226
227 ExtensionService* ManagementFunction::service() {
228   return GetProfile()->GetExtensionService();
229 }
230
231 ExtensionService* AsyncManagementFunction::service() {
232   return GetProfile()->GetExtensionService();
233 }
234
235 bool ManagementGetAllFunction::RunImpl() {
236   ExtensionInfoList extensions;
237   ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
238
239   AddExtensionInfo(*service()->extensions(), system, &extensions);
240   AddExtensionInfo(*service()->disabled_extensions(), system, &extensions);
241   AddExtensionInfo(*service()->terminated_extensions(), system, &extensions);
242
243   results_ = management::GetAll::Results::Create(extensions);
244   return true;
245 }
246
247 bool ManagementGetFunction::RunImpl() {
248   scoped_ptr<management::Get::Params> params(
249       management::Get::Params::Create(*args_));
250   EXTENSION_FUNCTION_VALIDATE(params.get());
251
252   const Extension* extension = service()->GetExtensionById(params->id, true);
253   if (!extension) {
254     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
255                                                      params->id);
256     return false;
257   }
258
259   scoped_ptr<management::ExtensionInfo> info =
260       CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
261   results_ = management::Get::Results::Create(*info);
262
263   return true;
264 }
265
266 bool ManagementGetPermissionWarningsByIdFunction::RunImpl() {
267   scoped_ptr<management::GetPermissionWarningsById::Params> params(
268       management::GetPermissionWarningsById::Params::Create(*args_));
269   EXTENSION_FUNCTION_VALIDATE(params.get());
270
271   const Extension* extension = service()->GetExtensionById(params->id, true);
272   if (!extension) {
273     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
274                                                      params->id);
275     return false;
276   }
277
278   std::vector<std::string> warnings = CreateWarningsList(extension);
279   results_ = management::GetPermissionWarningsById::Results::Create(warnings);
280   return true;
281 }
282
283 namespace {
284
285 // This class helps ManagementGetPermissionWarningsByManifestFunction manage
286 // sending manifest JSON strings to the utility process for parsing.
287 class SafeManifestJSONParser : public UtilityProcessHostClient {
288  public:
289   SafeManifestJSONParser(
290       ManagementGetPermissionWarningsByManifestFunction* client,
291       const std::string& manifest)
292       : client_(client),
293         manifest_(manifest) {}
294
295   void Start() {
296     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
297     BrowserThread::PostTask(
298         BrowserThread::IO,
299         FROM_HERE,
300         base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this));
301   }
302
303   void StartWorkOnIOThread() {
304     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
305     UtilityProcessHost* host = UtilityProcessHost::Create(
306         this, base::MessageLoopProxy::current().get());
307     host->EnableZygote();
308     host->Send(new ChromeUtilityMsg_ParseJSON(manifest_));
309   }
310
311   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
312     bool handled = true;
313     IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message)
314       IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
315                           OnJSONParseSucceeded)
316       IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
317                           OnJSONParseFailed)
318       IPC_MESSAGE_UNHANDLED(handled = false)
319     IPC_END_MESSAGE_MAP()
320     return handled;
321   }
322
323   void OnJSONParseSucceeded(const base::ListValue& wrapper) {
324     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
325     const Value* value = NULL;
326     CHECK(wrapper.Get(0, &value));
327     if (value->IsType(Value::TYPE_DICTIONARY))
328       parsed_manifest_.reset(
329           static_cast<const base::DictionaryValue*>(value)->DeepCopy());
330     else
331       error_ = keys::kManifestParseError;
332
333     BrowserThread::PostTask(
334         BrowserThread::UI,
335         FROM_HERE,
336         base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
337   }
338
339   void OnJSONParseFailed(const std::string& error) {
340     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
341     error_ = error;
342     BrowserThread::PostTask(
343         BrowserThread::UI,
344         FROM_HERE,
345         base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
346   }
347
348   void ReportResultFromUIThread() {
349     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
350     if (error_.empty() && parsed_manifest_.get())
351       client_->OnParseSuccess(parsed_manifest_.Pass());
352     else
353       client_->OnParseFailure(error_);
354   }
355
356  private:
357   virtual ~SafeManifestJSONParser() {}
358
359   // The client who we'll report results back to.
360   ManagementGetPermissionWarningsByManifestFunction* client_;
361
362   // Data to parse.
363   std::string manifest_;
364
365   // Results of parsing.
366   scoped_ptr<base::DictionaryValue> parsed_manifest_;
367
368   std::string error_;
369 };
370
371 }  // namespace
372
373 bool ManagementGetPermissionWarningsByManifestFunction::RunImpl() {
374   scoped_ptr<management::GetPermissionWarningsByManifest::Params> params(
375       management::GetPermissionWarningsByManifest::Params::Create(*args_));
376   EXTENSION_FUNCTION_VALIDATE(params.get());
377
378   scoped_refptr<SafeManifestJSONParser> parser =
379       new SafeManifestJSONParser(this, params->manifest_str);
380   parser->Start();
381
382   // Matched with a Release() in OnParseSuccess/Failure().
383   AddRef();
384
385   // Response is sent async in OnParseSuccess/Failure().
386   return true;
387 }
388
389 void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
390     scoped_ptr<base::DictionaryValue> parsed_manifest) {
391   CHECK(parsed_manifest.get());
392
393   scoped_refptr<Extension> extension = Extension::Create(
394       base::FilePath(), Manifest::INVALID_LOCATION, *parsed_manifest,
395       Extension::NO_FLAGS, &error_);
396   if (!extension.get()) {
397     OnParseFailure(keys::kExtensionCreateError);
398     return;
399   }
400
401   std::vector<std::string> warnings = CreateWarningsList(extension.get());
402   results_ =
403       management::GetPermissionWarningsByManifest::Results::Create(warnings);
404   SendResponse(true);
405
406   // Matched with AddRef() in RunImpl().
407   Release();
408 }
409
410 void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure(
411     const std::string& error) {
412   error_ = error;
413   SendResponse(false);
414
415   // Matched with AddRef() in RunImpl().
416   Release();
417 }
418
419 bool ManagementLaunchAppFunction::RunImpl() {
420   scoped_ptr<management::LaunchApp::Params> params(
421       management::LaunchApp::Params::Create(*args_));
422   EXTENSION_FUNCTION_VALIDATE(params.get());
423   const Extension* extension = service()->GetExtensionById(params->id, true);
424   if (!extension) {
425     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
426                                                      params->id);
427     return false;
428   }
429   if (!extension->is_app()) {
430     error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError,
431                                                      params->id);
432     return false;
433   }
434
435   // Look at prefs to find the right launch container.
436   // |default_pref_value| is set to LAUNCH_DEFAULT so that if
437   // the user has not set a preference, we open the app in a tab.
438   extension_misc::LaunchContainer launch_container =
439       service()->extension_prefs()->GetLaunchContainer(
440           extension, ExtensionPrefs::LAUNCH_DEFAULT);
441   OpenApplication(AppLaunchParams(
442       GetProfile(), extension, launch_container, NEW_FOREGROUND_TAB));
443 #if !defined(OS_ANDROID)
444   CoreAppLauncherHandler::RecordAppLaunchType(
445       extension_misc::APP_LAUNCH_EXTENSION_API,
446       extension->GetType());
447 #endif
448
449   return true;
450 }
451
452 ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
453 }
454
455 ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
456 }
457
458 bool ManagementSetEnabledFunction::RunImpl() {
459   scoped_ptr<management::SetEnabled::Params> params(
460       management::SetEnabled::Params::Create(*args_));
461   EXTENSION_FUNCTION_VALIDATE(params.get());
462
463   extension_id_ = params->id;
464
465   const Extension* extension = service()->GetInstalledExtension(extension_id_);
466   if (!extension || extension->ShouldNotBeVisible()) {
467     error_ = ErrorUtils::FormatErrorMessage(
468         keys::kNoExtensionError, extension_id_);
469     return false;
470   }
471
472   const ManagementPolicy* policy =
473       ExtensionSystem::Get(GetProfile())->management_policy();
474   if (!policy->UserMayModifySettings(extension, NULL) ||
475       (!params->enabled && policy->MustRemainEnabled(extension, NULL)) ||
476       (params->enabled && policy->MustRemainDisabled(extension, NULL, NULL))) {
477     error_ = ErrorUtils::FormatErrorMessage(
478         keys::kUserCantModifyError, extension_id_);
479     return false;
480   }
481
482   bool currently_enabled = service()->IsExtensionEnabled(extension_id_);
483
484   if (!currently_enabled && params->enabled) {
485     ExtensionPrefs* prefs = service()->extension_prefs();
486     if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
487       if (!user_gesture()) {
488         error_ = keys::kGestureNeededForEscalationError;
489         return false;
490       }
491       AddRef(); // Matched in InstallUIProceed/InstallUIAbort
492       install_prompt_.reset(
493           new ExtensionInstallPrompt(GetAssociatedWebContents()));
494       install_prompt_->ConfirmReEnable(this, extension);
495       return true;
496     }
497     service()->EnableExtension(extension_id_);
498   } else if (currently_enabled && !params->enabled) {
499     service()->DisableExtension(extension_id_, Extension::DISABLE_USER_ACTION);
500   }
501
502   BrowserThread::PostTask(
503       BrowserThread::UI,
504       FROM_HERE,
505       base::Bind(&ManagementSetEnabledFunction::SendResponse, this, true));
506
507   return true;
508 }
509
510 void ManagementSetEnabledFunction::InstallUIProceed() {
511   service()->EnableExtension(extension_id_);
512   SendResponse(true);
513   Release();
514 }
515
516 void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) {
517   error_ = keys::kUserDidNotReEnableError;
518   SendResponse(false);
519   Release();
520 }
521
522 ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
523 }
524
525 ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() {
526 }
527
528 bool ManagementUninstallFunctionBase::Uninstall(
529     const std::string& extension_id,
530     bool show_confirm_dialog) {
531   extension_id_ = extension_id;
532   const Extension* extension = service()->GetExtensionById(extension_id_, true);
533   if (!extension || extension->ShouldNotBeVisible()) {
534     error_ = ErrorUtils::FormatErrorMessage(
535         keys::kNoExtensionError, extension_id_);
536     return false;
537   }
538
539   if (!ExtensionSystem::Get(GetProfile())
540            ->management_policy()
541            ->UserMayModifySettings(extension, NULL)) {
542     error_ = ErrorUtils::FormatErrorMessage(
543         keys::kUserCantModifyError, extension_id_);
544     return false;
545   }
546
547   if (auto_confirm_for_test == DO_NOT_SKIP) {
548     if (show_confirm_dialog) {
549       AddRef(); // Balanced in ExtensionUninstallAccepted/Canceled
550       extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
551           GetProfile(), GetCurrentBrowser(), this));
552       extension_uninstall_dialog_->ConfirmUninstall(extension);
553     } else {
554       Finish(true);
555     }
556   } else {
557     Finish(auto_confirm_for_test == PROCEED);
558   }
559
560   return true;
561 }
562
563 // static
564 void ManagementUninstallFunctionBase::SetAutoConfirmForTest(
565     bool should_proceed) {
566   auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
567 }
568
569 void ManagementUninstallFunctionBase::Finish(bool should_uninstall) {
570   if (should_uninstall) {
571     bool success = service()->UninstallExtension(
572         extension_id_,
573         false, /* external uninstall */
574         NULL);
575
576     // TODO set error_ if !success
577     SendResponse(success);
578   } else {
579     error_ = ErrorUtils::FormatErrorMessage(
580         keys::kUninstallCanceledError, extension_id_);
581     SendResponse(false);
582   }
583
584 }
585
586 void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() {
587   Finish(true);
588   Release();
589 }
590
591 void ManagementUninstallFunctionBase::ExtensionUninstallCanceled() {
592   Finish(false);
593   Release();
594 }
595
596 ManagementUninstallFunction::ManagementUninstallFunction() {
597 }
598
599 ManagementUninstallFunction::~ManagementUninstallFunction() {
600 }
601
602 bool ManagementUninstallFunction::RunImpl() {
603   scoped_ptr<management::Uninstall::Params> params(
604       management::Uninstall::Params::Create(*args_));
605   EXTENSION_FUNCTION_VALIDATE(params.get());
606
607   bool show_confirm_dialog = false;
608   if (params->options.get() && params->options->show_confirm_dialog.get())
609     show_confirm_dialog = *params->options->show_confirm_dialog;
610
611   return Uninstall(params->id, show_confirm_dialog);
612 }
613
614 ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
615 }
616
617 ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
618 }
619
620 bool ManagementUninstallSelfFunction::RunImpl() {
621   scoped_ptr<management::UninstallSelf::Params> params(
622       management::UninstallSelf::Params::Create(*args_));
623   EXTENSION_FUNCTION_VALIDATE(params.get());
624
625   bool show_confirm_dialog = false;
626   if (params->options.get() && params->options->show_confirm_dialog.get())
627     show_confirm_dialog = *params->options->show_confirm_dialog;
628   return Uninstall(extension_->id(), show_confirm_dialog);
629 }
630
631 ManagementEventRouter::ManagementEventRouter(Profile* profile)
632     : profile_(profile) {
633   int types[] = {
634     chrome::NOTIFICATION_EXTENSION_INSTALLED,
635     chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
636     chrome::NOTIFICATION_EXTENSION_LOADED,
637     chrome::NOTIFICATION_EXTENSION_UNLOADED
638   };
639
640   CHECK(registrar_.IsEmpty());
641   for (size_t i = 0; i < arraysize(types); i++) {
642     registrar_.Add(this,
643                    types[i],
644                    content::Source<Profile>(profile_));
645   }
646 }
647
648 ManagementEventRouter::~ManagementEventRouter() {}
649
650 void ManagementEventRouter::Observe(
651     int type,
652     const content::NotificationSource& source,
653     const content::NotificationDetails& details) {
654   const char* event_name = NULL;
655   const Extension* extension = NULL;
656   Profile* profile = content::Source<Profile>(source).ptr();
657   CHECK(profile);
658   CHECK(profile_->IsSameProfile(profile));
659
660   switch (type) {
661     case chrome::NOTIFICATION_EXTENSION_INSTALLED:
662       event_name = management::OnInstalled::kEventName;
663       extension =
664           content::Details<const InstalledExtensionInfo>(details)->extension;
665       break;
666     case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
667       event_name = management::OnUninstalled::kEventName;
668       extension = content::Details<const Extension>(details).ptr();
669       break;
670     case chrome::NOTIFICATION_EXTENSION_LOADED:
671       event_name = management::OnEnabled::kEventName;
672       extension = content::Details<const Extension>(details).ptr();
673       break;
674     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
675       event_name = management::OnDisabled::kEventName;
676       extension =
677           content::Details<const UnloadedExtensionInfo>(details)->extension;
678       break;
679     default:
680       NOTREACHED();
681       return;
682   }
683   DCHECK(event_name);
684   DCHECK(extension);
685
686   if (extension->ShouldNotBeVisible())
687     return; // Don't dispatch events for built-in extensions.
688
689   scoped_ptr<base::ListValue> args(new base::ListValue());
690   if (event_name == management::OnUninstalled::kEventName) {
691     args->Append(new base::StringValue(extension->id()));
692   } else {
693     scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo(
694         *extension, ExtensionSystem::Get(profile));
695     args->Append(info->ToValue().release());
696   }
697
698   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
699   ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
700 }
701
702 ManagementAPI::ManagementAPI(Profile* profile)
703     : profile_(profile) {
704   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
705       this, management::OnInstalled::kEventName);
706   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
707       this, management::OnUninstalled::kEventName);
708   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
709       this, management::OnEnabled::kEventName);
710   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
711       this, management::OnDisabled::kEventName);
712 }
713
714 ManagementAPI::~ManagementAPI() {
715 }
716
717 void ManagementAPI::Shutdown() {
718   ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
719 }
720
721 static base::LazyInstance<ProfileKeyedAPIFactory<ManagementAPI> >
722 g_factory = LAZY_INSTANCE_INITIALIZER;
723
724 // static
725 ProfileKeyedAPIFactory<ManagementAPI>* ManagementAPI::GetFactoryInstance() {
726   return &g_factory.Get();
727 }
728
729 void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
730   management_event_router_.reset(new ManagementEventRouter(profile_));
731   ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
732 }
733
734 }  // namespace extensions