1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
|
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/chrome_extension_registrar_delegate.h"
#include <set>
#include <string>
#include "base/barrier_closure.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/notimplemented.h"
#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/corrupted_extension_reinstaller.h"
#include "chrome/browser/extensions/data_deleter.h"
#include "chrome/browser/extensions/extension_allowlist.h"
#include "chrome/browser/extensions/extension_assets_manager.h"
#include "chrome/browser/extensions/extension_disabled_ui.h"
#include "chrome/browser/extensions/extension_management.h"
#include "chrome/browser/extensions/extension_special_storage_policy.h"
#include "chrome/browser/extensions/external_install_manager.h"
#include "chrome/browser/extensions/install_verifier.h"
#include "chrome/browser/extensions/installed_loader.h"
#include "chrome/browser/extensions/permissions/permissions_updater.h"
#include "chrome/browser/extensions/profile_util.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/extensions/updater/extension_updater.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/favicon_source.h"
#include "chrome/common/webui_url_constants.h"
#include "components/favicon_base/favicon_url_parser.h"
#include "extensions/browser/delayed_install_manager.h"
#include "extensions/browser/disable_reason.h"
#include "extensions/browser/extension_file_task_runner.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/extension_util.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/install_flag.h"
#include "extensions/browser/pending_extension_manager.h"
#include "extensions/common/crash_keys.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/incognito_info.h"
#include "extensions/common/manifest_handlers/shared_module_info.h"
#include "extensions/common/mojom/manifest.mojom-shared.h"
#include "extensions/common/permissions/permission_message_provider.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/ash/fileapi/file_system_backend.h"
#include "content/public/browser/storage_partition.h"
#include "storage/browser/file_system/file_system_context.h"
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "chrome/browser/extensions/extension_sync_service.h"
#include "chrome/browser/ui/webui/theme_source.h"
#endif
using extensions::mojom::ManifestLocation;
namespace extensions {
namespace {
// When uninstalling an extension, determine if the extension's directory
// should be deleted when uninstalling. Returns `true` iff extension is
// unpacked and installed outside the unpacked extensions installations dir.
// Example: packed extensions are always deleted. But unpacked extensions are
// in a folder outside the profile dir are not deleted.
bool SkipDeleteExtensionDir(const Extension& extension,
const base::FilePath& profile_path) {
bool is_unpacked_location =
Manifest::IsUnpackedLocation(extension.location());
bool extension_dir_not_direct_subdir_of_unpacked_extensions_install_dir =
extension.path().DirName() !=
profile_path.AppendASCII(extensions::kUnpackedInstallDirectoryName);
return is_unpacked_location &&
extension_dir_not_direct_subdir_of_unpacked_extensions_install_dir;
}
} // namespace
ChromeExtensionRegistrarDelegate::ChromeExtensionRegistrarDelegate(
Profile* profile)
: profile_(profile),
system_(ExtensionSystem::Get(profile_)),
extension_prefs_(ExtensionPrefs::Get(profile_)),
registry_(ExtensionRegistry::Get(profile_)),
component_loader_(ComponentLoader::Get(profile_)) {}
ChromeExtensionRegistrarDelegate::~ChromeExtensionRegistrarDelegate() = default;
void ChromeExtensionRegistrarDelegate::Init(ExtensionRegistrar* registrar) {
extension_registrar_ = registrar;
}
void ChromeExtensionRegistrarDelegate::Shutdown() {
// Avoid dangling pointers.
profile_ = nullptr;
extension_prefs_ = nullptr;
system_ = nullptr;
registry_ = nullptr;
extension_registrar_ = nullptr;
component_loader_ = nullptr;
}
void ChromeExtensionRegistrarDelegate::PreAddExtension(
const Extension* extension,
const Extension* old_extension) {
// An extension may have updated to no longer support incognito. When this
// is the case, we don't show the toggle in the chrome://extensions page.
// In order to ensure an extension doesn't keep an unrevokable permission,
// reset the stored pref.
if (old_extension && !IncognitoInfo::IsIncognitoAllowed(extension)) {
extension_prefs_->SetIsIncognitoEnabled(extension->id(), false);
}
// Check if the extension's privileges have changed and mark the
// extension disabled if necessary.
CheckPermissionsIncrease(extension, !!old_extension);
}
void ChromeExtensionRegistrarDelegate::OnAddNewOrUpdatedExtension(
const Extension* extension) {
if (InstallVerifier::NeedsVerification(*extension, profile_)) {
InstallVerifier::Get(profile_)->VerifyExtension(extension->id());
}
}
void ChromeExtensionRegistrarDelegate::PostActivateExtension(
scoped_refptr<const Extension> extension) {
// Update policy permissions in case they were changed while extension was not
// active.
PermissionsUpdater(profile_).ApplyPolicyHostRestrictions(*extension);
// TODO(kalman): Convert ExtensionSpecialStoragePolicy to a
// BrowserContextKeyedService and use ExtensionRegistryObserver.
auto* special_storage_policy = profile_->GetExtensionSpecialStoragePolicy();
CHECK(special_storage_policy);
special_storage_policy->GrantRightsForExtension(extension.get(), profile_);
// TODO(kalman): This is broken. The crash reporter is process-wide so doesn't
// work properly multi-profile. Besides which, it should be using
// ExtensionRegistryObserver. See http://crbug.com/355029.
UpdateActiveExtensionsInCrashReporter();
const PermissionsData* permissions_data = extension->permissions_data();
// If the extension has permission to load chrome://favicon/ resources we need
// to make sure that the FaviconSource is registered with the
// ChromeURLDataManager.
if (permissions_data->HasHostPermission(GURL(chrome::kChromeUIFaviconURL))) {
content::URLDataSource::Add(
profile_, std::make_unique<FaviconSource>(
profile_, chrome::FaviconUrlFormat::kFaviconLegacy));
}
// Same for chrome://theme/ resources.
if (permissions_data->HasHostPermission(GURL(chrome::kChromeUIThemeURL))) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
content::URLDataSource::Add(profile_,
std::make_unique<ThemeSource>(profile_));
#else
// TODO(crbug.com/408507365): Figure out the theme story on desktop Android
// and port ThemeSource if necessary.
NOTIMPLEMENTED() << "Themes not yet supported on desktop Android.";
#endif
}
}
void ChromeExtensionRegistrarDelegate::PostDeactivateExtension(
scoped_refptr<const Extension> extension) {
// TODO(kalman): Convert ExtensionSpecialStoragePolicy to a
// BrowserContextKeyedService and use ExtensionRegistryObserver.
auto* special_storage_policy = profile_->GetExtensionSpecialStoragePolicy();
CHECK(special_storage_policy);
special_storage_policy->RevokeRightsForExtension(extension.get(), profile_);
#if BUILDFLAG(IS_CHROMEOS)
// Revoke external file access for the extension from its file system context.
// It is safe to access the extension's storage partition at this point. The
// storage partition may get destroyed only after the extension gets unloaded.
storage::FileSystemContext* filesystem_context =
util::GetStoragePartitionForExtensionId(extension->id(), profile_)
->GetFileSystemContext();
if (filesystem_context && ash::FileSystemBackend::Get(*filesystem_context)) {
ash::FileSystemBackend::Get(*filesystem_context)
->RevokeAccessForOrigin(extension->origin());
}
#endif
// TODO(kalman): This is broken. The crash reporter is process-wide so doesn't
// work properly multi-profile. Besides which, it should be using
// ExtensionRegistryObserver::OnExtensionLoaded. See http://crbug.com/355029.
UpdateActiveExtensionsInCrashReporter();
}
void ChromeExtensionRegistrarDelegate::PreUninstallExtension(
scoped_refptr<const Extension> extension) {
InstallVerifier::Get(profile_)->Remove(extension->id());
}
void ChromeExtensionRegistrarDelegate::PostUninstallExtension(
scoped_refptr<const Extension> extension,
base::OnceClosure done_callback) {
// Prepare barrier closure for UninstallExtensionOnFileThread() task (if
// applicable) and DataDeleter::StartDeleting().
bool is_unpacked_location =
Manifest::IsUnpackedLocation(extension->location());
base::RepeatingClosure subtask_done_callback = base::DoNothing();
if (!done_callback.is_null()) {
int num_tasks = is_unpacked_location ? 1 : 2;
subtask_done_callback =
base::BarrierClosure(num_tasks, std::move(done_callback));
}
// Delete extensions in profile directory (from webstore, or from .crx), but
// do not delete unpacked in a folder outside the profile directory.
if (!SkipDeleteExtensionDir(*extension, profile_->GetPath())) {
// Extensions installed from webstore or .crx are versioned in subdirs so we
// delete the parent dir. Unpacked (installed from .zip rather than folder)
// are not versioned so we just delete the single installation directory.
base::FilePath extension_dir_to_delete =
is_unpacked_location ? extension->path() : extension->path().DirName();
base::FilePath extensions_install_dir =
is_unpacked_location
? extension_registrar_->unpacked_install_directory()
: extension_registrar_->install_directory();
// Tell the backend to start deleting the installed extension on the file
// thread.
if (!GetExtensionFileTaskRunner()->PostTaskAndReply(
FROM_HERE,
base::BindOnce(&ChromeExtensionRegistrarDelegate::
UninstallExtensionOnFileThread,
extension->id(), profile_->GetProfileUserName(),
std::move(extensions_install_dir),
std::move(extension_dir_to_delete),
profile_->GetPath()),
subtask_done_callback)) {
NOTREACHED();
}
}
DataDeleter::StartDeleting(profile_, extension.get(), subtask_done_callback);
}
void ChromeExtensionRegistrarDelegate::DoLoadExtensionForReload(
const ExtensionId& extension_id,
const base::FilePath& path,
bool load_error_behavior_noisy) {
// If we're reloading a component extension, use the component extension
// loader's reloader.
if (component_loader_->Exists(extension_id)) {
component_loader_->Reload(extension_id);
return;
}
// Check the installed extensions to see if what we're reloading was already
// installed.
std::optional<ExtensionInfo> installed_extension(
extension_prefs_->GetInstalledExtensionInfo(extension_id));
if (installed_extension && installed_extension->extension_manifest.get()) {
InstalledLoader(profile_).Load(*installed_extension, false);
} else {
// Otherwise, the extension is unpacked (location LOAD). We must load it
// from the path.
CHECK(!path.empty()) << "ExtensionRegistrar should never ask to load an "
"unknown extension with no path";
scoped_refptr<UnpackedInstaller> unpacked_installer =
UnpackedInstaller::Create(profile_);
unpacked_installer->set_be_noisy_on_failure(load_error_behavior_noisy);
unpacked_installer->set_completion_callback(base::BindOnce(
&ChromeExtensionRegistrarDelegate::OnUnpackedReloadFailure,
weak_factory_.GetWeakPtr()));
unpacked_installer->Load(path);
}
}
void ChromeExtensionRegistrarDelegate::LoadExtensionForReload(
const ExtensionId& extension_id,
const base::FilePath& path) {
DoLoadExtensionForReload(extension_id, path, true);
}
void ChromeExtensionRegistrarDelegate::LoadExtensionForReloadWithQuietFailure(
const ExtensionId& extension_id,
const base::FilePath& path) {
DoLoadExtensionForReload(extension_id, path, false);
}
void ChromeExtensionRegistrarDelegate::ShowExtensionDisabledError(
const Extension* extension,
bool is_remote_install) {
AddExtensionDisabledError(profile_, extension, is_remote_install);
}
bool ChromeExtensionRegistrarDelegate::CanEnableExtension(
const Extension* extension) {
CHECK(system_->management_policy());
return !system_->management_policy()->MustRemainDisabled(extension, nullptr);
}
bool ChromeExtensionRegistrarDelegate::CanDisableExtension(
const Extension* extension) {
// Some extensions cannot be disabled by users:
// - |extension| can be null if sync disables an extension that is not
// installed yet; allow disablement in this case.
if (!extension) {
return true;
}
// - Shared modules are just resources used by other extensions, and are not
// user-controlled.
if (SharedModuleInfo::IsSharedModule(extension)) {
return false;
}
// - EXTERNAL_COMPONENT extensions are not generally modifiable by users, but
// can be uninstalled by the browser if the user sets extension-specific
// preferences.
if (extension->location() == ManifestLocation::kExternalComponent) {
return true;
}
CHECK(system_->management_policy());
return system_->management_policy()->UserMayModifySettings(extension,
nullptr);
}
void ChromeExtensionRegistrarDelegate::GrantActivePermissions(
const Extension* extension) {
PermissionsUpdater(profile_).GrantActivePermissions(extension);
}
void ChromeExtensionRegistrarDelegate::UpdateExternalExtensionAlert() {
ExternalInstallManager::Get(profile_)->UpdateExternalExtensionAlert();
}
void ChromeExtensionRegistrarDelegate::OnExtensionInstalled(
const Extension* extension,
const syncer::StringOrdinal& page_ordinal,
int install_flags,
base::Value::Dict ruleset_install_prefs) {
const std::string& id = extension->id();
base::flat_set<int> disable_reasons =
extension_registrar_->GetDisableReasonsOnInstalled(extension);
std::string install_parameter;
auto* pending_extension_manager = PendingExtensionManager::Get(profile_);
const PendingExtensionInfo* pending_extension_info =
pending_extension_manager->GetById(id);
auto* corrupted_extension_reinstaller =
CorruptedExtensionReinstaller::Get(profile_);
bool is_reinstall_for_corruption =
corrupted_extension_reinstaller->IsReinstallForCorruptionExpected(id);
if (is_reinstall_for_corruption) {
corrupted_extension_reinstaller->MarkResolved(id);
}
if (pending_extension_info) {
if (!pending_extension_info->ShouldAllowInstall(extension, profile_)) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
// Note: Theme is unsupported on desktop Android.
// Hack for crbug.com/558299, see comment on DeleteThemeDoNotUse.
if (extension->is_theme() && pending_extension_info->is_from_sync()) {
ExtensionSyncService::Get(profile_)->DeleteThemeDoNotUse(*extension);
}
#endif
pending_extension_manager->Remove(id);
ExtensionManagement* management =
ExtensionManagementFactory::GetForBrowserContext(profile_);
LOG(WARNING) << "ShouldAllowInstall() returned false for " << id
<< " of type " << extension->GetType() << " and update URL "
<< management->GetEffectiveUpdateURL(*extension).spec()
<< "; not installing";
// Delete the extension directory since we're not going to
// load it.
if (!GetExtensionFileTaskRunner()->PostTask(
FROM_HERE,
base::GetDeletePathRecursivelyCallback(extension->path()))) {
NOTREACHED();
}
return;
}
install_parameter = pending_extension_info->install_parameter();
pending_extension_manager->Remove(id);
} else if (!is_reinstall_for_corruption) {
// We explicitly want to re-enable an uninstalled external
// extension; if we're here, that means the user is manually
// installing the extension.
if (extension_prefs_->IsExternalExtensionUninstalled(id)) {
disable_reasons.clear();
}
}
// If the old version of the extension was disabled due to corruption, this
// new install may correct the problem.
disable_reasons.erase(disable_reason::DISABLE_CORRUPTED);
// Unsupported requirements overrides the management policy.
if (install_flags & kInstallFlagHasRequirementErrors) {
disable_reasons.insert(disable_reason::DISABLE_UNSUPPORTED_REQUIREMENT);
} else {
// Requirement is supported now, remove the corresponding disable reason
// instead.
disable_reasons.erase(disable_reason::DISABLE_UNSUPPORTED_REQUIREMENT);
}
// Check if the extension was disabled because of the minimum version
// requirements from enterprise policy, and satisfies it now.
if (ExtensionManagementFactory::GetForBrowserContext(profile_)
->CheckMinimumVersion(extension, nullptr)) {
// And remove the corresponding disable reason.
disable_reasons.erase(disable_reason::DISABLE_UPDATE_REQUIRED_BY_POLICY);
}
if (install_flags & kInstallFlagIsBlocklistedForMalware) {
// Installation of a blocklisted extension can happen from sync, policy,
// etc, where to maintain consistency we need to install it, just never
// load it (see AddExtension). Usually it should be the job of callers to
// intercept blocklisted extensions earlier (e.g. CrxInstaller, before even
// showing the install dialogue).
extension_prefs_->AcknowledgeBlocklistedExtension(id);
UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.SilentInstall",
extension->location());
}
RecordInstallHistograms(extension);
ExtensionAllowlist::Get(profile_)->OnExtensionInstalled(id, install_flags);
DelayedInstallManager* delayed_install_manager =
DelayedInstallManager::Get(profile_);
ExtensionPrefs::DelayReason delay_reason;
InstallGate::Action action =
delayed_install_manager->ShouldDelayExtensionInstall(
extension, !!(install_flags & kInstallFlagInstallImmediately),
&delay_reason);
switch (action) {
case InstallGate::INSTALL:
extension_registrar_->AddNewOrUpdatedExtension(
extension, disable_reasons, install_flags, page_ordinal,
install_parameter, std::move(ruleset_install_prefs));
return;
case InstallGate::DELAY:
extension_prefs_->SetDelayedInstallInfo(
extension, disable_reasons, install_flags, delay_reason, page_ordinal,
install_parameter, std::move(ruleset_install_prefs));
// Transfer ownership of |extension|.
delayed_install_manager->Insert(extension);
if (delay_reason == ExtensionPrefs::DelayReason::kWaitForIdle) {
ExtensionUpdater::Get(profile_)->NotifyAppUpdateAvailable(*extension);
}
return;
case InstallGate::ABORT:
// Do nothing to abort the install. One such case is the shared module
// service gets IMPORT_STATUS_UNRECOVERABLE status for the pending
// install.
return;
}
NOTREACHED() << "Unknown action for delayed install: " << action;
}
void ChromeExtensionRegistrarDelegate::CheckPermissionsIncrease(
const Extension* extension,
bool is_extension_loaded) {
PermissionsUpdater(profile_).InitializePermissions(extension);
// We keep track of all permissions the user has granted each extension.
// This allows extensions to gracefully support backwards compatibility
// by including unknown permissions in their manifests. When the user
// installs the extension, only the recognized permissions are recorded.
// When the unknown permissions become recognized (e.g., through browser
// upgrade), we can prompt the user to accept these new permissions.
// Extensions can also silently upgrade to less permissions, and then
// silently upgrade to a version that adds these permissions back.
//
// For example, pretend that Chrome 10 includes a permission "omnibox"
// for an API that adds suggestions to the omnibox. An extension can
// maintain backwards compatibility while still having "omnibox" in the
// manifest. If a user installs the extension on Chrome 9, the browser
// will record the permissions it recognized, not including "omnibox."
// When upgrading to Chrome 10, "omnibox" will be recognized and Chrome
// will disable the extension and prompt the user to approve the increase
// in privileges. The extension could then release a new version that
// removes the "omnibox" permission. When the user upgrades, Chrome will
// still remember that "omnibox" had been granted, so that if the
// extension once again includes "omnibox" in an upgrade, the extension
// can upgrade without requiring this user's approval.
// Silently grant all active permissions to pre-installed apps and apps
// installed in kiosk mode.
bool auto_grant_permission =
extension->was_installed_by_default() ||
ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode();
if (auto_grant_permission) {
PermissionsUpdater(profile_).GrantActivePermissions(extension);
}
bool is_privilege_increase = false;
// We only need to compare the granted permissions to the current permissions
// if the extension has not been auto-granted its permissions above and is
// installed internally.
if (extension->location() == ManifestLocation::kInternal &&
!auto_grant_permission) {
// Add all the recognized permissions if the granted permissions list
// hasn't been initialized yet.
std::unique_ptr<const PermissionSet> granted_permissions =
extension_prefs_->GetGrantedPermissions(extension->id());
CHECK(granted_permissions.get());
// We check the union of both granted permissions and runtime granted
// permissions as it is possible for permissions which were withheld during
// installation to have never entered the granted set, but to have later
// been granted as runtime permissions.
std::unique_ptr<const PermissionSet> runtime_granted_permissions =
extension_prefs_->GetRuntimeGrantedPermissions(extension->id());
std::unique_ptr<const PermissionSet> total_permissions =
PermissionSet::CreateUnion(*granted_permissions,
*runtime_granted_permissions);
// Here, we check if an extension's privileges have increased in a manner
// that requires the user's approval. This could occur because the browser
// upgraded and recognized additional privileges, or an extension upgrades
// to a version that requires additional privileges.
is_privilege_increase =
PermissionMessageProvider::Get()->IsPrivilegeIncrease(
*total_permissions,
extension->permissions_data()->active_permissions(),
extension->GetType());
// If there was no privilege increase, the extension might still have new
// permissions (which either don't generate a warning message, or whose
// warning messages are suppressed by existing permissions). Grant the new
// permissions.
if (!is_privilege_increase) {
PermissionsUpdater(profile_).GrantActivePermissions(extension);
}
}
const DisableReasonSet disable_reasons =
extension_prefs_->GetDisableReasons(extension->id());
// If the extension is disabled due to a permissions increase, but does in
// fact have all permissions, remove that disable reason.
if (disable_reasons.contains(disable_reason::DISABLE_PERMISSIONS_INCREASE) &&
!is_privilege_increase) {
extension_prefs_->RemoveDisableReason(
extension->id(), disable_reason::DISABLE_PERMISSIONS_INCREASE);
}
// Extension has changed permissions significantly. Disable it. A
// notification should be sent by the caller. If the extension is already
// disabled because it was installed remotely, don't add another disable
// reason.
if (is_privilege_increase &&
!disable_reasons.contains(disable_reason::DISABLE_REMOTE_INSTALL)) {
extension_prefs_->AddDisableReason(
extension->id(), disable_reason::DISABLE_PERMISSIONS_INCREASE);
}
}
void ChromeExtensionRegistrarDelegate::UpdateActiveExtensionsInCrashReporter() {
std::set<std::string> extension_ids;
for (const auto& extension : registry_->enabled_extensions()) {
if (!extension->is_theme() &&
extension->location() != ManifestLocation::kComponent) {
extension_ids.insert(extension->id());
}
}
// TODO(kalman): This is broken. ExtensionService is per-profile.
// crash_keys::SetActiveExtensions is per-process. See
// http://crbug.com/355029.
crash_keys::SetActiveExtensions(extension_ids);
}
// static
void ChromeExtensionRegistrarDelegate::UninstallExtensionOnFileThread(
const std::string& id,
const std::string& profile_user_name,
const base::FilePath& extensions_install_dir,
const base::FilePath& extension_dir_to_delete,
const base::FilePath& profile_dir) {
ExtensionAssetsManager* assets_manager =
ExtensionAssetsManager::GetInstance();
assets_manager->UninstallExtension(id, profile_user_name,
extensions_install_dir,
extension_dir_to_delete, profile_dir);
}
void ChromeExtensionRegistrarDelegate::OnUnpackedReloadFailure(
const Extension* extension,
const base::FilePath& file_path,
const std::string& error) {
if (!error.empty()) {
extension_registrar_->OnUnpackedExtensionReloadFailed(file_path);
}
}
void ChromeExtensionRegistrarDelegate::RecordInstallHistograms(
const Extension* extension) {
bool is_user_profile =
extensions::profile_util::ProfileCanUseNonComponentExtensions(profile_);
if (!registry_->GetInstalledExtension(extension->id())) {
UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType", extension->GetType(),
100);
if (is_user_profile) {
UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType.User",
extension->GetType(), 100);
} else {
UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType.NonUser",
extension->GetType(), 100);
}
UMA_HISTOGRAM_ENUMERATION("Extensions.InstallSource",
extension->location());
if (is_user_profile) {
UMA_HISTOGRAM_ENUMERATION("Extensions.InstallSource.User2",
extension->location(), 100);
} else {
UMA_HISTOGRAM_ENUMERATION("Extensions.InstallSource.NonUser2",
extension->location(), 100);
}
// TODO(crbug.com/40878021): Address Install metrics below in a follow-up
// CL.
InstalledLoader::RecordPermissionMessagesHistogram(extension, "Install",
is_user_profile);
}
}
} // namespace extensions
|