1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// found in the LICENSE file.
4c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
5c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/extensions/extension_storage_monitor.h"
6c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
7c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <map>
8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
9c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/strings/string_number_conversions.h"
10c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/strings/string_util.h"
11c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/strings/utf_string_conversions.h"
12c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/chrome_notification_types.h"
1346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/extensions/extension_storage_monitor_factory.h"
15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/extensions/extension_util.h"
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
17c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
1803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/generated_resources.h"
19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "content/public/browser/browser_context.h"
20c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "content/public/browser/browser_thread.h"
21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "content/public/browser/notification_details.h"
22c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "content/public/browser/notification_source.h"
23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "content/public/browser/storage_partition.h"
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/browser/extension_prefs.h"
25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/browser/extension_registry.h"
2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/browser/extension_system.h"
276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/browser/image_loader.h"
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/uninstall_reason.h"
29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/extension.h"
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/manifest_handlers/icons_handler.h"
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/permissions/permissions_data.h"
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/quota/quota_manager.h"
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/quota/storage_observer.h"
34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/base/l10n/l10n_util.h"
35c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/message_center/message_center.h"
36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/message_center/notifier_settings.h"
37c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/message_center/views/constants.h"
38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochusing content::BrowserThread;
40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace extensions {
42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace {
44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// The rate at which we would like to observe storage events.
46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int kStorageEventRateSec = 30;
47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// The storage type to monitor.
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const storage::StorageType kMonitorStorageType =
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    storage::kStorageTypePersistent;
51c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Set the thresholds for the first notification. Ephemeral apps have a lower
53c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// threshold than installed extensions and apps. Once a threshold is exceeded,
54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// it will be doubled to throttle notifications.
55c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int64 kMBytes = 1024 * 1024;
56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int64 kEphemeralAppInitialThreshold = 250 * kMBytes;
57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int64 kExtensionInitialThreshold = 1000 * kMBytes;
58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Notifications have an ID so that we can update them.
60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kNotificationIdFormat[] = "ExtensionStorageMonitor-$1-$2";
61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kSystemNotifierId[] = "ExtensionStorageMonitor";
62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// A preference that stores the next threshold for displaying a notification
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// when an extension or app consumes excessive disk space. This will not be
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// set until the extension/app reaches the initial threshold.
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const char kPrefNextStorageThreshold[] = "next_storage_threshold";
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// If this preference is set to true, notifications will be suppressed when an
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// extension or app consumes excessive disk space.
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const char kPrefDisableStorageNotifications[] = "disable_storage_notifications";
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool ShouldMonitorStorageFor(const Extension* extension) {
7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Only monitor storage for extensions that are granted unlimited storage.
7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Do not monitor storage for component extensions.
7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return extension->permissions_data()->HasAPIPermission(
7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)             APIPermission::kUnlimitedStorage) &&
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)         extension->location() != Manifest::COMPONENT;
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
7946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const Extension* GetExtensionById(content::BrowserContext* context,
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  const std::string& extension_id) {
8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return ExtensionRegistry::Get(context)->GetExtensionById(
8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension_id, ExtensionRegistry::EVERYTHING);
8446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
86c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}  // namespace
87c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
88c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// StorageEventObserver monitors the storage usage of extensions and lives on
89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// the IO thread. When a threshold is exceeded, a message will be posted to the
90c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// UI thread, which displays the notification.
91c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass StorageEventObserver
9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : public base::RefCountedThreadSafe<StorageEventObserver,
9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                        BrowserThread::DeleteOnIOThread>,
9403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      public storage::StorageObserver {
95c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch public:
96c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  explicit StorageEventObserver(
97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::WeakPtr<ExtensionStorageMonitor> storage_monitor)
98c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      : storage_monitor_(storage_monitor) {
99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
100c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
101c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Register as an observer for the extension's storage events.
102c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  void StartObservingForExtension(
10303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      scoped_refptr<storage::QuotaManager> quota_manager,
104c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      const std::string& extension_id,
105c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      const GURL& site_url,
106c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      int64 next_threshold,
107c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      int rate) {
108c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
109c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DCHECK(quota_manager.get());
110c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
111c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    GURL origin = site_url.GetOrigin();
112c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    StorageState& state = origin_state_map_[origin];
113c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    state.quota_manager = quota_manager;
114c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    state.extension_id = extension_id;
115c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    state.next_threshold = next_threshold;
116c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
11703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    storage::StorageObserver::MonitorParams params(
11803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        kMonitorStorageType, origin, base::TimeDelta::FromSeconds(rate), false);
119c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    quota_manager->AddStorageObserver(this, params);
120c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
121c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Updates the threshold for an extension already being monitored.
12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void UpdateThresholdForExtension(const std::string& extension_id,
12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   int64 next_threshold) {
12546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
12646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
12746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    for (OriginStorageStateMap::iterator it = origin_state_map_.begin();
12846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)         it != origin_state_map_.end();
12946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)         ++it) {
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (it->second.extension_id == extension_id) {
13146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        it->second.next_threshold = next_threshold;
13246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        break;
13346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      }
13446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
13546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
13646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
137c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Deregister as an observer for the extension's storage events.
138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  void StopObservingForExtension(const std::string& extension_id) {
139c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    for (OriginStorageStateMap::iterator it = origin_state_map_.begin();
142c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         it != origin_state_map_.end(); ) {
143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (it->second.extension_id == extension_id) {
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        storage::StorageObserver::Filter filter(kMonitorStorageType, it->first);
145c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        it->second.quota_manager->RemoveStorageObserverForFilter(this, filter);
146c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        origin_state_map_.erase(it++);
147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      } else {
148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        ++it;
149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      }
150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
151c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
152c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
153c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Stop observing all storage events. Called during shutdown.
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  void StopObserving() {
155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
157c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    for (OriginStorageStateMap::iterator it = origin_state_map_.begin();
158c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         it != origin_state_map_.end(); ++it) {
159c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      it->second.quota_manager->RemoveStorageObserver(this);
160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
161c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    origin_state_map_.clear();
162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
163c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
164c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch private:
165c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  friend class base::DeleteHelper<StorageEventObserver>;
166c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  friend struct content::BrowserThread::DeleteOnThread<
167c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      content::BrowserThread::IO>;
168c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
169c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  struct StorageState {
17003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_refptr<storage::QuotaManager> quota_manager;
171c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    std::string extension_id;
172c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    int64 next_threshold;
173c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
174c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    StorageState() : next_threshold(0) {}
175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  };
176c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  typedef std::map<GURL, StorageState> OriginStorageStateMap;
177c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  virtual ~StorageEventObserver() {
179c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DCHECK(origin_state_map_.empty());
180c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    StopObserving();
181c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // storage::StorageObserver implementation.
184c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  virtual void OnStorageEvent(const Event& event) OVERRIDE {
185c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    OriginStorageStateMap::iterator state =
186c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        origin_state_map_.find(event.filter.origin);
187c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (state == origin_state_map_.end())
188c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return;
189c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
190c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (event.usage >= state->second.next_threshold) {
191c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      while (event.usage >= state->second.next_threshold)
192c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        state->second.next_threshold *= 2;
193c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      BrowserThread::PostTask(
195c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          BrowserThread::UI,
196c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          FROM_HERE,
197c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          base::Bind(&ExtensionStorageMonitor::OnStorageThresholdExceeded,
198c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     storage_monitor_,
199c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     state->second.extension_id,
200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     state->second.next_threshold,
201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     event.usage));
202c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
203c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
204c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
205c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  OriginStorageStateMap origin_state_map_;
206c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  base::WeakPtr<ExtensionStorageMonitor> storage_monitor_;
207c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch};
208c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
209c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// ExtensionStorageMonitor
210c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
211c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// static
212c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochExtensionStorageMonitor* ExtensionStorageMonitor::Get(
213c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    content::BrowserContext* context) {
214c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return ExtensionStorageMonitorFactory::GetForBrowserContext(context);
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
216c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
217c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochExtensionStorageMonitor::ExtensionStorageMonitor(
218c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    content::BrowserContext* context)
219c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    : enable_for_all_extensions_(false),
220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      initial_extension_threshold_(kExtensionInitialThreshold),
221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      initial_ephemeral_threshold_(kEphemeralAppInitialThreshold),
222c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      observer_rate_(kStorageEventRateSec),
223c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      context_(context),
22446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension_prefs_(ExtensionPrefs::Get(context)),
22546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension_registry_observer_(this),
226c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      weak_ptr_factory_(this) {
22746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(extension_prefs_);
22846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
229c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
230c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 content::Source<content::BrowserContext>(context_));
231c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
23246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  extension_registry_observer_.Add(ExtensionRegistry::Get(context_));
233c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
234c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
235c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochExtensionStorageMonitor::~ExtensionStorageMonitor() {}
236c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
237c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::Observe(
238c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    int type,
239c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const content::NotificationSource& source,
240c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const content::NotificationDetails& details) {
241c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  switch (type) {
242c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      StopMonitoringAll();
244c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      break;
245c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
246c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    default:
247c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      NOTREACHED();
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
249c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
250c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
251c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::OnExtensionLoaded(
252c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    content::BrowserContext* browser_context,
253c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const Extension* extension) {
254c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  StartMonitoringStorage(extension);
255c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
256c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
257c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::OnExtensionUnloaded(
258c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    content::BrowserContext* browser_context,
2590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const Extension* extension,
2600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    UnloadedExtensionInfo::Reason reason) {
261c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  StopMonitoringStorage(extension->id());
262c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
263c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
26446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionStorageMonitor::OnExtensionWillBeInstalled(
26546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    content::BrowserContext* browser_context,
26646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const Extension* extension,
26746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    bool is_update,
26846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    bool from_ephemeral,
26946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& old_name) {
27046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // If an ephemeral app was promoted to a regular installed app, we may need to
27146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // increase its next threshold.
27246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!from_ephemeral || !ShouldMonitorStorageFor(extension))
27346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
27446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
27546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!enable_for_all_extensions_) {
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // If monitoring is not enabled for installed extensions, just stop
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // monitoring.
27846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    SetNextStorageThreshold(extension->id(), 0);
27946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    StopMonitoringStorage(extension->id());
28046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
28146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
28246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  int64 next_threshold = GetNextStorageThresholdFromPrefs(extension->id());
28446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (next_threshold <= initial_extension_threshold_) {
28546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // Clear the next threshold in the prefs. This effectively raises it to
28646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // |initial_extension_threshold_|. If the current threshold is already
28746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // higher than this, leave it as is.
28846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    SetNextStorageThreshold(extension->id(), 0);
28946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
29046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (storage_observer_.get()) {
29146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      BrowserThread::PostTask(
29246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          BrowserThread::IO,
29346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          FROM_HERE,
29446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          base::Bind(&StorageEventObserver::UpdateThresholdForExtension,
29546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     storage_observer_,
29646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     extension->id(),
29746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     initial_extension_threshold_));
29846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
29946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
30046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
30146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
30246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionStorageMonitor::OnExtensionUninstalled(
30346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    content::BrowserContext* browser_context,
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const Extension* extension,
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    extensions::UninstallReason reason) {
30646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RemoveNotificationForExtension(extension->id());
30746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
30846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
30946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionStorageMonitor::ExtensionUninstallAccepted() {
31046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(!uninstall_extension_id_.empty());
31146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
31246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const Extension* extension = GetExtensionById(context_,
31346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                                uninstall_extension_id_);
31446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  uninstall_extension_id_.clear();
31546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!extension)
31646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
31746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
31846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ExtensionService* service =
31946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ExtensionSystem::Get(context_)->extension_service();
32046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(service);
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  service->UninstallExtension(
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension->id(),
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extensions::UNINSTALL_REASON_STORAGE_THRESHOLD_EXCEEDED,
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&base::DoNothing),
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      NULL);
32646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
32746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
32846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionStorageMonitor::ExtensionUninstallCanceled() {
32946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  uninstall_extension_id_.clear();
33046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
33146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
332c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstd::string ExtensionStorageMonitor::GetNotificationId(
333c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& extension_id) {
334c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::vector<std::string> placeholders;
335c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  placeholders.push_back(context_->GetPath().BaseName().MaybeAsASCII());
336c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  placeholders.push_back(extension_id);
337c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
338c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return ReplaceStringPlaceholders(kNotificationIdFormat, placeholders, NULL);
339c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
340c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
341c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::OnStorageThresholdExceeded(
342c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& extension_id,
343c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    int64 next_threshold,
344c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    int64 current_usage) {
345c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
346c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
34746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const Extension* extension = GetExtensionById(context_, extension_id);
348c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!extension)
349c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
350c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
35146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (GetNextStorageThreshold(extension->id()) < next_threshold)
35246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    SetNextStorageThreshold(extension->id(), next_threshold);
353c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
354c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const int kIconSize = message_center::kNotificationIconSize;
355c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ExtensionResource resource =  IconsInfo::GetIconResource(
356c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      extension, kIconSize, ExtensionIconSet::MATCH_BIGGER);
357c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ImageLoader::Get(context_)->LoadImageAsync(
358c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      extension, resource, gfx::Size(kIconSize, kIconSize),
359c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(&ExtensionStorageMonitor::OnImageLoaded,
360c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 weak_ptr_factory_.GetWeakPtr(),
361c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 extension_id,
362c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 current_usage));
363c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
364c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
365c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::OnImageLoaded(
366c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& extension_id,
367c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    int64 current_usage,
368c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const gfx::Image& image) {
36946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const Extension* extension = GetExtensionById(context_, extension_id);
370c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!extension)
371c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
372c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
373c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Remove any existing notifications to force a new notification to pop up.
374c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::string notification_id(GetNotificationId(extension_id));
375c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  message_center::MessageCenter::Get()->RemoveNotification(
376c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      notification_id, false);
377c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
378c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  message_center::RichNotificationData notification_data;
379c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  notification_data.buttons.push_back(message_center::ButtonInfo(
380c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      l10n_util::GetStringUTF16(extension->is_app() ?
381c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          IDS_EXTENSION_STORAGE_MONITOR_BUTTON_DISMISS_APP :
382c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          IDS_EXTENSION_STORAGE_MONITOR_BUTTON_DISMISS_EXTENSION)));
38346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  notification_data.buttons.push_back(message_center::ButtonInfo(
38446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      l10n_util::GetStringUTF16(extension->is_app() ?
38546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          IDS_EXTENSION_STORAGE_MONITOR_BUTTON_UNINSTALL_APP :
38646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          IDS_EXTENSION_STORAGE_MONITOR_BUTTON_UNINSTALL_EXTENSION)));
387c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
388c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  gfx::Image notification_image(image);
389c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (notification_image.IsEmpty()) {
390c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    notification_image =
3915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        extension->is_app() ? gfx::Image(util::GetDefaultAppIcon())
3925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                            : gfx::Image(util::GetDefaultExtensionIcon());
393c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
394c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
395c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<message_center::Notification> notification;
396c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  notification.reset(new message_center::Notification(
397c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      message_center::NOTIFICATION_TYPE_SIMPLE,
398c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      notification_id,
399c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      l10n_util::GetStringUTF16(IDS_EXTENSION_STORAGE_MONITOR_TITLE),
400c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      l10n_util::GetStringFUTF16(
401c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          IDS_EXTENSION_STORAGE_MONITOR_TEXT,
402c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          base::UTF8ToUTF16(extension->name()),
403c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          base::IntToString16(current_usage / kMBytes)),
404c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      notification_image,
405c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::string16() /* display source */,
406c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      message_center::NotifierId(
407c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          message_center::NotifierId::SYSTEM_COMPONENT, kSystemNotifierId),
408c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      notification_data,
409c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      new message_center::HandleNotificationButtonClickDelegate(base::Bind(
410c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          &ExtensionStorageMonitor::OnNotificationButtonClick,
411c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          weak_ptr_factory_.GetWeakPtr(),
412c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          extension_id))));
413c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  notification->SetSystemPriority();
414c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
415c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
416c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  notified_extension_ids_.insert(extension_id);
417c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
418c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
419c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::OnNotificationButtonClick(
420c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& extension_id, int button_index) {
421c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  switch (button_index) {
422c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case BUTTON_DISABLE_NOTIFICATION: {
423c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      DisableStorageMonitoring(extension_id);
424c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      break;
425c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
42646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    case BUTTON_UNINSTALL: {
42746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ShowUninstallPrompt(extension_id);
42846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      break;
42946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
430c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    default:
431c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      NOTREACHED();
432cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
433c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
434c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
435c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::DisableStorageMonitoring(
436c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& extension_id) {
437c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  StopMonitoringStorage(extension_id);
438c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
43946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  SetStorageNotificationEnabled(extension_id, false);
440c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
441c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  message_center::MessageCenter::Get()->RemoveNotification(
442c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      GetNotificationId(extension_id), false);
443c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
444c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
445c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::StartMonitoringStorage(
446c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const Extension* extension) {
44746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!ShouldMonitorStorageFor(extension))
448c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
449c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
450c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // First apply this feature only to experimental ephemeral apps. If it works
451c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // well, roll it out to all extensions and apps.
45246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!enable_for_all_extensions_ &&
45346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      !extension_prefs_->IsEphemeralApp(extension->id())) {
454c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
45546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
456c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
45746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!IsStorageNotificationEnabled(extension->id()))
458c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
459c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
460c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Lazily create the storage monitor proxy on the IO thread.
461c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!storage_observer_.get()) {
462c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    storage_observer_ =
463c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        new StorageEventObserver(weak_ptr_factory_.GetWeakPtr());
464c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
465c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
466c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GURL site_url =
467c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      extensions::util::GetSiteForExtensionId(extension->id(), context_);
468c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  content::StoragePartition* storage_partition =
469c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      content::BrowserContext::GetStoragePartitionForSite(context_, site_url);
470c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(storage_partition);
47103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_refptr<storage::QuotaManager> quota_manager(
472c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      storage_partition->GetQuotaManager());
473c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
474c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GURL storage_origin(site_url.GetOrigin());
475c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (extension->is_hosted_app())
476c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    storage_origin = AppLaunchInfo::GetLaunchWebURL(extension).GetOrigin();
477c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
478c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BrowserThread::PostTask(
479c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      BrowserThread::IO,
480c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
481c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(&StorageEventObserver::StartObservingForExtension,
482c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 storage_observer_,
483c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 quota_manager,
484c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 extension->id(),
485c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 storage_origin,
48646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 GetNextStorageThreshold(extension->id()),
487c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 observer_rate_));
488c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
489c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
490c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::StopMonitoringStorage(
491c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& extension_id) {
492c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!storage_observer_.get())
493c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
494c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
495c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BrowserThread::PostTask(
496c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      BrowserThread::IO,
497c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
498c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(&StorageEventObserver::StopObservingForExtension,
499c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 storage_observer_,
500c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 extension_id));
501c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
502c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
503c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::StopMonitoringAll() {
50446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  extension_registry_observer_.RemoveAll();
505c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
506c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  RemoveAllNotifications();
507c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
508c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!storage_observer_.get())
509c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
510c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
511c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BrowserThread::PostTask(
512c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      BrowserThread::IO,
513c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
514c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(&StorageEventObserver::StopObserving, storage_observer_));
515c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  storage_observer_ = NULL;
516c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
517c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
518c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::RemoveNotificationForExtension(
519c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& extension_id) {
520c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::set<std::string>::iterator ext_id =
521c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      notified_extension_ids_.find(extension_id);
522c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (ext_id == notified_extension_ids_.end())
523c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
524c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
525c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  notified_extension_ids_.erase(ext_id);
526c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  message_center::MessageCenter::Get()->RemoveNotification(
527c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      GetNotificationId(extension_id), false);
528c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
529c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
530c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ExtensionStorageMonitor::RemoveAllNotifications() {
531c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (notified_extension_ids_.empty())
532c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
533c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
534c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  message_center::MessageCenter* center = message_center::MessageCenter::Get();
535c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(center);
536c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (std::set<std::string>::iterator it = notified_extension_ids_.begin();
537c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       it != notified_extension_ids_.end(); ++it) {
538c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    center->RemoveNotification(GetNotificationId(*it), false);
539c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
540c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  notified_extension_ids_.clear();
541c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
542c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
54346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionStorageMonitor::ShowUninstallPrompt(
54446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& extension_id) {
54546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const Extension* extension = GetExtensionById(context_, extension_id);
54646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!extension)
54746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
54846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
54946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!uninstall_dialog_.get()) {
55046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
55146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        Profile::FromBrowserContext(context_), NULL, this));
55246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
55346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
55446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  uninstall_extension_id_ = extension->id();
55546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  uninstall_dialog_->ConfirmUninstall(extension);
55646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
55746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
55846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)int64 ExtensionStorageMonitor::GetNextStorageThreshold(
55946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& extension_id) const {
56046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  int next_threshold = GetNextStorageThresholdFromPrefs(extension_id);
56146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (next_threshold == 0) {
56246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // The next threshold is written to the prefs after the initial threshold is
56346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // exceeded.
56446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    next_threshold = extension_prefs_->IsEphemeralApp(extension_id)
56546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         ? initial_ephemeral_threshold_
56646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         : initial_extension_threshold_;
56746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
56846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return next_threshold;
56946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
57046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
57146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionStorageMonitor::SetNextStorageThreshold(
57246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& extension_id,
57346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    int64 next_threshold) {
57446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  extension_prefs_->UpdateExtensionPref(
57546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension_id,
57646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      kPrefNextStorageThreshold,
57746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      next_threshold > 0
57846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          ? new base::StringValue(base::Int64ToString(next_threshold))
57946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          : NULL);
58046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
58146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
58246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)int64 ExtensionStorageMonitor::GetNextStorageThresholdFromPrefs(
58346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& extension_id) const {
58446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::string next_threshold_str;
58546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (extension_prefs_->ReadPrefAsString(
58646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          extension_id, kPrefNextStorageThreshold, &next_threshold_str)) {
58746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    int64 next_threshold;
58846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (base::StringToInt64(next_threshold_str, &next_threshold))
58946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return next_threshold;
59046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
59146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
59246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // A return value of zero indicates that the initial threshold has not yet
59346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // been reached.
59446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return 0;
59546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
59646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
59746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool ExtensionStorageMonitor::IsStorageNotificationEnabled(
59846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& extension_id) const {
59946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  bool disable_notifications;
60046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (extension_prefs_->ReadPrefAsBoolean(extension_id,
60146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                          kPrefDisableStorageNotifications,
60246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                          &disable_notifications)) {
60346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return !disable_notifications;
60446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
60546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
60646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return true;
60746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
60846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
60946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionStorageMonitor::SetStorageNotificationEnabled(
61046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& extension_id,
61146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    bool enable_notifications) {
61246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  extension_prefs_->UpdateExtensionPref(
61346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension_id,
61446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      kPrefDisableStorageNotifications,
61546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      enable_notifications ? NULL : new base::FundamentalValue(true));
61646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
61746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
618c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}  // namespace extensions
619