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 |