Home | History | Annotate | Download | only in storage
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "extensions/browser/api/storage/storage_frontend.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/files/file_path.h"
     10 #include "base/json/json_reader.h"
     11 #include "base/lazy_instance.h"
     12 #include "content/public/browser/browser_context.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "extensions/browser/api/extensions_api_client.h"
     15 #include "extensions/browser/api/storage/leveldb_settings_storage_factory.h"
     16 #include "extensions/browser/api/storage/local_value_store_cache.h"
     17 #include "extensions/browser/event_router.h"
     18 #include "extensions/browser/extension_registry.h"
     19 #include "extensions/common/api/storage.h"
     20 
     21 using content::BrowserContext;
     22 using content::BrowserThread;
     23 
     24 namespace extensions {
     25 
     26 namespace {
     27 
     28 base::LazyInstance<BrowserContextKeyedAPIFactory<StorageFrontend> > g_factory =
     29     LAZY_INSTANCE_INITIALIZER;
     30 
     31 // Settings change Observer which forwards changes on to the extension
     32 // processes for |context| and its incognito partner if it exists.
     33 class DefaultObserver : public SettingsObserver {
     34  public:
     35   explicit DefaultObserver(BrowserContext* context)
     36       : browser_context_(context) {}
     37 
     38   // SettingsObserver implementation.
     39   virtual void OnSettingsChanged(
     40       const std::string& extension_id,
     41       settings_namespace::Namespace settings_namespace,
     42       const std::string& change_json) OVERRIDE {
     43     // TODO(gdk): This is a temporary hack while the refactoring for
     44     // string-based event payloads is removed. http://crbug.com/136045
     45     scoped_ptr<base::ListValue> args(new base::ListValue());
     46     args->Append(base::JSONReader::Read(change_json));
     47     args->Append(new base::StringValue(settings_namespace::ToString(
     48         settings_namespace)));
     49     scoped_ptr<Event> event(new Event(
     50         core_api::storage::OnChanged::kEventName, args.Pass()));
     51     EventRouter::Get(browser_context_)
     52         ->DispatchEventToExtension(extension_id, event.Pass());
     53   }
     54 
     55  private:
     56   BrowserContext* const browser_context_;
     57 };
     58 
     59 }  // namespace
     60 
     61 // static
     62 StorageFrontend* StorageFrontend::Get(BrowserContext* context) {
     63   return BrowserContextKeyedAPIFactory<StorageFrontend>::Get(context);
     64 }
     65 
     66 // static
     67 StorageFrontend* StorageFrontend::CreateForTesting(
     68     const scoped_refptr<SettingsStorageFactory>& storage_factory,
     69     BrowserContext* context) {
     70   return new StorageFrontend(storage_factory, context);
     71 }
     72 
     73 StorageFrontend::StorageFrontend(BrowserContext* context)
     74     : browser_context_(context) {
     75   Init(new LeveldbSettingsStorageFactory());
     76 }
     77 
     78 StorageFrontend::StorageFrontend(
     79     const scoped_refptr<SettingsStorageFactory>& factory,
     80     BrowserContext* context)
     81     : browser_context_(context) {
     82   Init(factory);
     83 }
     84 
     85 void StorageFrontend::Init(
     86     const scoped_refptr<SettingsStorageFactory>& factory) {
     87   observers_ = new SettingsObserverList();
     88   browser_context_observer_.reset(new DefaultObserver(browser_context_));
     89   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     90   DCHECK(!browser_context_->IsOffTheRecord());
     91 
     92   observers_->AddObserver(browser_context_observer_.get());
     93 
     94   caches_[settings_namespace::LOCAL] =
     95       new LocalValueStoreCache(factory, browser_context_->GetPath());
     96 
     97   // Add any additional caches the embedder supports (for example, caches
     98   // for chrome.storage.managed and chrome.storage.sync).
     99   ExtensionsAPIClient::Get()->AddAdditionalValueStoreCaches(
    100       browser_context_, factory, observers_, &caches_);
    101 }
    102 
    103 StorageFrontend::~StorageFrontend() {
    104   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    105   observers_->RemoveObserver(browser_context_observer_.get());
    106   for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) {
    107     ValueStoreCache* cache = it->second;
    108     cache->ShutdownOnUI();
    109     BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, cache);
    110   }
    111 }
    112 
    113 ValueStoreCache* StorageFrontend::GetValueStoreCache(
    114     settings_namespace::Namespace settings_namespace) const {
    115   CacheMap::const_iterator it = caches_.find(settings_namespace);
    116   if (it != caches_.end())
    117     return it->second;
    118   return NULL;
    119 }
    120 
    121 bool StorageFrontend::IsStorageEnabled(
    122     settings_namespace::Namespace settings_namespace) const {
    123   return caches_.find(settings_namespace) != caches_.end();
    124 }
    125 
    126 void StorageFrontend::RunWithStorage(
    127     scoped_refptr<const Extension> extension,
    128     settings_namespace::Namespace settings_namespace,
    129     const ValueStoreCache::StorageCallback& callback) {
    130   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    131   CHECK(extension.get());
    132 
    133   ValueStoreCache* cache = caches_[settings_namespace];
    134   CHECK(cache);
    135 
    136   BrowserThread::PostTask(
    137       BrowserThread::FILE, FROM_HERE,
    138       base::Bind(&ValueStoreCache::RunWithValueStoreForExtension,
    139                  base::Unretained(cache), callback, extension));
    140 }
    141 
    142 void StorageFrontend::DeleteStorageSoon(const std::string& extension_id) {
    143   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    144   for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) {
    145     ValueStoreCache* cache = it->second;
    146     BrowserThread::PostTask(
    147         BrowserThread::FILE, FROM_HERE,
    148         base::Bind(&ValueStoreCache::DeleteStorageSoon,
    149                    base::Unretained(cache),
    150                    extension_id));
    151   }
    152 }
    153 
    154 scoped_refptr<SettingsObserverList> StorageFrontend::GetObservers() {
    155   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    156   return observers_;
    157 }
    158 
    159 void StorageFrontend::DisableStorageForTesting(
    160     settings_namespace::Namespace settings_namespace) {
    161   CacheMap::iterator it = caches_.find(settings_namespace);
    162   if (it != caches_.end()) {
    163     ValueStoreCache* cache = it->second;
    164     cache->ShutdownOnUI();
    165     BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, cache);
    166     caches_.erase(it);
    167   }
    168 }
    169 
    170 // BrowserContextKeyedAPI implementation.
    171 
    172 // static
    173 BrowserContextKeyedAPIFactory<StorageFrontend>*
    174 StorageFrontend::GetFactoryInstance() {
    175   return g_factory.Pointer();
    176 }
    177 
    178 // static
    179 const char* StorageFrontend::service_name() { return "StorageFrontend"; }
    180 
    181 }  // namespace extensions
    182