| Index: chrome/browser/extensions/extension_storage_monitor.cc
|
| diff --git a/chrome/browser/extensions/extension_storage_monitor.cc b/chrome/browser/extensions/extension_storage_monitor.cc
|
| index 9fda00f552466d294f78fefdcfff462d41c41466..1ad2d4255c626ed0106033986d73ebb4189ebbe2 100644
|
| --- a/chrome/browser/extensions/extension_storage_monitor.cc
|
| +++ b/chrome/browser/extensions/extension_storage_monitor.cc
|
| @@ -54,6 +54,22 @@ const int64 kExtensionInitialThreshold = 1000 * kMBytes;
|
| const char kNotificationIdFormat[] = "ExtensionStorageMonitor-$1-$2";
|
| const char kSystemNotifierId[] = "ExtensionStorageMonitor";
|
|
|
| +// A preference that stores the next threshold for displaying a notification
|
| +// when an extension or app consumes excessive disk space. This will not be
|
| +// set until the extension/app reaches the initial threshold.
|
| +const char kPrefNextStorageThreshold[] = "next_storage_threshold";
|
| +
|
| +// If this preference is set to true, notifications will be suppressed when an
|
| +// extension or app consumes excessive disk space.
|
| +const char kPrefDisableStorageNotifications[] = "disable_storage_notifications";
|
| +
|
| +bool ShouldMonitorStorageFor(const Extension* extension) {
|
| + // Only monitor storage for extensions that are granted unlimited storage.
|
| + // Do not monitor storage for component extensions.
|
| + return extension->HasAPIPermission(APIPermission::kUnlimitedStorage) &&
|
| + extension->location() != Manifest::COMPONENT;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // StorageEventObserver monitors the storage usage of extensions and lives on
|
| @@ -94,6 +110,21 @@ class StorageEventObserver
|
| quota_manager->AddStorageObserver(this, params);
|
| }
|
|
|
| + // Updates the threshold for an extension already being monitored.
|
| + void UpdateThresholdForExtension(const std::string& extension_id,
|
| + int64 next_threshold) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| +
|
| + for (OriginStorageStateMap::iterator it = origin_state_map_.begin();
|
| + it != origin_state_map_.end();
|
| + ++it) {
|
| + if (it->second.extension_id == extension_id) {
|
| + it->second.next_threshold = next_threshold;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| // Deregister as an observer for the extension's storage events.
|
| void StopObservingForExtension(const std::string& extension_id) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| @@ -181,16 +212,15 @@ ExtensionStorageMonitor::ExtensionStorageMonitor(
|
| initial_ephemeral_threshold_(kEphemeralAppInitialThreshold),
|
| observer_rate_(kStorageEventRateSec),
|
| context_(context),
|
| + extension_prefs_(ExtensionPrefs::Get(context)),
|
| + extension_registry_observer_(this),
|
| weak_ptr_factory_(this) {
|
| - registrar_.Add(this,
|
| - chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED,
|
| - content::Source<content::BrowserContext>(context_));
|
| + DCHECK(extension_prefs_);
|
| +
|
| registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
|
| content::Source<content::BrowserContext>(context_));
|
|
|
| - ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
|
| - DCHECK(registry);
|
| - registry->AddObserver(this);
|
| + extension_registry_observer_.Add(ExtensionRegistry::Get(context_));
|
| }
|
|
|
| ExtensionStorageMonitor::~ExtensionStorageMonitor() {}
|
| @@ -200,12 +230,6 @@ void ExtensionStorageMonitor::Observe(
|
| const content::NotificationSource& source,
|
| const content::NotificationDetails& details) {
|
| switch (type) {
|
| - case chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED: {
|
| - const Extension* extension =
|
| - content::Details<const Extension>(details).ptr();
|
| - RemoveNotificationForExtension(extension->id());
|
| - break;
|
| - }
|
| case chrome::NOTIFICATION_PROFILE_DESTROYED: {
|
| StopMonitoringAll();
|
| break;
|
| @@ -218,7 +242,6 @@ void ExtensionStorageMonitor::Observe(
|
| void ExtensionStorageMonitor::OnExtensionLoaded(
|
| content::BrowserContext* browser_context,
|
| const Extension* extension) {
|
| - DCHECK(extension);
|
| StartMonitoringStorage(extension);
|
| }
|
|
|
| @@ -226,10 +249,53 @@ void ExtensionStorageMonitor::OnExtensionUnloaded(
|
| content::BrowserContext* browser_context,
|
| const Extension* extension,
|
| UnloadedExtensionInfo::Reason reason) {
|
| - DCHECK(extension);
|
| StopMonitoringStorage(extension->id());
|
| }
|
|
|
| +void ExtensionStorageMonitor::OnExtensionWillBeInstalled(
|
| + content::BrowserContext* browser_context,
|
| + const Extension* extension,
|
| + bool is_update,
|
| + bool from_ephemeral,
|
| + const std::string& old_name) {
|
| + // If an ephemeral app was promoted to a regular installed app, we may need to
|
| + // increase its next threshold.
|
| + if (!from_ephemeral || !ShouldMonitorStorageFor(extension))
|
| + return;
|
| +
|
| + if (!enable_for_all_extensions_) {
|
| + // If monitoring is not enabled for installed extensions, just stop
|
| + // monitoring.
|
| + SetNextStorageThreshold(extension->id(), 0);
|
| + StopMonitoringStorage(extension->id());
|
| + return;
|
| + }
|
| +
|
| + int64 next_threshold = GetNextStorageThresholdFromPrefs(extension->id());
|
| + if (next_threshold <= initial_extension_threshold_) {
|
| + // Clear the next threshold in the prefs. This effectively raises it to
|
| + // |initial_extension_threshold_|. If the current threshold is already
|
| + // higher than this, leave it as is.
|
| + SetNextStorageThreshold(extension->id(), 0);
|
| +
|
| + if (storage_observer_.get()) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(&StorageEventObserver::UpdateThresholdForExtension,
|
| + storage_observer_,
|
| + extension->id(),
|
| + initial_extension_threshold_));
|
| + }
|
| + }
|
| +}
|
| +
|
| +void ExtensionStorageMonitor::OnExtensionUninstalled(
|
| + content::BrowserContext* browser_context,
|
| + const Extension* extension) {
|
| + RemoveNotificationForExtension(extension->id());
|
| +}
|
| +
|
| std::string ExtensionStorageMonitor::GetNotificationId(
|
| const std::string& extension_id) {
|
| std::vector<std::string> placeholders;
|
| @@ -250,9 +316,8 @@ void ExtensionStorageMonitor::OnStorageThresholdExceeded(
|
| if (!extension)
|
| return;
|
|
|
| - ExtensionPrefs* prefs = ExtensionPrefs::Get(context_);
|
| - DCHECK(prefs);
|
| - prefs->SetNextStorageThreshold(extension->id(), next_threshold);
|
| + if (GetNextStorageThreshold(extension->id()) < next_threshold)
|
| + SetNextStorageThreshold(extension->id(), next_threshold);
|
|
|
| const int kIconSize = message_center::kNotificationIconSize;
|
| ExtensionResource resource = IconsInfo::GetIconResource(
|
| @@ -332,9 +397,7 @@ void ExtensionStorageMonitor::DisableStorageMonitoring(
|
| const std::string& extension_id) {
|
| StopMonitoringStorage(extension_id);
|
|
|
| - ExtensionPrefs* prefs = ExtensionPrefs::Get(context_);
|
| - DCHECK(prefs);
|
| - prefs->SetStorageNotificationEnabled(extension_id, false);
|
| + SetStorageNotificationEnabled(extension_id, false);
|
|
|
| message_center::MessageCenter::Get()->RemoveNotification(
|
| GetNotificationId(extension_id), false);
|
| @@ -342,23 +405,17 @@ void ExtensionStorageMonitor::DisableStorageMonitoring(
|
|
|
| void ExtensionStorageMonitor::StartMonitoringStorage(
|
| const Extension* extension) {
|
| - if (!extension->HasAPIPermission(APIPermission::kUnlimitedStorage))
|
| - return;
|
| -
|
| - // Do not monitor storage for component extensions.
|
| - if (extension->location() == Manifest::COMPONENT)
|
| + if (!ShouldMonitorStorageFor(extension))
|
| return;
|
|
|
| - ExtensionPrefs* prefs = ExtensionPrefs::Get(context_);
|
| - DCHECK(prefs);
|
| -
|
| // First apply this feature only to experimental ephemeral apps. If it works
|
| // well, roll it out to all extensions and apps.
|
| - bool is_ephemeral = prefs->IsEphemeralApp(extension->id());
|
| - if (!is_ephemeral && !enable_for_all_extensions_)
|
| + if (!enable_for_all_extensions_ &&
|
| + !extension_prefs_->IsEphemeralApp(extension->id())) {
|
| return;
|
| + }
|
|
|
| - if (!prefs->IsStorageNotificationEnabled(extension->id()))
|
| + if (!IsStorageNotificationEnabled(extension->id()))
|
| return;
|
|
|
| // Lazily create the storage monitor proxy on the IO thread.
|
| @@ -379,14 +436,6 @@ void ExtensionStorageMonitor::StartMonitoringStorage(
|
| if (extension->is_hosted_app())
|
| storage_origin = AppLaunchInfo::GetLaunchWebURL(extension).GetOrigin();
|
|
|
| - int next_threshold = prefs->GetNextStorageThreshold(extension->id());
|
| - if (next_threshold == 0) {
|
| - // The next threshold is written to the prefs after the initial threshold is
|
| - // exceeded.
|
| - next_threshold = is_ephemeral ? initial_ephemeral_threshold_
|
| - : initial_extension_threshold_;
|
| - }
|
| -
|
| BrowserThread::PostTask(
|
| BrowserThread::IO,
|
| FROM_HERE,
|
| @@ -395,7 +444,7 @@ void ExtensionStorageMonitor::StartMonitoringStorage(
|
| quota_manager,
|
| extension->id(),
|
| storage_origin,
|
| - next_threshold,
|
| + GetNextStorageThreshold(extension->id()),
|
| observer_rate_));
|
| }
|
|
|
| @@ -413,9 +462,7 @@ void ExtensionStorageMonitor::StopMonitoringStorage(
|
| }
|
|
|
| void ExtensionStorageMonitor::StopMonitoringAll() {
|
| - ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
|
| - DCHECK(registry);
|
| - registry->RemoveObserver(this);
|
| + extension_registry_observer_.RemoveAll();
|
|
|
| RemoveAllNotifications();
|
|
|
| @@ -454,4 +501,64 @@ void ExtensionStorageMonitor::RemoveAllNotifications() {
|
| notified_extension_ids_.clear();
|
| }
|
|
|
| +int64 ExtensionStorageMonitor::GetNextStorageThreshold(
|
| + const std::string& extension_id) const {
|
| + int next_threshold = GetNextStorageThresholdFromPrefs(extension_id);
|
| + if (next_threshold == 0) {
|
| + // The next threshold is written to the prefs after the initial threshold is
|
| + // exceeded.
|
| + next_threshold = extension_prefs_->IsEphemeralApp(extension_id)
|
| + ? initial_ephemeral_threshold_
|
| + : initial_extension_threshold_;
|
| + }
|
| + return next_threshold;
|
| +}
|
| +
|
| +void ExtensionStorageMonitor::SetNextStorageThreshold(
|
| + const std::string& extension_id,
|
| + int64 next_threshold) {
|
| + extension_prefs_->UpdateExtensionPref(
|
| + extension_id,
|
| + kPrefNextStorageThreshold,
|
| + next_threshold > 0
|
| + ? new base::StringValue(base::Int64ToString(next_threshold))
|
| + : NULL);
|
| +}
|
| +
|
| +int64 ExtensionStorageMonitor::GetNextStorageThresholdFromPrefs(
|
| + const std::string& extension_id) const {
|
| + std::string next_threshold_str;
|
| + if (extension_prefs_->ReadPrefAsString(
|
| + extension_id, kPrefNextStorageThreshold, &next_threshold_str)) {
|
| + int64 next_threshold;
|
| + if (base::StringToInt64(next_threshold_str, &next_threshold))
|
| + return next_threshold;
|
| + }
|
| +
|
| + // A return value of zero indicates that the initial threshold has not yet
|
| + // been reached.
|
| + return 0;
|
| +}
|
| +
|
| +bool ExtensionStorageMonitor::IsStorageNotificationEnabled(
|
| + const std::string& extension_id) const {
|
| + bool disable_notifications;
|
| + if (extension_prefs_->ReadPrefAsBoolean(extension_id,
|
| + kPrefDisableStorageNotifications,
|
| + &disable_notifications)) {
|
| + return !disable_notifications;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void ExtensionStorageMonitor::SetStorageNotificationEnabled(
|
| + const std::string& extension_id,
|
| + bool enable_notifications) {
|
| + extension_prefs_->UpdateExtensionPref(
|
| + extension_id,
|
| + kPrefDisableStorageNotifications,
|
| + enable_notifications ? NULL : new base::FundamentalValue(true));
|
| +}
|
| +
|
| } // namespace extensions
|
|
|