Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / management / management_api.cc
blob70296895bc22367b6436db83f5d2dc1c2b8b44cd
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.
5 #include "extensions/browser/api/management/management_api.h"
7 #include <string>
8 #include <vector>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/json/json_writer.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.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 "content/public/browser/browser_context.h"
22 #include "extensions/browser/api/extensions_api_client.h"
23 #include "extensions/browser/api/management/management_api_constants.h"
24 #include "extensions/browser/event_router.h"
25 #include "extensions/browser/extension_prefs.h"
26 #include "extensions/browser/extension_registry.h"
27 #include "extensions/browser/extension_system.h"
28 #include "extensions/browser/management_policy.h"
29 #include "extensions/browser/requirements_checker.h"
30 #include "extensions/browser/uninstall_reason.h"
31 #include "extensions/common/api/management.h"
32 #include "extensions/common/constants.h"
33 #include "extensions/common/error_utils.h"
34 #include "extensions/common/extension.h"
35 #include "extensions/common/extension_icon_set.h"
36 #include "extensions/common/manifest_handlers/icons_handler.h"
37 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
38 #include "extensions/common/manifest_handlers/options_page_info.h"
39 #include "extensions/common/manifest_url_handlers.h"
40 #include "extensions/common/permissions/permission_message.h"
41 #include "extensions/common/permissions/permissions_data.h"
42 #include "extensions/common/url_pattern.h"
44 using base::IntToString;
45 using content::BrowserThread;
47 namespace keys = extension_management_api_constants;
49 namespace extensions {
51 namespace management = api::management;
53 namespace {
55 typedef std::vector<linked_ptr<management::ExtensionInfo>> ExtensionInfoList;
56 typedef std::vector<linked_ptr<management::IconInfo>> IconInfoList;
58 enum AutoConfirmForTest { DO_NOT_SKIP = 0, PROCEED, ABORT };
60 AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
62 std::vector<std::string> CreateWarningsList(const Extension* extension) {
63 std::vector<std::string> warnings_list;
64 for (const PermissionMessage& msg :
65 extension->permissions_data()->GetPermissionMessages()) {
66 warnings_list.push_back(base::UTF16ToUTF8(msg.message()));
69 return warnings_list;
72 std::vector<management::LaunchType> GetAvailableLaunchTypes(
73 const Extension& extension,
74 const ManagementAPIDelegate* delegate) {
75 std::vector<management::LaunchType> launch_type_list;
76 if (extension.is_platform_app()) {
77 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
78 return launch_type_list;
81 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB);
83 // TODO(dominickn): remove check when hosted apps can open in windows on Mac.
84 if (delegate->CanHostedAppsOpenInWindows())
85 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
87 if (!delegate->IsNewBookmarkAppsEnabled()) {
88 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB);
89 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_FULL_SCREEN);
91 return launch_type_list;
94 scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
95 const Extension& extension,
96 content::BrowserContext* context) {
97 ExtensionSystem* system = ExtensionSystem::Get(context);
98 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
99 const ManagementAPIDelegate* delegate =
100 ManagementAPI::GetFactoryInstance()->Get(context)->GetDelegate();
101 scoped_ptr<management::ExtensionInfo> info(new management::ExtensionInfo());
103 info->id = extension.id();
104 info->name = extension.name();
105 info->short_name = extension.short_name();
106 info->enabled = registry->enabled_extensions().Contains(info->id);
107 info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension);
108 info->version = extension.VersionString();
109 info->description = extension.description();
110 info->options_url = OptionsPageInfo::GetOptionsPage(&extension).spec();
111 info->homepage_url.reset(
112 new std::string(ManifestURL::GetHomepageURL(&extension).spec()));
113 info->may_disable =
114 system->management_policy()->UserMayModifySettings(&extension, NULL);
115 info->is_app = extension.is_app();
116 if (info->is_app) {
117 if (extension.is_legacy_packaged_app())
118 info->type = management::EXTENSION_TYPE_LEGACY_PACKAGED_APP;
119 else if (extension.is_hosted_app())
120 info->type = management::EXTENSION_TYPE_HOSTED_APP;
121 else
122 info->type = management::EXTENSION_TYPE_PACKAGED_APP;
123 } else if (extension.is_theme()) {
124 info->type = management::EXTENSION_TYPE_THEME;
125 } else {
126 info->type = management::EXTENSION_TYPE_EXTENSION;
129 if (info->enabled) {
130 info->disabled_reason = management::EXTENSION_DISABLED_REASON_NONE;
131 } else {
132 ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
133 if (prefs->DidExtensionEscalatePermissions(extension.id())) {
134 info->disabled_reason =
135 management::EXTENSION_DISABLED_REASON_PERMISSIONS_INCREASE;
136 } else {
137 info->disabled_reason =
138 management::EXTENSION_DISABLED_REASON_UNKNOWN;
142 if (!ManifestURL::GetUpdateURL(&extension).is_empty()) {
143 info->update_url.reset(
144 new std::string(ManifestURL::GetUpdateURL(&extension).spec()));
147 if (extension.is_app()) {
148 info->app_launch_url.reset(
149 new std::string(delegate->GetFullLaunchURL(&extension).spec()));
152 const ExtensionIconSet::IconMap& icons =
153 IconsInfo::GetIcons(&extension).map();
154 if (!icons.empty()) {
155 info->icons.reset(new IconInfoList());
156 ExtensionIconSet::IconMap::const_iterator icon_iter;
157 for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) {
158 management::IconInfo* icon_info = new management::IconInfo();
159 icon_info->size = icon_iter->first;
160 GURL url =
161 delegate->GetIconURL(&extension, icon_info->size,
162 ExtensionIconSet::MATCH_EXACTLY, false, nullptr);
163 icon_info->url = url.spec();
164 info->icons->push_back(make_linked_ptr<management::IconInfo>(icon_info));
168 const std::set<std::string> perms =
169 extension.permissions_data()->active_permissions()->GetAPIsAsStrings();
170 if (!perms.empty()) {
171 std::set<std::string>::const_iterator perms_iter;
172 for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter)
173 info->permissions.push_back(*perms_iter);
176 if (!extension.is_hosted_app()) {
177 // Skip host permissions for hosted apps.
178 const URLPatternSet host_perms =
179 extension.permissions_data()->active_permissions()->explicit_hosts();
180 if (!host_perms.is_empty()) {
181 for (URLPatternSet::const_iterator iter = host_perms.begin();
182 iter != host_perms.end(); ++iter) {
183 info->host_permissions.push_back(iter->GetAsString());
188 switch (extension.location()) {
189 case Manifest::INTERNAL:
190 info->install_type = management::EXTENSION_INSTALL_TYPE_NORMAL;
191 break;
192 case Manifest::UNPACKED:
193 case Manifest::COMMAND_LINE:
194 info->install_type = management::EXTENSION_INSTALL_TYPE_DEVELOPMENT;
195 break;
196 case Manifest::EXTERNAL_PREF:
197 case Manifest::EXTERNAL_REGISTRY:
198 case Manifest::EXTERNAL_PREF_DOWNLOAD:
199 info->install_type = management::EXTENSION_INSTALL_TYPE_SIDELOAD;
200 break;
201 case Manifest::EXTERNAL_POLICY:
202 case Manifest::EXTERNAL_POLICY_DOWNLOAD:
203 info->install_type = management::EXTENSION_INSTALL_TYPE_ADMIN;
204 break;
205 case Manifest::NUM_LOCATIONS:
206 NOTREACHED();
207 case Manifest::INVALID_LOCATION:
208 case Manifest::COMPONENT:
209 case Manifest::EXTERNAL_COMPONENT:
210 info->install_type = management::EXTENSION_INSTALL_TYPE_OTHER;
211 break;
214 info->launch_type = management::LAUNCH_TYPE_NONE;
215 if (extension.is_app()) {
216 LaunchType launch_type;
217 if (extension.is_platform_app()) {
218 launch_type = LAUNCH_TYPE_WINDOW;
219 } else {
220 launch_type =
221 delegate->GetLaunchType(ExtensionPrefs::Get(context), &extension);
224 switch (launch_type) {
225 case LAUNCH_TYPE_PINNED:
226 info->launch_type = management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB;
227 break;
228 case LAUNCH_TYPE_REGULAR:
229 info->launch_type = management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB;
230 break;
231 case LAUNCH_TYPE_FULLSCREEN:
232 info->launch_type = management::LAUNCH_TYPE_OPEN_FULL_SCREEN;
233 break;
234 case LAUNCH_TYPE_WINDOW:
235 info->launch_type = management::LAUNCH_TYPE_OPEN_AS_WINDOW;
236 break;
237 case LAUNCH_TYPE_INVALID:
238 case NUM_LAUNCH_TYPES:
239 NOTREACHED();
242 info->available_launch_types.reset(new std::vector<management::LaunchType>(
243 GetAvailableLaunchTypes(extension, delegate)));
246 return info.Pass();
249 bool ShouldNotBeVisible(const Extension* extension,
250 content::BrowserContext* context) {
251 return (extension->ShouldNotBeVisible() ||
252 ExtensionPrefs::Get(context)->IsEphemeralApp(extension->id()));
255 void AddExtensionInfo(const ExtensionSet& extensions,
256 ExtensionInfoList* extension_list,
257 content::BrowserContext* context) {
258 for (ExtensionSet::const_iterator iter = extensions.begin();
259 iter != extensions.end(); ++iter) {
260 const Extension& extension = *iter->get();
262 if (ShouldNotBeVisible(&extension, context))
263 continue; // Skip built-in extensions/apps.
265 extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
266 CreateExtensionInfo(extension, context).release()));
270 } // namespace
272 bool ManagementGetAllFunction::RunSync() {
273 ExtensionInfoList extensions;
274 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
276 AddExtensionInfo(registry->enabled_extensions(), &extensions,
277 browser_context());
278 AddExtensionInfo(registry->disabled_extensions(), &extensions,
279 browser_context());
280 AddExtensionInfo(registry->terminated_extensions(), &extensions,
281 browser_context());
283 results_ = management::GetAll::Results::Create(extensions);
284 return true;
287 bool ManagementGetFunction::RunSync() {
288 scoped_ptr<management::Get::Params> params(
289 management::Get::Params::Create(*args_));
290 EXTENSION_FUNCTION_VALIDATE(params.get());
291 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
293 const Extension* extension =
294 registry->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
295 if (!extension) {
296 error_ =
297 ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
298 return false;
301 scoped_ptr<management::ExtensionInfo> info =
302 CreateExtensionInfo(*extension, browser_context());
303 results_ = management::Get::Results::Create(*info);
305 return true;
308 bool ManagementGetSelfFunction::RunSync() {
309 scoped_ptr<management::ExtensionInfo> info =
310 CreateExtensionInfo(*extension_, browser_context());
311 results_ = management::Get::Results::Create(*info);
313 return true;
316 bool ManagementGetPermissionWarningsByIdFunction::RunSync() {
317 scoped_ptr<management::GetPermissionWarningsById::Params> params(
318 management::GetPermissionWarningsById::Params::Create(*args_));
319 EXTENSION_FUNCTION_VALIDATE(params.get());
321 const Extension* extension =
322 ExtensionRegistry::Get(browser_context())
323 ->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
324 if (!extension) {
325 error_ =
326 ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
327 return false;
330 std::vector<std::string> warnings = CreateWarningsList(extension);
331 results_ = management::GetPermissionWarningsById::Results::Create(warnings);
332 return true;
335 bool ManagementGetPermissionWarningsByManifestFunction::RunAsync() {
336 scoped_ptr<management::GetPermissionWarningsByManifest::Params> params(
337 management::GetPermissionWarningsByManifest::Params::Create(*args_));
338 EXTENSION_FUNCTION_VALIDATE(params.get());
340 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
341 ->Get(browser_context())
342 ->GetDelegate();
344 if (delegate) {
345 delegate->GetPermissionWarningsByManifestFunctionDelegate(
346 this, params->manifest_str);
348 // Matched with a Release() in OnParseSuccess/Failure().
349 AddRef();
351 // Response is sent async in OnParseSuccess/Failure().
352 return true;
353 } else {
354 // TODO(lfg) add error string
355 OnParseFailure("");
356 return false;
360 void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
361 scoped_ptr<base::Value> value) {
362 if (!value->IsType(base::Value::TYPE_DICTIONARY)) {
363 OnParseFailure(keys::kManifestParseError);
364 return;
366 const base::DictionaryValue* parsed_manifest =
367 static_cast<const base::DictionaryValue*>(value.get());
369 scoped_refptr<Extension> extension =
370 Extension::Create(base::FilePath(), Manifest::INVALID_LOCATION,
371 *parsed_manifest, Extension::NO_FLAGS, &error_);
372 if (!extension) {
373 OnParseFailure(keys::kExtensionCreateError);
374 return;
377 std::vector<std::string> warnings = CreateWarningsList(extension.get());
378 results_ =
379 management::GetPermissionWarningsByManifest::Results::Create(warnings);
380 SendResponse(true);
382 // Matched with AddRef() in RunAsync().
383 Release();
386 void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure(
387 const std::string& error) {
388 error_ = error;
389 SendResponse(false);
391 // Matched with AddRef() in RunAsync().
392 Release();
395 bool ManagementLaunchAppFunction::RunSync() {
396 scoped_ptr<management::LaunchApp::Params> params(
397 management::LaunchApp::Params::Create(*args_));
398 EXTENSION_FUNCTION_VALIDATE(params.get());
399 const Extension* extension =
400 ExtensionRegistry::Get(browser_context())
401 ->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
402 if (!extension) {
403 error_ =
404 ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
405 return false;
407 if (!extension->is_app()) {
408 error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
409 return false;
412 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
413 ->Get(browser_context())
414 ->GetDelegate();
415 return delegate->LaunchAppFunctionDelegate(extension, browser_context());
418 ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
421 ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
424 ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
425 scoped_ptr<management::SetEnabled::Params> params(
426 management::SetEnabled::Params::Create(*args_));
427 EXTENSION_FUNCTION_VALIDATE(params.get());
428 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
429 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
430 ->Get(browser_context())
431 ->GetDelegate();
433 extension_id_ = params->id;
435 const Extension* extension =
436 registry->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
437 if (!extension || ShouldNotBeVisible(extension, browser_context()))
438 return RespondNow(Error(keys::kNoExtensionError, extension_id_));
440 bool enabled = params->enabled;
441 const ManagementPolicy* policy =
442 ExtensionSystem::Get(browser_context())->management_policy();
443 if (!policy->UserMayModifySettings(extension, nullptr) ||
444 (!enabled && policy->MustRemainEnabled(extension, nullptr)) ||
445 (enabled && policy->MustRemainDisabled(extension, nullptr, nullptr))) {
446 return RespondNow(Error(keys::kUserCantModifyError, extension_id_));
449 bool currently_enabled =
450 registry->enabled_extensions().Contains(extension_id_) ||
451 registry->terminated_extensions().Contains(extension_id_);
453 if (!currently_enabled && enabled) {
454 ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
455 if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
456 if (!user_gesture())
457 return RespondNow(Error(keys::kGestureNeededForEscalationError));
459 AddRef(); // Matched in InstallUIProceed/InstallUIAbort
460 install_prompt_ = delegate->SetEnabledFunctionDelegate(this, extension);
461 return RespondLater();
463 if (prefs->GetDisableReasons(extension_id_) &
464 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) {
465 // Recheck the requirements.
466 requirements_checker_ = delegate->CreateRequirementsChecker();
467 requirements_checker_->Check(
468 extension,
469 base::Bind(&ManagementSetEnabledFunction::OnRequirementsChecked,
470 this)); // This bind creates a reference.
471 return RespondLater();
473 delegate->EnableExtension(browser_context(), extension_id_);
474 } else if (currently_enabled && !params->enabled) {
475 delegate->DisableExtension(browser_context(), extension_id_,
476 Extension::DISABLE_USER_ACTION);
479 return RespondNow(NoArguments());
482 void ManagementSetEnabledFunction::InstallUIProceed() {
483 ManagementAPI::GetFactoryInstance()
484 ->Get(browser_context())
485 ->GetDelegate()
486 ->EnableExtension(browser_context(), extension_id_);
487 Respond(OneArgument(new base::FundamentalValue(true)));
488 Release();
491 void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) {
492 Respond(Error(keys::kUserDidNotReEnableError));
493 Release();
496 void ManagementSetEnabledFunction::OnRequirementsChecked(
497 const std::vector<std::string>& requirements_errors) {
498 if (requirements_errors.empty()) {
499 ManagementAPI::GetFactoryInstance()->Get(browser_context())->GetDelegate()->
500 EnableExtension(browser_context(), extension_id_);
501 Respond(NoArguments());
502 } else {
503 // TODO(devlin): Should we really be noisy here all the time?
504 Respond(Error(keys::kMissingRequirementsError,
505 base::JoinString(requirements_errors, " ")));
509 ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
512 ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() {
515 ExtensionFunction::ResponseAction ManagementUninstallFunctionBase::Uninstall(
516 const std::string& target_extension_id,
517 bool show_confirm_dialog) {
518 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
519 ->Get(browser_context())
520 ->GetDelegate();
521 target_extension_id_ = target_extension_id;
522 const Extension* target_extension =
523 extensions::ExtensionRegistry::Get(browser_context())
524 ->GetExtensionById(target_extension_id_,
525 ExtensionRegistry::EVERYTHING);
526 if (!target_extension ||
527 ShouldNotBeVisible(target_extension, browser_context())) {
528 return RespondNow(Error(keys::kNoExtensionError, target_extension_id_));
531 ManagementPolicy* policy =
532 ExtensionSystem::Get(browser_context())->management_policy();
533 if (!policy->UserMayModifySettings(target_extension, nullptr) ||
534 policy->MustRemainInstalled(target_extension, nullptr)) {
535 return RespondNow(Error(keys::kUserCantModifyError, target_extension_id_));
538 // Note: null extension() means it's WebUI.
539 bool self_uninstall = extension() && extension_id() == target_extension_id_;
540 // We need to show a dialog for any extension uninstalling another extension.
541 show_confirm_dialog |= !self_uninstall;
543 if (show_confirm_dialog && !user_gesture())
544 return RespondNow(Error(keys::kGestureNeededForUninstallError));
546 if (show_confirm_dialog) {
547 // We show the programmatic uninstall ui for extensions uninstalling
548 // other extensions.
549 bool show_programmatic_uninstall_ui = !self_uninstall && extension();
550 AddRef(); // Balanced in OnExtensionUninstallDialogClosed.
551 // TODO(devlin): A method called "UninstallFunctionDelegate" does not in
552 // any way imply that this actually creates a dialog and runs it.
553 uninstall_dialog_ = delegate->UninstallFunctionDelegate(
554 this, target_extension, show_programmatic_uninstall_ui);
555 } else { // No confirm dialog.
556 base::MessageLoop::current()->PostTask(
557 FROM_HERE,
558 base::Bind(&ManagementUninstallFunctionBase::UninstallExtension, this));
561 return RespondLater();
564 void ManagementUninstallFunctionBase::Finish(bool did_start_uninstall,
565 const std::string& error) {
566 Respond(did_start_uninstall ? NoArguments() : Error(error));
569 void ManagementUninstallFunctionBase::OnExtensionUninstallDialogClosed(
570 bool did_start_uninstall,
571 const base::string16& error) {
572 Finish(did_start_uninstall,
573 ErrorUtils::FormatErrorMessage(keys::kUninstallCanceledError,
574 target_extension_id_));
575 Release(); // Balanced in Uninstall().
578 void ManagementUninstallFunctionBase::UninstallExtension() {
579 // The extension can be uninstalled in another window while the UI was
580 // showing. Do nothing in that case.
581 const Extension* target_extension =
582 extensions::ExtensionRegistry::Get(browser_context())
583 ->GetExtensionById(target_extension_id_,
584 ExtensionRegistry::EVERYTHING);
585 std::string error;
586 bool success = false;
587 if (target_extension) {
588 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
589 ->Get(browser_context())
590 ->GetDelegate();
591 base::string16 utf16_error;
592 success = delegate->UninstallExtension(
593 browser_context(), target_extension_id_,
594 extensions::UNINSTALL_REASON_MANAGEMENT_API,
595 base::Bind(&base::DoNothing), &utf16_error);
596 error = base::UTF16ToUTF8(utf16_error);
597 } else {
598 error = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
599 target_extension_id_);
601 Finish(success, error);
604 ManagementUninstallFunction::ManagementUninstallFunction() {
607 ManagementUninstallFunction::~ManagementUninstallFunction() {
610 ExtensionFunction::ResponseAction ManagementUninstallFunction::Run() {
611 scoped_ptr<management::Uninstall::Params> params(
612 management::Uninstall::Params::Create(*args_));
613 EXTENSION_FUNCTION_VALIDATE(params.get());
615 bool show_confirm_dialog = params->options.get() &&
616 params->options->show_confirm_dialog.get() &&
617 *params->options->show_confirm_dialog;
618 return Uninstall(params->id, show_confirm_dialog);
621 ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
624 ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
627 ExtensionFunction::ResponseAction ManagementUninstallSelfFunction::Run() {
628 scoped_ptr<management::UninstallSelf::Params> params(
629 management::UninstallSelf::Params::Create(*args_));
630 EXTENSION_FUNCTION_VALIDATE(params.get());
631 EXTENSION_FUNCTION_VALIDATE(extension_.get());
633 bool show_confirm_dialog = params->options.get() &&
634 params->options->show_confirm_dialog.get() &&
635 *params->options->show_confirm_dialog;
636 return Uninstall(extension_->id(), show_confirm_dialog);
639 ManagementCreateAppShortcutFunction::ManagementCreateAppShortcutFunction() {
642 ManagementCreateAppShortcutFunction::~ManagementCreateAppShortcutFunction() {
645 // static
646 void ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(
647 bool should_proceed) {
648 auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
651 void ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt(bool created) {
652 if (!created)
653 error_ = keys::kCreateShortcutCanceledError;
654 SendResponse(created);
655 Release();
658 bool ManagementCreateAppShortcutFunction::RunAsync() {
659 if (!user_gesture()) {
660 error_ = keys::kGestureNeededForCreateAppShortcutError;
661 return false;
664 scoped_ptr<management::CreateAppShortcut::Params> params(
665 management::CreateAppShortcut::Params::Create(*args_));
666 EXTENSION_FUNCTION_VALIDATE(params.get());
667 const Extension* extension =
668 ExtensionRegistry::Get(browser_context())
669 ->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
670 if (!extension) {
671 error_ =
672 ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
673 return false;
676 if (!extension->is_app()) {
677 error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
678 return false;
681 #if defined(OS_MACOSX)
682 if (!extension->is_platform_app()) {
683 error_ = keys::kCreateOnlyPackagedAppShortcutMac;
684 return false;
686 #endif
688 if (auto_confirm_for_test != DO_NOT_SKIP) {
689 // Matched with a Release() in OnCloseShortcutPrompt().
690 AddRef();
692 OnCloseShortcutPrompt(auto_confirm_for_test == PROCEED);
694 return true;
697 if (ManagementAPI::GetFactoryInstance()
698 ->Get(browser_context())
699 ->GetDelegate()
700 ->CreateAppShortcutFunctionDelegate(this, extension)) {
701 // Matched with a Release() in OnCloseShortcutPrompt().
702 AddRef();
705 // Response is sent async in OnCloseShortcutPrompt().
706 return true;
709 bool ManagementSetLaunchTypeFunction::RunSync() {
710 if (!user_gesture()) {
711 error_ = keys::kGestureNeededForSetLaunchTypeError;
712 return false;
715 scoped_ptr<management::SetLaunchType::Params> params(
716 management::SetLaunchType::Params::Create(*args_));
717 EXTENSION_FUNCTION_VALIDATE(params.get());
718 const Extension* extension =
719 ExtensionRegistry::Get(browser_context())
720 ->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
721 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
722 ->Get(browser_context())
723 ->GetDelegate();
724 if (!extension) {
725 error_ =
726 ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
727 return false;
730 if (!extension->is_app()) {
731 error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
732 return false;
735 std::vector<management::LaunchType> available_launch_types =
736 GetAvailableLaunchTypes(*extension, delegate);
738 management::LaunchType app_launch_type = params->launch_type;
739 if (std::find(available_launch_types.begin(), available_launch_types.end(),
740 app_launch_type) == available_launch_types.end()) {
741 error_ = keys::kLaunchTypeNotAvailableError;
742 return false;
745 LaunchType launch_type = LAUNCH_TYPE_DEFAULT;
746 switch (app_launch_type) {
747 case management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB:
748 launch_type = LAUNCH_TYPE_PINNED;
749 break;
750 case management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB:
751 launch_type = LAUNCH_TYPE_REGULAR;
752 break;
753 case management::LAUNCH_TYPE_OPEN_FULL_SCREEN:
754 launch_type = LAUNCH_TYPE_FULLSCREEN;
755 break;
756 case management::LAUNCH_TYPE_OPEN_AS_WINDOW:
757 launch_type = LAUNCH_TYPE_WINDOW;
758 break;
759 case management::LAUNCH_TYPE_NONE:
760 NOTREACHED();
763 delegate->SetLaunchType(browser_context(), params->id, launch_type);
765 return true;
768 ManagementGenerateAppForLinkFunction::ManagementGenerateAppForLinkFunction() {
771 ManagementGenerateAppForLinkFunction::~ManagementGenerateAppForLinkFunction() {
774 void ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp(
775 const Extension* extension,
776 const WebApplicationInfo& web_app_info) {
777 if (extension) {
778 scoped_ptr<management::ExtensionInfo> info =
779 CreateExtensionInfo(*extension, browser_context());
780 results_ = management::GenerateAppForLink::Results::Create(*info);
782 SendResponse(true);
783 Release();
784 } else {
785 error_ = keys::kGenerateAppForLinkInstallError;
786 SendResponse(false);
787 Release();
791 bool ManagementGenerateAppForLinkFunction::RunAsync() {
792 if (!user_gesture()) {
793 error_ = keys::kGestureNeededForGenerateAppForLinkError;
794 return false;
797 scoped_ptr<management::GenerateAppForLink::Params> params(
798 management::GenerateAppForLink::Params::Create(*args_));
799 EXTENSION_FUNCTION_VALIDATE(params.get());
801 GURL launch_url(params->url);
802 if (!launch_url.is_valid() || !launch_url.SchemeIsHTTPOrHTTPS()) {
803 error_ =
804 ErrorUtils::FormatErrorMessage(keys::kInvalidURLError, params->url);
805 return false;
808 if (params->title.empty()) {
809 error_ = keys::kEmptyTitleError;
810 return false;
813 app_for_link_delegate_ =
814 ManagementAPI::GetFactoryInstance()
815 ->Get(browser_context())
816 ->GetDelegate()
817 ->GenerateAppForLinkFunctionDelegate(this, browser_context(),
818 params->title, launch_url);
820 // Matched with a Release() in FinishCreateBookmarkApp().
821 AddRef();
823 // Response is sent async in FinishCreateBookmarkApp().
824 return true;
827 ManagementEventRouter::ManagementEventRouter(content::BrowserContext* context)
828 : browser_context_(context), extension_registry_observer_(this) {
829 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
832 ManagementEventRouter::~ManagementEventRouter() {
835 void ManagementEventRouter::OnExtensionLoaded(
836 content::BrowserContext* browser_context,
837 const Extension* extension) {
838 BroadcastEvent(extension, events::MANAGEMENT_ON_ENABLED,
839 management::OnEnabled::kEventName);
842 void ManagementEventRouter::OnExtensionUnloaded(
843 content::BrowserContext* browser_context,
844 const Extension* extension,
845 UnloadedExtensionInfo::Reason reason) {
846 BroadcastEvent(extension, events::MANAGEMENT_ON_DISABLED,
847 management::OnDisabled::kEventName);
850 void ManagementEventRouter::OnExtensionInstalled(
851 content::BrowserContext* browser_context,
852 const Extension* extension,
853 bool is_update) {
854 BroadcastEvent(extension, events::MANAGEMENT_ON_INSTALLED,
855 management::OnInstalled::kEventName);
858 void ManagementEventRouter::OnExtensionUninstalled(
859 content::BrowserContext* browser_context,
860 const Extension* extension,
861 extensions::UninstallReason reason) {
862 BroadcastEvent(extension, events::MANAGEMENT_ON_UNINSTALLED,
863 management::OnUninstalled::kEventName);
866 void ManagementEventRouter::BroadcastEvent(
867 const Extension* extension,
868 events::HistogramValue histogram_value,
869 const char* event_name) {
870 if (ShouldNotBeVisible(extension, browser_context_))
871 return; // Don't dispatch events for built-in extenions.
872 scoped_ptr<base::ListValue> args(new base::ListValue());
873 if (event_name == management::OnUninstalled::kEventName) {
874 args->Append(new base::StringValue(extension->id()));
875 } else {
876 scoped_ptr<management::ExtensionInfo> info =
877 CreateExtensionInfo(*extension, browser_context_);
878 args->Append(info->ToValue().release());
881 EventRouter::Get(browser_context_)
882 ->BroadcastEvent(scoped_ptr<Event>(
883 new Event(histogram_value, event_name, args.Pass())));
886 ManagementAPI::ManagementAPI(content::BrowserContext* context)
887 : browser_context_(context),
888 delegate_(ExtensionsAPIClient::Get()->CreateManagementAPIDelegate()) {
889 EventRouter* event_router = EventRouter::Get(browser_context_);
890 event_router->RegisterObserver(this, management::OnInstalled::kEventName);
891 event_router->RegisterObserver(this, management::OnUninstalled::kEventName);
892 event_router->RegisterObserver(this, management::OnEnabled::kEventName);
893 event_router->RegisterObserver(this, management::OnDisabled::kEventName);
896 ManagementAPI::~ManagementAPI() {
899 void ManagementAPI::Shutdown() {
900 EventRouter::Get(browser_context_)->UnregisterObserver(this);
903 static base::LazyInstance<BrowserContextKeyedAPIFactory<ManagementAPI>>
904 g_factory = LAZY_INSTANCE_INITIALIZER;
906 // static
907 BrowserContextKeyedAPIFactory<ManagementAPI>*
908 ManagementAPI::GetFactoryInstance() {
909 return g_factory.Pointer();
912 void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
913 management_event_router_.reset(new ManagementEventRouter(browser_context_));
914 EventRouter::Get(browser_context_)->UnregisterObserver(this);
917 } // namespace extensions