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