blob: fc043c0a0cc88bc1a51e920661d85ad203a9a8c2 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/api/management/management_api.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/management/management_api_constants.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/management_policy.h"
#include "extensions/browser/requirements_checker.h"
#include "extensions/browser/uninstall_reason.h"
#include "extensions/common/api/management.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_icon_set.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/manifest_handlers/offline_enabled_info.h"
#include "extensions/common/manifest_handlers/options_page_info.h"
#include "extensions/common/manifest_url_handlers.h"
#include "extensions/common/permissions/permission_message.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/url_pattern.h"
using base::IntToString;
using content::BrowserThread;
namespace keys = extension_management_api_constants;
namespace extensions {
namespace management = api::management;
namespace {
typedef std::vector<management::ExtensionInfo> ExtensionInfoList;
typedef std::vector<management::IconInfo> IconInfoList;
enum AutoConfirmForTest { DO_NOT_SKIP = 0, PROCEED, ABORT };
AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
std::vector<std::string> CreateWarningsList(const Extension* extension) {
std::vector<std::string> warnings_list;
for (const PermissionMessage& msg :
extension->permissions_data()->GetPermissionMessages()) {
warnings_list.push_back(base::UTF16ToUTF8(msg.message()));
}
return warnings_list;
}
std::vector<management::LaunchType> GetAvailableLaunchTypes(
const Extension& extension,
const ManagementAPIDelegate* delegate) {
std::vector<management::LaunchType> launch_type_list;
if (extension.is_platform_app()) {
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
return launch_type_list;
}
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB);
// TODO(dominickn): remove check when hosted apps can open in windows on Mac.
if (delegate->CanHostedAppsOpenInWindows())
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
if (!delegate->IsNewBookmarkAppsEnabled()) {
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB);
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_FULL_SCREEN);
}
return launch_type_list;
}
management::ExtensionInfo CreateExtensionInfo(
const Extension& extension,
content::BrowserContext* context) {
ExtensionSystem* system = ExtensionSystem::Get(context);
ExtensionRegistry* registry = ExtensionRegistry::Get(context);
const ManagementAPIDelegate* delegate =
ManagementAPI::GetFactoryInstance()->Get(context)->GetDelegate();
management::ExtensionInfo info;
info.id = extension.id();
info.name = extension.name();
info.short_name = extension.short_name();
info.enabled = registry->enabled_extensions().Contains(info.id);
info.offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension);
info.version = extension.VersionString();
if (!extension.version_name().empty())
info.version_name.reset(new std::string(extension.version_name()));
info.description = extension.description();
info.options_url = OptionsPageInfo::GetOptionsPage(&extension).spec();
info.homepage_url.reset(
new std::string(ManifestURL::GetHomepageURL(&extension).spec()));
info.may_disable =
system->management_policy()->UserMayModifySettings(&extension, NULL);
info.is_app = extension.is_app();
if (info.is_app) {
if (extension.is_legacy_packaged_app())
info.type = management::EXTENSION_TYPE_LEGACY_PACKAGED_APP;
else if (extension.is_hosted_app())
info.type = management::EXTENSION_TYPE_HOSTED_APP;
else
info.type = management::EXTENSION_TYPE_PACKAGED_APP;
} else if (extension.is_theme()) {
info.type = management::EXTENSION_TYPE_THEME;
} else {
info.type = management::EXTENSION_TYPE_EXTENSION;
}
if (info.enabled) {
info.disabled_reason = management::EXTENSION_DISABLED_REASON_NONE;
} else {
ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
if (prefs->DidExtensionEscalatePermissions(extension.id())) {
info.disabled_reason =
management::EXTENSION_DISABLED_REASON_PERMISSIONS_INCREASE;
} else {
info.disabled_reason = management::EXTENSION_DISABLED_REASON_UNKNOWN;
}
}
if (!ManifestURL::GetUpdateURL(&extension).is_empty()) {
info.update_url.reset(
new std::string(ManifestURL::GetUpdateURL(&extension).spec()));
}
if (extension.is_app()) {
info.app_launch_url.reset(
new std::string(delegate->GetFullLaunchURL(&extension).spec()));
}
const ExtensionIconSet::IconMap& icons =
IconsInfo::GetIcons(&extension).map();
if (!icons.empty()) {
info.icons.reset(new IconInfoList());
ExtensionIconSet::IconMap::const_iterator icon_iter;
for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) {
management::IconInfo icon_info;
icon_info.size = icon_iter->first;
GURL url =
delegate->GetIconURL(&extension, icon_info.size,
ExtensionIconSet::MATCH_EXACTLY, false, nullptr);
icon_info.url = url.spec();
info.icons->push_back(std::move(icon_info));
}
}
const std::set<std::string> perms =
extension.permissions_data()->active_permissions().GetAPIsAsStrings();
if (!perms.empty()) {
std::set<std::string>::const_iterator perms_iter;
for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter)
info.permissions.push_back(*perms_iter);
}
if (!extension.is_hosted_app()) {
// Skip host permissions for hosted apps.
const URLPatternSet host_perms =
extension.permissions_data()->active_permissions().explicit_hosts();
if (!host_perms.is_empty()) {
for (URLPatternSet::const_iterator iter = host_perms.begin();
iter != host_perms.end(); ++iter) {
info.host_permissions.push_back(iter->GetAsString());
}
}
}
switch (extension.location()) {
case Manifest::INTERNAL:
info.install_type = management::EXTENSION_INSTALL_TYPE_NORMAL;
break;
case Manifest::UNPACKED:
case Manifest::COMMAND_LINE:
info.install_type = management::EXTENSION_INSTALL_TYPE_DEVELOPMENT;
break;
case Manifest::EXTERNAL_PREF:
case Manifest::EXTERNAL_REGISTRY:
case Manifest::EXTERNAL_PREF_DOWNLOAD:
info.install_type = management::EXTENSION_INSTALL_TYPE_SIDELOAD;
break;
case Manifest::EXTERNAL_POLICY:
case Manifest::EXTERNAL_POLICY_DOWNLOAD:
info.install_type = management::EXTENSION_INSTALL_TYPE_ADMIN;
break;
case Manifest::NUM_LOCATIONS:
NOTREACHED();
case Manifest::INVALID_LOCATION:
case Manifest::COMPONENT:
case Manifest::EXTERNAL_COMPONENT:
info.install_type = management::EXTENSION_INSTALL_TYPE_OTHER;
break;
}
info.launch_type = management::LAUNCH_TYPE_NONE;
if (extension.is_app()) {
LaunchType launch_type;
if (extension.is_platform_app()) {
launch_type = LAUNCH_TYPE_WINDOW;
} else {
launch_type =
delegate->GetLaunchType(ExtensionPrefs::Get(context), &extension);
}
switch (launch_type) {
case LAUNCH_TYPE_PINNED:
info.launch_type = management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB;
break;
case LAUNCH_TYPE_REGULAR:
info.launch_type = management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB;
break;
case LAUNCH_TYPE_FULLSCREEN:
info.launch_type = management::LAUNCH_TYPE_OPEN_FULL_SCREEN;
break;
case LAUNCH_TYPE_WINDOW:
info.launch_type = management::LAUNCH_TYPE_OPEN_AS_WINDOW;
break;
case LAUNCH_TYPE_INVALID:
case NUM_LAUNCH_TYPES:
NOTREACHED();
}
info.available_launch_types.reset(new std::vector<management::LaunchType>(
GetAvailableLaunchTypes(extension, delegate)));
}
return info;
}
void AddExtensionInfo(const ExtensionSet& extensions,
ExtensionInfoList* extension_list,
content::BrowserContext* context) {
for (ExtensionSet::const_iterator iter = extensions.begin();
iter != extensions.end(); ++iter) {
const Extension& extension = *iter->get();
if (extension.ShouldNotBeVisible())
continue; // Skip built-in extensions/apps.
extension_list->push_back(CreateExtensionInfo(extension, context));
}
}
} // namespace
bool ManagementGetAllFunction::RunSync() {
ExtensionInfoList extensions;
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
AddExtensionInfo(registry->enabled_extensions(), &extensions,
browser_context());
AddExtensionInfo(registry->disabled_extensions(), &extensions,
browser_context());
AddExtensionInfo(registry->terminated_extensions(), &extensions,
browser_context());
results_ = management::GetAll::Results::Create(extensions);
return true;
}
bool ManagementGetFunction::RunSync() {
std::unique_ptr<management::Get::Params> params(
management::Get::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
const Extension* extension =
registry->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
if (!extension) {
error_ =
ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
return false;
}
results_ = management::Get::Results::Create(
CreateExtensionInfo(*extension, browser_context()));
return true;
}
bool ManagementGetSelfFunction::RunSync() {
results_ = management::Get::Results::Create(
CreateExtensionInfo(*extension_, browser_context()));
return true;
}
bool ManagementGetPermissionWarningsByIdFunction::RunSync() {
std::unique_ptr<management::GetPermissionWarningsById::Params> params(
management::GetPermissionWarningsById::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const Extension* extension =
ExtensionRegistry::Get(browser_context())
->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
if (!extension) {
error_ =
ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
return false;
}
std::vector<std::string> warnings = CreateWarningsList(extension);
results_ = management::GetPermissionWarningsById::Results::Create(warnings);
return true;
}
bool ManagementGetPermissionWarningsByManifestFunction::RunAsync() {
std::unique_ptr<management::GetPermissionWarningsByManifest::Params> params(
management::GetPermissionWarningsByManifest::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetDelegate();
if (delegate) {
delegate->GetPermissionWarningsByManifestFunctionDelegate(
this, params->manifest_str);
// Matched with a Release() in OnParseSuccess/Failure().
AddRef();
// Response is sent async in OnParseSuccess/Failure().
return true;
} else {
// TODO(lfg) add error string
OnParseFailure("");
return false;
}
}
void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
std::unique_ptr<base::Value> value) {
if (!value->IsType(base::Value::TYPE_DICTIONARY)) {
OnParseFailure(keys::kManifestParseError);
return;
}
const base::DictionaryValue* parsed_manifest =
static_cast<const base::DictionaryValue*>(value.get());
scoped_refptr<Extension> extension =
Extension::Create(base::FilePath(), Manifest::INVALID_LOCATION,
*parsed_manifest, Extension::NO_FLAGS, &error_);
if (!extension) {
OnParseFailure(keys::kExtensionCreateError);
return;
}
std::vector<std::string> warnings = CreateWarningsList(extension.get());
results_ =
management::GetPermissionWarningsByManifest::Results::Create(warnings);
SendResponse(true);
// Matched with AddRef() in RunAsync().
Release();
}
void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure(
const std::string& error) {
error_ = error;
SendResponse(false);
// Matched with AddRef() in RunAsync().
Release();
}
bool ManagementLaunchAppFunction::RunSync() {
std::unique_ptr<management::LaunchApp::Params> params(
management::LaunchApp::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const Extension* extension =
ExtensionRegistry::Get(browser_context())
->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
if (!extension) {
error_ =
ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
return false;
}
if (!extension->is_app()) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
return false;
}
const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetDelegate();
return delegate->LaunchAppFunctionDelegate(extension, browser_context());
}
ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
}
ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
}
ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
std::unique_ptr<management::SetEnabled::Params> params(
management::SetEnabled::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetDelegate();
extension_id_ = params->id;
const Extension* extension =
registry->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
if (!extension || extension->ShouldNotBeVisible())
return RespondNow(Error(keys::kNoExtensionError, extension_id_));
bool enabled = params->enabled;
const ManagementPolicy* policy =
ExtensionSystem::Get(browser_context())->management_policy();
if (!policy->UserMayModifySettings(extension, nullptr) ||
(!enabled && policy->MustRemainEnabled(extension, nullptr)) ||
(enabled && policy->MustRemainDisabled(extension, nullptr, nullptr))) {
return RespondNow(Error(keys::kUserCantModifyError, extension_id_));
}
bool currently_enabled =
registry->enabled_extensions().Contains(extension_id_) ||
registry->terminated_extensions().Contains(extension_id_);
if (!currently_enabled && enabled) {
ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
if (!user_gesture())
return RespondNow(Error(keys::kGestureNeededForEscalationError));
AddRef(); // Matched in OnInstallPromptDone().
install_prompt_ = delegate->SetEnabledFunctionDelegate(
GetSenderWebContents(), browser_context(), extension,
base::Bind(&ManagementSetEnabledFunction::OnInstallPromptDone, this));
return RespondLater();
}
if (prefs->GetDisableReasons(extension_id_) &
Extension::DISABLE_UNSUPPORTED_REQUIREMENT) {
// Recheck the requirements.
requirements_checker_ = delegate->CreateRequirementsChecker();
requirements_checker_->Check(
extension,
base::Bind(&ManagementSetEnabledFunction::OnRequirementsChecked,
this)); // This bind creates a reference.
return RespondLater();
}
delegate->EnableExtension(browser_context(), extension_id_);
} else if (currently_enabled && !params->enabled) {
delegate->DisableExtension(browser_context(), extension_id_,
Extension::DISABLE_USER_ACTION);
}
return RespondNow(NoArguments());
}
void ManagementSetEnabledFunction::OnInstallPromptDone(bool did_accept) {
if (did_accept) {
ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetDelegate()
->EnableExtension(browser_context(), extension_id_);
Respond(OneArgument(base::MakeUnique<base::FundamentalValue>(true)));
} else {
Respond(Error(keys::kUserDidNotReEnableError));
}
Release(); // Balanced in Run().
}
void ManagementSetEnabledFunction::OnRequirementsChecked(
const std::vector<std::string>& requirements_errors) {
if (requirements_errors.empty()) {
ManagementAPI::GetFactoryInstance()->Get(browser_context())->GetDelegate()->
EnableExtension(browser_context(), extension_id_);
Respond(NoArguments());
} else {
// TODO(devlin): Should we really be noisy here all the time?
Respond(Error(keys::kMissingRequirementsError,
base::JoinString(requirements_errors, " ")));
}
}
ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
}
ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() {
}
ExtensionFunction::ResponseAction ManagementUninstallFunctionBase::Uninstall(
const std::string& target_extension_id,
bool show_confirm_dialog) {
const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetDelegate();
target_extension_id_ = target_extension_id;
const Extension* target_extension =
extensions::ExtensionRegistry::Get(browser_context())
->GetExtensionById(target_extension_id_,
ExtensionRegistry::EVERYTHING);
if (!target_extension || target_extension->ShouldNotBeVisible()) {
return RespondNow(Error(keys::kNoExtensionError, target_extension_id_));
}
ManagementPolicy* policy =
ExtensionSystem::Get(browser_context())->management_policy();
if (!policy->UserMayModifySettings(target_extension, nullptr) ||
policy->MustRemainInstalled(target_extension, nullptr)) {
return RespondNow(Error(keys::kUserCantModifyError, target_extension_id_));
}
// Note: null extension() means it's WebUI.
bool self_uninstall = extension() && extension_id() == target_extension_id_;
// We need to show a dialog for any extension uninstalling another extension.
show_confirm_dialog |= !self_uninstall;
if (show_confirm_dialog && !user_gesture())
return RespondNow(Error(keys::kGestureNeededForUninstallError));
if (show_confirm_dialog) {
// We show the programmatic uninstall ui for extensions uninstalling
// other extensions.
bool show_programmatic_uninstall_ui = !self_uninstall && extension();
AddRef(); // Balanced in OnExtensionUninstallDialogClosed.
// TODO(devlin): A method called "UninstallFunctionDelegate" does not in
// any way imply that this actually creates a dialog and runs it.
uninstall_dialog_ = delegate->UninstallFunctionDelegate(
this, target_extension, show_programmatic_uninstall_ui);
} else { // No confirm dialog.
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&ManagementUninstallFunctionBase::UninstallExtension, this));
}
return RespondLater();
}
void ManagementUninstallFunctionBase::Finish(bool did_start_uninstall,
const std::string& error) {
Respond(did_start_uninstall ? NoArguments() : Error(error));
}
void ManagementUninstallFunctionBase::OnExtensionUninstallDialogClosed(
bool did_start_uninstall,
const base::string16& error) {
Finish(did_start_uninstall,
ErrorUtils::FormatErrorMessage(keys::kUninstallCanceledError,
target_extension_id_));
Release(); // Balanced in Uninstall().
}
void ManagementUninstallFunctionBase::UninstallExtension() {
// The extension can be uninstalled in another window while the UI was
// showing. Do nothing in that case.
const Extension* target_extension =
extensions::ExtensionRegistry::Get(browser_context())
->GetExtensionById(target_extension_id_,
ExtensionRegistry::EVERYTHING);
std::string error;
bool success = false;
if (target_extension) {
const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetDelegate();
base::string16 utf16_error;
success = delegate->UninstallExtension(
browser_context(), target_extension_id_,
extensions::UNINSTALL_REASON_MANAGEMENT_API,
base::Bind(&base::DoNothing), &utf16_error);
error = base::UTF16ToUTF8(utf16_error);
} else {
error = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
target_extension_id_);
}
Finish(success, error);
}
ManagementUninstallFunction::ManagementUninstallFunction() {
}
ManagementUninstallFunction::~ManagementUninstallFunction() {
}
ExtensionFunction::ResponseAction ManagementUninstallFunction::Run() {
std::unique_ptr<management::Uninstall::Params> params(
management::Uninstall::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
bool show_confirm_dialog = params->options.get() &&
params->options->show_confirm_dialog.get() &&
*params->options->show_confirm_dialog;
return Uninstall(params->id, show_confirm_dialog);
}
ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
}
ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
}
ExtensionFunction::ResponseAction ManagementUninstallSelfFunction::Run() {
std::unique_ptr<management::UninstallSelf::Params> params(
management::UninstallSelf::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
EXTENSION_FUNCTION_VALIDATE(extension_.get());
bool show_confirm_dialog = params->options.get() &&
params->options->show_confirm_dialog.get() &&
*params->options->show_confirm_dialog;
return Uninstall(extension_->id(), show_confirm_dialog);
}
ManagementCreateAppShortcutFunction::ManagementCreateAppShortcutFunction() {
}
ManagementCreateAppShortcutFunction::~ManagementCreateAppShortcutFunction() {
}
// static
void ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(
bool should_proceed) {
auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
}
void ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt(bool created) {
if (!created)
error_ = keys::kCreateShortcutCanceledError;
SendResponse(created);
Release();
}
bool ManagementCreateAppShortcutFunction::RunAsync() {
if (!user_gesture()) {
error_ = keys::kGestureNeededForCreateAppShortcutError;
return false;
}
std::unique_ptr<management::CreateAppShortcut::Params> params(
management::CreateAppShortcut::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const Extension* extension =
ExtensionRegistry::Get(browser_context())
->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
if (!extension) {
error_ =
ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
return false;
}
if (!extension->is_app()) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
return false;
}
#if defined(OS_MACOSX)
if (!extension->is_platform_app()) {
error_ = keys::kCreateOnlyPackagedAppShortcutMac;
return false;
}
#endif
if (auto_confirm_for_test != DO_NOT_SKIP) {
// Matched with a Release() in OnCloseShortcutPrompt().
AddRef();
OnCloseShortcutPrompt(auto_confirm_for_test == PROCEED);
return true;
}
if (ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetDelegate()
->CreateAppShortcutFunctionDelegate(this, extension)) {
// Matched with a Release() in OnCloseShortcutPrompt().
AddRef();
}
// Response is sent async in OnCloseShortcutPrompt().
return true;
}
bool ManagementSetLaunchTypeFunction::RunSync() {
if (!user_gesture()) {
error_ = keys::kGestureNeededForSetLaunchTypeError;
return false;
}
std::unique_ptr<management::SetLaunchType::Params> params(
management::SetLaunchType::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const Extension* extension =
ExtensionRegistry::Get(browser_context())
->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetDelegate();
if (!extension) {
error_ =
ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
return false;
}
if (!extension->is_app()) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
return false;
}
std::vector<management::LaunchType> available_launch_types =
GetAvailableLaunchTypes(*extension, delegate);
management::LaunchType app_launch_type = params->launch_type;
if (std::find(available_launch_types.begin(), available_launch_types.end(),
app_launch_type) == available_launch_types.end()) {
error_ = keys::kLaunchTypeNotAvailableError;
return false;
}
LaunchType launch_type = LAUNCH_TYPE_DEFAULT;
switch (app_launch_type) {
case management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB:
launch_type = LAUNCH_TYPE_PINNED;
break;
case management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB:
launch_type = LAUNCH_TYPE_REGULAR;
break;
case management::LAUNCH_TYPE_OPEN_FULL_SCREEN:
launch_type = LAUNCH_TYPE_FULLSCREEN;
break;
case management::LAUNCH_TYPE_OPEN_AS_WINDOW:
launch_type = LAUNCH_TYPE_WINDOW;
break;
case management::LAUNCH_TYPE_NONE:
NOTREACHED();
}
delegate->SetLaunchType(browser_context(), params->id, launch_type);
return true;
}
ManagementGenerateAppForLinkFunction::ManagementGenerateAppForLinkFunction() {
}
ManagementGenerateAppForLinkFunction::~ManagementGenerateAppForLinkFunction() {
}
void ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp(
const Extension* extension,
const WebApplicationInfo& web_app_info) {
if (extension) {
results_ = management::GenerateAppForLink::Results::Create(
CreateExtensionInfo(*extension, browser_context()));
SendResponse(true);
Release();
} else {
error_ = keys::kGenerateAppForLinkInstallError;
SendResponse(false);
Release();
}
}
bool ManagementGenerateAppForLinkFunction::RunAsync() {
if (!user_gesture()) {
error_ = keys::kGestureNeededForGenerateAppForLinkError;
return false;
}
std::unique_ptr<management::GenerateAppForLink::Params> params(
management::GenerateAppForLink::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
GURL launch_url(params->url);
if (!launch_url.is_valid() || !launch_url.SchemeIsHTTPOrHTTPS()) {
error_ =
ErrorUtils::FormatErrorMessage(keys::kInvalidURLError, params->url);
return false;
}
if (params->title.empty()) {
error_ = keys::kEmptyTitleError;
return false;
}
app_for_link_delegate_ =
ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetDelegate()
->GenerateAppForLinkFunctionDelegate(this, browser_context(),
params->title, launch_url);
// Matched with a Release() in FinishCreateBookmarkApp().
AddRef();
// Response is sent async in FinishCreateBookmarkApp().
return true;
}
ManagementEventRouter::ManagementEventRouter(content::BrowserContext* context)
: browser_context_(context), extension_registry_observer_(this) {
extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
}
ManagementEventRouter::~ManagementEventRouter() {
}
void ManagementEventRouter::OnExtensionLoaded(
content::BrowserContext* browser_context,
const Extension* extension) {
BroadcastEvent(extension, events::MANAGEMENT_ON_ENABLED,
management::OnEnabled::kEventName);
}
void ManagementEventRouter::OnExtensionUnloaded(
content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionInfo::Reason reason) {
BroadcastEvent(extension, events::MANAGEMENT_ON_DISABLED,
management::OnDisabled::kEventName);
}
void ManagementEventRouter::OnExtensionInstalled(
content::BrowserContext* browser_context,
const Extension* extension,
bool is_update) {
BroadcastEvent(extension, events::MANAGEMENT_ON_INSTALLED,
management::OnInstalled::kEventName);
}
void ManagementEventRouter::OnExtensionUninstalled(
content::BrowserContext* browser_context,
const Extension* extension,
extensions::UninstallReason reason) {
BroadcastEvent(extension, events::MANAGEMENT_ON_UNINSTALLED,
management::OnUninstalled::kEventName);
}
void ManagementEventRouter::BroadcastEvent(
const Extension* extension,
events::HistogramValue histogram_value,
const char* event_name) {
if (extension->ShouldNotBeVisible())
return; // Don't dispatch events for built-in extenions.
std::unique_ptr<base::ListValue> args(new base::ListValue());
if (event_name == management::OnUninstalled::kEventName) {
args->Append(new base::StringValue(extension->id()));
} else {
args->Append(CreateExtensionInfo(*extension, browser_context_).ToValue());
}
EventRouter::Get(browser_context_)
->BroadcastEvent(std::unique_ptr<Event>(
new Event(histogram_value, event_name, std::move(args))));
}
ManagementAPI::ManagementAPI(content::BrowserContext* context)
: browser_context_(context),
delegate_(ExtensionsAPIClient::Get()->CreateManagementAPIDelegate()) {
EventRouter* event_router = EventRouter::Get(browser_context_);
event_router->RegisterObserver(this, management::OnInstalled::kEventName);
event_router->RegisterObserver(this, management::OnUninstalled::kEventName);
event_router->RegisterObserver(this, management::OnEnabled::kEventName);
event_router->RegisterObserver(this, management::OnDisabled::kEventName);
}
ManagementAPI::~ManagementAPI() {
}
void ManagementAPI::Shutdown() {
EventRouter::Get(browser_context_)->UnregisterObserver(this);
}
static base::LazyInstance<BrowserContextKeyedAPIFactory<ManagementAPI>>
g_factory = LAZY_INSTANCE_INITIALIZER;
// static
BrowserContextKeyedAPIFactory<ManagementAPI>*
ManagementAPI::GetFactoryInstance() {
return g_factory.Pointer();
}
void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
management_event_router_.reset(new ManagementEventRouter(browser_context_));
EventRouter::Get(browser_context_)->UnregisterObserver(this);
}
} // namespace extensions