This source file includes following definitions.
- CreateSilent
- Create
- Create
- installer_
- InstallCrx
- InstallUserScript
- ConvertUserScriptOnFileThread
- InstallWebApp
- ConvertWebAppOnFileThread
- AllowInstall
- OnUnpackFailure
- OnUnpackSuccess
- CheckImportsAndRequirements
- OnRequirementsChecked
- OnBlacklistChecked
- ConfirmInstall
- InstallUIProceed
- InstallUIAbort
- CompleteInstall
- ReportFailureFromFileThread
- ReportFailureFromUIThread
- ReportSuccessFromFileThread
- ReportSuccessFromUIThread
- NotifyCrxInstallComplete
- CleanupTempFiles
- CheckUpdateFromSettingsPage
- ConfirmReEnable
#include "chrome/browser/extensions/crx_installer.h"
#include <map>
#include <set>
#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/lazy_instance.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "base/version.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/convert_user_script.h"
#include "chrome/browser/extensions/convert_web_app.h"
#include "chrome/browser/extensions/crx_installer_error.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/install_tracker.h"
#include "chrome/browser/extensions/install_tracker_factory.h"
#include "chrome/browser/extensions/permissions_updater.h"
#include "chrome/browser/extensions/webstore_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/manifest_url_handler.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/user_metrics.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/feature_switch.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_handlers/kiosk_mode_info.h"
#include "extensions/common/manifest_handlers/shared_module_info.h"
#include "extensions/common/permissions/permission_message_provider.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/user_script.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/user_manager.h"
#endif
using base::UserMetricsAction;
using content::BrowserThread;
using extensions::SharedModuleInfo;
namespace extensions {
namespace {
enum OffStoreInstallDecision {
OnStoreInstall,
OffStoreInstallAllowed,
OffStoreInstallDisallowed,
NumOffStoreInstallDecision
};
}
scoped_refptr<CrxInstaller> CrxInstaller::CreateSilent(
ExtensionService* frontend) {
return new CrxInstaller(frontend->AsWeakPtr(),
scoped_ptr<ExtensionInstallPrompt>(),
NULL);
}
scoped_refptr<CrxInstaller> CrxInstaller::Create(
ExtensionService* frontend,
scoped_ptr<ExtensionInstallPrompt> client) {
return new CrxInstaller(frontend->AsWeakPtr(), client.Pass(), NULL);
}
scoped_refptr<CrxInstaller> CrxInstaller::Create(
ExtensionService* service,
scoped_ptr<ExtensionInstallPrompt> client,
const WebstoreInstaller::Approval* approval) {
return new CrxInstaller(service->AsWeakPtr(), client.Pass(), approval);
}
CrxInstaller::CrxInstaller(
base::WeakPtr<ExtensionService> service_weak,
scoped_ptr<ExtensionInstallPrompt> client,
const WebstoreInstaller::Approval* approval)
: install_directory_(service_weak->install_directory()),
install_source_(Manifest::INTERNAL),
approved_(false),
expected_manifest_check_level_(
WebstoreInstaller::MANIFEST_CHECK_LEVEL_STRICT),
expected_version_strict_checking_(false),
extensions_enabled_(service_weak->extensions_enabled()),
delete_source_(false),
create_app_shortcut_(false),
service_weak_(service_weak),
client_(client.release()),
apps_require_extension_mime_type_(false),
allow_silent_install_(false),
install_cause_(extension_misc::INSTALL_CAUSE_UNSET),
creation_flags_(Extension::NO_FLAGS),
off_store_install_allow_reason_(OffStoreInstallDisallowed),
did_handle_successfully_(true),
error_on_unsupported_requirements_(false),
has_requirement_errors_(false),
blacklist_state_(extensions::NOT_BLACKLISTED),
install_wait_for_idle_(true),
update_from_settings_page_(false),
installer_(service_weak->profile()) {
installer_task_runner_ = service_weak->GetFileTaskRunner();
if (!approval)
return;
CHECK(profile()->IsSameProfile(approval->profile));
if (client_) {
client_->install_ui()->SetUseAppInstalledBubble(
approval->use_app_installed_bubble);
client_->install_ui()->set_skip_post_install_ui(
approval->skip_post_install_ui);
}
if (approval->skip_install_dialog) {
approved_ = true;
expected_manifest_check_level_ = approval->manifest_check_level;
if (expected_manifest_check_level_ !=
WebstoreInstaller::MANIFEST_CHECK_LEVEL_NONE)
expected_manifest_.reset(approval->manifest->DeepCopy());
expected_id_ = approval->extension_id;
}
if (approval->minimum_version.get()) {
expected_version_.reset(new Version(*approval->minimum_version));
expected_version_strict_checking_ = false;
}
show_dialog_callback_ = approval->show_dialog_callback;
if (approval->is_ephemeral)
creation_flags_ |= Extension::IS_EPHEMERAL;
}
CrxInstaller::~CrxInstaller() {
if (client_) {
BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, client_);
client_ = NULL;
}
}
void CrxInstaller::InstallCrx(const base::FilePath& source_file) {
ExtensionService* service = service_weak_.get();
if (!service || service->browser_terminating())
return;
InstallTrackerFactory::GetForProfile(profile())
->OnBeginCrxInstall(expected_id_);
source_file_ = source_file;
scoped_refptr<SandboxedUnpacker> unpacker(
new SandboxedUnpacker(source_file,
install_source_,
creation_flags_,
install_directory_,
installer_task_runner_.get(),
this));
if (!installer_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SandboxedUnpacker::Start, unpacker.get())))
NOTREACHED();
}
void CrxInstaller::InstallUserScript(const base::FilePath& source_file,
const GURL& download_url) {
DCHECK(!download_url.is_empty());
source_file_ = source_file;
download_url_ = download_url;
if (!installer_task_runner_->PostTask(
FROM_HERE,
base::Bind(&CrxInstaller::ConvertUserScriptOnFileThread, this)))
NOTREACHED();
}
void CrxInstaller::ConvertUserScriptOnFileThread() {
base::string16 error;
scoped_refptr<Extension> extension = ConvertUserScriptToExtension(
source_file_, download_url_, install_directory_, &error);
if (!extension.get()) {
ReportFailureFromFileThread(CrxInstallerError(error));
return;
}
OnUnpackSuccess(extension->path(), extension->path(), NULL, extension.get(),
SkBitmap());
}
void CrxInstaller::InstallWebApp(const WebApplicationInfo& web_app) {
if (!installer_task_runner_->PostTask(
FROM_HERE,
base::Bind(&CrxInstaller::ConvertWebAppOnFileThread,
this,
web_app,
install_directory_)))
NOTREACHED();
}
void CrxInstaller::ConvertWebAppOnFileThread(
const WebApplicationInfo& web_app,
const base::FilePath& install_directory) {
base::string16 error;
scoped_refptr<Extension> extension(
ConvertWebAppToExtension(web_app, base::Time::Now(), install_directory));
if (!extension.get()) {
NOTREACHED() << "Could not convert web app to extension.";
return;
}
OnUnpackSuccess(extension->path(), extension->path(), NULL, extension.get(),
SkBitmap());
}
CrxInstallerError CrxInstaller::AllowInstall(const Extension* extension) {
DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
if ((approved_ || !expected_id_.empty()) &&
expected_id_ != extension->id()) {
return CrxInstallerError(
l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALL_UNEXPECTED_ID,
base::ASCIIToUTF16(expected_id_),
base::ASCIIToUTF16(extension->id())));
}
if (expected_version_.get()) {
if (expected_version_strict_checking_) {
if (!expected_version_->Equals(*extension->version())) {
return CrxInstallerError(
l10n_util::GetStringFUTF16(
IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
base::ASCIIToUTF16(expected_version_->GetString()),
base::ASCIIToUTF16(extension->version()->GetString())));
}
} else {
if (extension->version()->CompareTo(*expected_version_) < 0) {
return CrxInstallerError(
l10n_util::GetStringFUTF16(
IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
base::ASCIIToUTF16(expected_version_->GetString() + "+"),
base::ASCIIToUTF16(extension->version()->GetString())));
}
}
}
if (approved_) {
bool valid = false;
if (expected_manifest_check_level_ ==
WebstoreInstaller::MANIFEST_CHECK_LEVEL_NONE) {
if (SharedModuleInfo::IsSharedModule(extension) &&
PermissionsData::GetActivePermissions(extension)->IsEmpty()) {
valid = true;
}
} else {
valid = expected_manifest_->Equals(original_manifest_.get());
if (!valid && expected_manifest_check_level_ ==
WebstoreInstaller::MANIFEST_CHECK_LEVEL_LOOSE) {
std::string error;
scoped_refptr<Extension> dummy_extension =
Extension::Create(base::FilePath(),
install_source_,
*expected_manifest_->value(),
creation_flags_,
&error);
if (error.empty()) {
scoped_refptr<const PermissionSet> expected_permissions =
PermissionsData::GetActivePermissions(dummy_extension.get());
valid = !(PermissionMessageProvider::Get()->IsPrivilegeIncrease(
expected_permissions,
PermissionsData::GetActivePermissions(extension),
extension->GetType()));
}
}
}
if (!valid)
return CrxInstallerError(
l10n_util::GetStringUTF16(IDS_EXTENSION_MANIFEST_INVALID));
}
if (extension->is_theme() || Manifest::IsExternalLocation(install_source_))
return CrxInstallerError();
if (!extensions_enabled_) {
return CrxInstallerError(
l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_NOT_ENABLED));
}
if (install_cause_ == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD) {
if (FeatureSwitch::easy_off_store_install()->IsEnabled()) {
const char* kHistogramName = "Extensions.OffStoreInstallDecisionEasy";
if (is_gallery_install()) {
UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall,
NumOffStoreInstallDecision);
} else {
UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed,
NumOffStoreInstallDecision);
}
} else {
const char* kHistogramName = "Extensions.OffStoreInstallDecisionHard";
if (is_gallery_install()) {
UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall,
NumOffStoreInstallDecision);
} else if (off_store_install_allow_reason_ != OffStoreInstallDisallowed) {
UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed,
NumOffStoreInstallDecision);
UMA_HISTOGRAM_ENUMERATION("Extensions.OffStoreInstallAllowReason",
off_store_install_allow_reason_,
NumOffStoreInstallAllowReasons);
} else {
UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallDisallowed,
NumOffStoreInstallDecision);
delete_source_ = false;
did_handle_successfully_ = false;
return CrxInstallerError(
CrxInstallerError::ERROR_OFF_STORE,
l10n_util::GetStringUTF16(
IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE));
}
}
}
if (installer_.extension()->is_app()) {
if (!download_url_.SchemeIsFile() &&
apps_require_extension_mime_type_ &&
original_mime_type_ != Extension::kMimeType) {
return CrxInstallerError(
l10n_util::GetStringFUTF16(
IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE,
base::ASCIIToUTF16(Extension::kMimeType)));
}
if (!is_gallery_install() && client_) {
if (ManifestURL::UpdatesFromGallery(extension)) {
return CrxInstallerError(
l10n_util::GetStringFUTF16(
IDS_EXTENSION_DISALLOW_NON_DOWNLOADED_GALLERY_INSTALLS,
l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)));
}
URLPattern pattern(UserScript::ValidUserScriptSchemes());
pattern.SetHost(download_url_.host());
pattern.SetMatchSubdomains(true);
URLPatternSet patterns = installer_.extension()->web_extent();
for (URLPatternSet::const_iterator i = patterns.begin();
i != patterns.end(); ++i) {
if (!pattern.MatchesHost(i->host())) {
return CrxInstallerError(
l10n_util::GetStringUTF16(
IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST));
}
}
}
}
return CrxInstallerError();
}
void CrxInstaller::OnUnpackFailure(const base::string16& error_message) {
DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallSource",
install_source(), Manifest::NUM_LOCATIONS);
UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallCause",
install_cause(),
extension_misc::NUM_INSTALL_CAUSES);
ReportFailureFromFileThread(CrxInstallerError(error_message));
}
void CrxInstaller::OnUnpackSuccess(
const base::FilePath& temp_dir,
const base::FilePath& extension_dir,
const base::DictionaryValue* original_manifest,
const Extension* extension,
const SkBitmap& install_icon) {
DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource",
install_source(), Manifest::NUM_LOCATIONS);
UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause",
install_cause(),
extension_misc::NUM_INSTALL_CAUSES);
installer_.set_extension(extension);
temp_dir_ = temp_dir;
if (!install_icon.empty())
install_icon_.reset(new SkBitmap(install_icon));
if (original_manifest)
original_manifest_.reset(new Manifest(
Manifest::INVALID_LOCATION,
scoped_ptr<base::DictionaryValue>(original_manifest->DeepCopy())));
unpacked_extension_root_ = extension_dir;
CrxInstallerError error = AllowInstall(extension);
if (error.type() != CrxInstallerError::ERROR_NONE) {
ReportFailureFromFileThread(error);
return;
}
if (!BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&CrxInstaller::CheckImportsAndRequirements, this)))
NOTREACHED();
}
void CrxInstaller::CheckImportsAndRequirements() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ExtensionService* service = service_weak_.get();
if (!service || service->browser_terminating())
return;
if (SharedModuleInfo::ImportsModules(extension())) {
const std::vector<SharedModuleInfo::ImportInfo>& imports =
SharedModuleInfo::GetImports(extension());
std::vector<SharedModuleInfo::ImportInfo>::const_iterator i;
for (i = imports.begin(); i != imports.end(); ++i) {
Version version_required(i->minimum_version);
const Extension* imported_module =
service->GetExtensionById(i->extension_id, true);
if (imported_module &&
!SharedModuleInfo::IsSharedModule(imported_module)) {
ReportFailureFromUIThread(
CrxInstallerError(l10n_util::GetStringFUTF16(
IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_SHARED_MODULE,
base::ASCIIToUTF16(i->extension_id))));
return;
}
}
}
installer_.CheckRequirements(base::Bind(&CrxInstaller::OnRequirementsChecked,
this));
}
void CrxInstaller::OnRequirementsChecked(
std::vector<std::string> requirement_errors) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!service_weak_)
return;
if (!requirement_errors.empty()) {
if (error_on_unsupported_requirements_) {
ReportFailureFromUIThread(CrxInstallerError(
base::UTF8ToUTF16(JoinString(requirement_errors, ' '))));
return;
}
has_requirement_errors_ = true;
}
ExtensionSystem::Get(profile())->blacklist()->IsBlacklisted(
extension()->id(),
base::Bind(&CrxInstaller::OnBlacklistChecked, this));
}
void CrxInstaller::OnBlacklistChecked(
extensions::BlacklistState blacklist_state) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!service_weak_)
return;
blacklist_state_ = blacklist_state;
if ((blacklist_state_ == extensions::BLACKLISTED_MALWARE ||
blacklist_state_ == extensions::BLACKLISTED_UNKNOWN) &&
!allow_silent_install_) {
ReportFailureFromUIThread(extensions::CrxInstallerError(
l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLACKLISTED,
base::UTF8ToUTF16(extension()->name()))));
UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX",
extension()->location(),
Manifest::NUM_LOCATIONS);
return;
}
ConfirmInstall();
}
void CrxInstaller::ConfirmInstall() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ExtensionService* service = service_weak_.get();
if (!service || service->browser_terminating())
return;
if (KioskModeInfo::IsKioskOnly(installer_.extension())) {
bool in_kiosk_mode = false;
#if defined(OS_CHROMEOS)
chromeos::UserManager* user_manager = chromeos::UserManager::Get();
in_kiosk_mode = user_manager && user_manager->IsLoggedInAsKioskApp();
#endif
if (!in_kiosk_mode) {
ReportFailureFromUIThread(CrxInstallerError(
l10n_util::GetStringUTF16(
IDS_EXTENSION_INSTALL_KIOSK_MODE_ONLY)));
}
}
base::string16 error = installer_.CheckManagementPolicy();
if (!error.empty()) {
if (extension()->from_webstore() && client_)
client_->install_ui()->set_skip_post_install_ui(true);
ReportFailureFromUIThread(CrxInstallerError(error));
return;
}
CheckUpdateFromSettingsPage();
GURL overlapping_url;
const Extension* overlapping_extension =
service->extensions()->GetHostedAppByOverlappingWebExtent(
extension()->web_extent());
if (overlapping_extension &&
overlapping_extension->id() != extension()->id()) {
ReportFailureFromUIThread(
CrxInstallerError(
l10n_util::GetStringFUTF16(
IDS_EXTENSION_OVERLAPPING_WEB_EXTENT,
base::UTF8ToUTF16(overlapping_extension->name()))));
return;
}
current_version_ = ExtensionPrefs::Get(service->profile())
->GetVersionString(extension()->id());
if (client_ &&
(!allow_silent_install_ || !approved_) &&
!update_from_settings_page_) {
AddRef();
client_->ConfirmInstall(this, extension(), show_dialog_callback_);
} else {
if (!installer_task_runner_->PostTask(
FROM_HERE,
base::Bind(&CrxInstaller::CompleteInstall, this)))
NOTREACHED();
}
return;
}
void CrxInstaller::InstallUIProceed() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ExtensionService* service = service_weak_.get();
if (!service || service->browser_terminating())
return;
if (update_from_settings_page_) {
service->GrantPermissionsAndEnableExtension(extension());
} else {
if (!installer_task_runner_->PostTask(
FROM_HERE,
base::Bind(&CrxInstaller::CompleteInstall, this)))
NOTREACHED();
}
Release();
}
void CrxInstaller::InstallUIAbort(bool user_initiated) {
if (!update_from_settings_page_) {
std::string histogram_name = user_initiated ?
"Extensions.Permissions_InstallCancel" :
"Extensions.Permissions_InstallAbort";
ExtensionService::RecordPermissionMessagesHistogram(
extension(), histogram_name.c_str());
NotifyCrxInstallComplete(false);
}
Release();
}
void CrxInstaller::CompleteInstall() {
DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
if (!current_version_.empty()) {
Version current_version(current_version_);
if (current_version.CompareTo(*(extension()->version())) > 0) {
ReportFailureFromFileThread(
CrxInstallerError(
l10n_util::GetStringUTF16(extension()->is_app() ?
IDS_APP_CANT_DOWNGRADE_VERSION :
IDS_EXTENSION_CANT_DOWNGRADE_VERSION)));
return;
}
}
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Extensions.CrxInstallDirPathLength",
install_directory_.value().length(), 0, 500, 100);
base::FilePath version_dir = extension_file_util::InstallExtension(
unpacked_extension_root_,
extension()->id(),
extension()->VersionString(),
install_directory_);
if (version_dir.empty()) {
ReportFailureFromFileThread(
CrxInstallerError(
l10n_util::GetStringUTF16(
IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED)));
return;
}
std::string extension_id = extension()->id();
std::string error;
installer_.set_extension(extension_file_util::LoadExtension(
version_dir,
install_source_,
extension()->creation_flags() | Extension::REQUIRE_KEY,
&error).get());
if (extension()) {
ReportSuccessFromFileThread();
} else {
LOG(ERROR) << error << " " << extension_id << " " << download_url_;
ReportFailureFromFileThread(CrxInstallerError(base::UTF8ToUTF16(error)));
}
}
void CrxInstaller::ReportFailureFromFileThread(const CrxInstallerError& error) {
DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
if (!BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&CrxInstaller::ReportFailureFromUIThread, this, error))) {
NOTREACHED();
}
}
void CrxInstaller::ReportFailureFromUIThread(const CrxInstallerError& error) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::NotificationService* service =
content::NotificationService::current();
service->Notify(chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
content::Source<CrxInstaller>(this),
content::Details<const base::string16>(&error.message()));
ExtensionErrorReporter::GetInstance()->ReportError(
error.message(),
false,
NULL);
if (client_)
client_->OnInstallFailure(error);
NotifyCrxInstallComplete(false);
CleanupTempFiles();
}
void CrxInstaller::ReportSuccessFromFileThread() {
DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
if (install_cause() == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD)
UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionInstalled", 1, 2);
if (!BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&CrxInstaller::ReportSuccessFromUIThread, this)))
NOTREACHED();
CleanupTempFiles();
}
void CrxInstaller::ReportSuccessFromUIThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!service_weak_.get() || service_weak_->browser_terminating())
return;
if (!update_from_settings_page_) {
if (client_)
client_->OnInstallSuccess(extension(), install_icon_.get());
if (client_ || allow_silent_install_) {
PermissionsUpdater perms_updater(profile());
perms_updater.GrantActivePermissions(extension());
}
}
service_weak_->OnExtensionInstalled(extension(),
page_ordinal_,
has_requirement_errors_,
blacklist_state_,
install_wait_for_idle_);
NotifyCrxInstallComplete(true);
}
void CrxInstaller::NotifyCrxInstallComplete(bool success) {
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_CRX_INSTALLER_DONE,
content::Source<CrxInstaller>(this),
content::Details<const Extension>(
success ? extension() : NULL));
if (success)
ConfirmReEnable();
}
void CrxInstaller::CleanupTempFiles() {
if (!installer_task_runner_->RunsTasksOnCurrentThread()) {
if (!installer_task_runner_->PostTask(
FROM_HERE,
base::Bind(&CrxInstaller::CleanupTempFiles, this))) {
NOTREACHED();
}
return;
}
if (!temp_dir_.value().empty()) {
extension_file_util::DeleteFile(temp_dir_, true);
temp_dir_ = base::FilePath();
}
if (delete_source_ && !source_file_.value().empty()) {
extension_file_util::DeleteFile(source_file_, false);
source_file_ = base::FilePath();
}
}
void CrxInstaller::CheckUpdateFromSettingsPage() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ExtensionService* service = service_weak_.get();
if (!service || service->browser_terminating())
return;
if (off_store_install_allow_reason_ != OffStoreInstallAllowedFromSettingsPage)
return;
const Extension* installed_extension =
service->GetInstalledExtension(extension()->id());
if (installed_extension) {
update_from_settings_page_ = true;
expected_id_ = installed_extension->id();
install_source_ = installed_extension->location();
install_cause_ = extension_misc::INSTALL_CAUSE_UPDATE;
}
}
void CrxInstaller::ConfirmReEnable() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ExtensionService* service = service_weak_.get();
if (!service || service->browser_terminating())
return;
if (!update_from_settings_page_)
return;
ExtensionPrefs* prefs = ExtensionPrefs::Get(service->profile());
if (!prefs->DidExtensionEscalatePermissions(extension()->id()))
return;
if (client_) {
AddRef();
client_->ConfirmReEnable(this, extension());
}
}
}