1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/storage/sync_or_local_value_store_cache.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "base/files/file_path.h" 10 #include "base/sequenced_task_runner.h" 11 #include "chrome/browser/extensions/api/storage/settings_backend.h" 12 #include "chrome/browser/extensions/api/storage/settings_frontend.h" 13 #include "chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.h" 14 #include "chrome/browser/extensions/api/storage/weak_unlimited_settings_storage.h" 15 #include "chrome/browser/sync/glue/sync_start_util.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "extensions/common/constants.h" 18 #include "extensions/common/extension.h" 19 #include "extensions/common/permissions/api_permission.h" 20 21 using content::BrowserThread; 22 23 namespace extensions { 24 25 SyncOrLocalValueStoreCache::SyncOrLocalValueStoreCache( 26 settings_namespace::Namespace settings_namespace, 27 const scoped_refptr<SettingsStorageFactory>& factory, 28 const SettingsStorageQuotaEnforcer::Limits& quota, 29 const scoped_refptr<SettingsObserverList>& observers, 30 const base::FilePath& profile_path) 31 : settings_namespace_(settings_namespace) { 32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 33 DCHECK(settings_namespace_ == settings_namespace::LOCAL || 34 settings_namespace_ == settings_namespace::SYNC); 35 36 // This post is safe since the destructor can only be invoked from the 37 // same message loop, and any potential post of a deletion task must come 38 // after the constructor returns. 39 BrowserThread::PostTask( 40 BrowserThread::FILE, FROM_HERE, 41 base::Bind(&SyncOrLocalValueStoreCache::InitOnFileThread, 42 base::Unretained(this), 43 factory, quota, observers, profile_path)); 44 } 45 46 SyncOrLocalValueStoreCache::~SyncOrLocalValueStoreCache() { 47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 48 } 49 50 SettingsBackend* SyncOrLocalValueStoreCache::GetAppBackend() const { 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 52 DCHECK(app_backend_.get()); 53 return app_backend_.get(); 54 } 55 56 SettingsBackend* SyncOrLocalValueStoreCache::GetExtensionBackend() const { 57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 58 DCHECK(extension_backend_.get()); 59 return extension_backend_.get(); 60 } 61 62 void SyncOrLocalValueStoreCache::RunWithValueStoreForExtension( 63 const StorageCallback& callback, 64 scoped_refptr<const Extension> extension) { 65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 66 DCHECK(app_backend_.get()); 67 DCHECK(extension_backend_.get()); 68 SettingsBackend* backend = 69 extension->is_app() ? app_backend_.get() : extension_backend_.get(); 70 ValueStore* storage = backend->GetStorage(extension->id()); 71 72 // A neat way to implement unlimited storage; if the extension has the 73 // unlimited storage permission, force through all calls to Set() (in the 74 // same way that writes from sync ignore quota). 75 // But only if it's local storage (bad stuff would happen if sync'ed 76 // storage is allowed to be unlimited). 77 bool is_unlimited = 78 settings_namespace_ == settings_namespace::LOCAL && 79 extension->HasAPIPermission(APIPermission::kUnlimitedStorage); 80 81 if (is_unlimited) { 82 WeakUnlimitedSettingsStorage unlimited_storage(storage); 83 callback.Run(&unlimited_storage); 84 } else { 85 callback.Run(storage); 86 } 87 } 88 89 void SyncOrLocalValueStoreCache::DeleteStorageSoon( 90 const std::string& extension_id) { 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 92 app_backend_->DeleteStorage(extension_id); 93 extension_backend_->DeleteStorage(extension_id); 94 } 95 96 void SyncOrLocalValueStoreCache::InitOnFileThread( 97 const scoped_refptr<SettingsStorageFactory>& factory, 98 const SettingsStorageQuotaEnforcer::Limits& quota, 99 const scoped_refptr<SettingsObserverList>& observers, 100 const base::FilePath& profile_path) { 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 102 DCHECK(!app_backend_.get()); 103 DCHECK(!extension_backend_.get()); 104 const bool local = settings_namespace_ == settings_namespace::LOCAL; 105 const base::FilePath app_path = profile_path.AppendASCII( 106 local ? extensions::kLocalAppSettingsDirectoryName 107 : extensions::kSyncAppSettingsDirectoryName); 108 const base::FilePath extension_path = profile_path.AppendASCII( 109 local ? extensions::kLocalExtensionSettingsDirectoryName 110 : extensions::kSyncExtensionSettingsDirectoryName); 111 app_backend_.reset(new SettingsBackend( 112 factory, app_path, syncer::APP_SETTINGS, 113 sync_start_util::GetFlareForSyncableService(profile_path), 114 quota, observers)); 115 extension_backend_.reset(new SettingsBackend( 116 factory, extension_path, syncer::EXTENSION_SETTINGS, 117 sync_start_util::GetFlareForSyncableService(profile_path), 118 quota, observers)); 119 } 120 121 } // namespace extensions 122