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