| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/extension_settings_backend.h" | 5 #include "chrome/browser/extensions/extension_settings_backend.h" |
| 6 | 6 |
| 7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
| 8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
| 10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 // restrictive than that. | 31 // restrictive than that. |
| 32 const size_t kQuotaPerSettingBytes = 2048; | 32 const size_t kQuotaPerSettingBytes = 2048; |
| 33 | 33 |
| 34 // Max number of settings per extension. Keep low for sync. | 34 // Max number of settings per extension. Keep low for sync. |
| 35 const size_t kMaxSettingKeys = 512; | 35 const size_t kMaxSettingKeys = 512; |
| 36 | 36 |
| 37 } // namespace | 37 } // namespace |
| 38 | 38 |
| 39 ExtensionSettingsBackend::ExtensionSettingsBackend( | 39 ExtensionSettingsBackend::ExtensionSettingsBackend( |
| 40 const FilePath& base_path, | 40 const FilePath& base_path, |
| 41 const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >& | 41 const scoped_refptr<ExtensionSettingsObserverList>& observers) |
| 42 observers) | |
| 43 : base_path_(base_path), | 42 : base_path_(base_path), |
| 44 observers_(observers), | 43 observers_(observers), |
| 44 sync_type_(syncable::UNSPECIFIED), |
| 45 sync_processor_(NULL) { | 45 sync_processor_(NULL) { |
| 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 47 } | 47 } |
| 48 | 48 |
| 49 ExtensionSettingsBackend::~ExtensionSettingsBackend() { | 49 ExtensionSettingsBackend::~ExtensionSettingsBackend() { |
| 50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 51 } | 51 } |
| 52 | 52 |
| 53 ExtensionSettingsStorage* ExtensionSettingsBackend::GetStorage( | 53 ExtensionSettingsStorage* ExtensionSettingsBackend::GetStorage( |
| 54 const std::string& extension_id) const { | 54 const std::string& extension_id) const { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 kTotalQuotaBytes, kQuotaPerSettingBytes, kMaxSettingKeys, storage); | 86 kTotalQuotaBytes, kQuotaPerSettingBytes, kMaxSettingKeys, storage); |
| 87 | 87 |
| 88 syncable_storage = | 88 syncable_storage = |
| 89 linked_ptr<SyncableExtensionSettingsStorage>( | 89 linked_ptr<SyncableExtensionSettingsStorage>( |
| 90 new SyncableExtensionSettingsStorage( | 90 new SyncableExtensionSettingsStorage( |
| 91 observers_, | 91 observers_, |
| 92 extension_id, | 92 extension_id, |
| 93 storage)); | 93 storage)); |
| 94 if (sync_processor_) { | 94 if (sync_processor_) { |
| 95 // TODO(kalman): do something if StartSyncing fails. | 95 // TODO(kalman): do something if StartSyncing fails. |
| 96 ignore_result(syncable_storage->StartSyncing(sync_data, sync_processor_)); | 96 ignore_result(syncable_storage->StartSyncing( |
| 97 sync_type_, sync_data, sync_processor_)); |
| 97 } | 98 } |
| 98 | 99 |
| 99 storage_objs_[extension_id] = syncable_storage; | 100 storage_objs_[extension_id] = syncable_storage; |
| 100 return syncable_storage.get(); | 101 return syncable_storage.get(); |
| 101 } | 102 } |
| 102 | 103 |
| 103 void ExtensionSettingsBackend::DeleteExtensionData( | 104 void ExtensionSettingsBackend::DeleteStorage(const std::string& extension_id) { |
| 104 const std::string& extension_id) { | |
| 105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 106 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); | 106 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); |
| 107 if (maybe_storage == storage_objs_.end()) { | 107 if (maybe_storage == storage_objs_.end()) { |
| 108 return; | 108 return; |
| 109 } | 109 } |
| 110 | 110 |
| 111 // Clear settings when the extension is uninstalled. Leveldb implementations | 111 // Clear settings when the extension is uninstalled. Leveldb implementations |
| 112 // will also delete the database from disk when the object is destroyed as | 112 // will also delete the database from disk when the object is destroyed as |
| 113 // a result of being removed from |storage_objs_|. | 113 // a result of being removed from |storage_objs_|. |
| 114 maybe_storage->second->Clear(); | 114 maybe_storage->second->Clear(); |
| 115 storage_objs_.erase(maybe_storage); | 115 storage_objs_.erase(maybe_storage); |
| 116 } | 116 } |
| 117 | 117 |
| 118 void ExtensionSettingsBackend::TriggerOnSettingsChanged( | 118 void ExtensionSettingsBackend::TriggerOnSettingsChanged( |
| 119 Profile* profile, | 119 Profile* profile, |
| 120 const std::string& extension_id, | 120 const std::string& extension_id, |
| 121 const ExtensionSettingChanges& changes) const { | 121 const ExtensionSettingChanges& changes) const { |
| 122 observers_->Notify( | 122 observers_->Notify( |
| 123 &ExtensionSettingsObserver::OnSettingsChanged, | 123 &ExtensionSettingsObserver::OnSettingsChanged, |
| 124 profile, | 124 profile, |
| 125 extension_id, | 125 extension_id, |
| 126 changes); | 126 changes); |
| 127 } | 127 } |
| 128 | 128 |
| 129 std::set<std::string> ExtensionSettingsBackend::GetKnownExtensionIDs() const { | 129 std::set<std::string> ExtensionSettingsBackend::GetKnownExtensionIDs() const { |
| 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 131 std::set<std::string> result; | 131 std::set<std::string> result; |
| 132 | 132 |
| 133 // TODO(kalman): we will need to do something to disambiguate between app | |
| 134 // settings and extension settings, since settings for apps should be synced | |
| 135 // iff app sync is turned on, ditto for extensions. | |
| 136 | |
| 137 // Extension IDs live in-memory and/or on disk. The cache will contain all | 133 // Extension IDs live in-memory and/or on disk. The cache will contain all |
| 138 // that are in-memory. | 134 // that are in-memory. |
| 139 for (StorageObjMap::iterator it = storage_objs_.begin(); | 135 for (StorageObjMap::iterator it = storage_objs_.begin(); |
| 140 it != storage_objs_.end(); ++it) { | 136 it != storage_objs_.end(); ++it) { |
| 141 result.insert(it->first); | 137 result.insert(it->first); |
| 142 } | 138 } |
| 143 | 139 |
| 144 // Leveldb databases are directories inside base_path_. | 140 // Leveldb databases are directories inside base_path_. |
| 145 file_util::FileEnumerator::FindInfo find_info; | 141 file_util::FileEnumerator::FindInfo find_info; |
| 146 file_util::FileEnumerator extension_dirs( | 142 file_util::FileEnumerator extension_dirs( |
| 147 base_path_, false, file_util::FileEnumerator::DIRECTORIES); | 143 base_path_, false, file_util::FileEnumerator::DIRECTORIES); |
| 148 while (!extension_dirs.Next().empty()) { | 144 while (!extension_dirs.Next().empty()) { |
| 149 extension_dirs.GetFindInfo(&find_info); | 145 extension_dirs.GetFindInfo(&find_info); |
| 150 FilePath extension_dir(file_util::FileEnumerator::GetFilename(find_info)); | 146 FilePath extension_dir(file_util::FileEnumerator::GetFilename(find_info)); |
| 151 DCHECK(!extension_dir.IsAbsolute()); | 147 DCHECK(!extension_dir.IsAbsolute()); |
| 152 // Extension IDs are created as std::strings so they *should* be ASCII. | 148 // Extension IDs are created as std::strings so they *should* be ASCII. |
| 153 std::string maybe_as_ascii(extension_dir.MaybeAsASCII()); | 149 std::string maybe_as_ascii(extension_dir.MaybeAsASCII()); |
| 154 if (!maybe_as_ascii.empty()) { | 150 if (!maybe_as_ascii.empty()) { |
| 155 result.insert(maybe_as_ascii); | 151 result.insert(maybe_as_ascii); |
| 156 } | 152 } |
| 157 } | 153 } |
| 158 | 154 |
| 159 return result; | 155 return result; |
| 160 } | 156 } |
| 161 | 157 |
| 162 SyncDataList ExtensionSettingsBackend::GetAllSyncData( | 158 SyncDataList ExtensionSettingsBackend::GetAllSyncData( |
| 163 syncable::ModelType type) const { | 159 syncable::ModelType type) const { |
| 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 165 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS); | 161 // Ignore the type, it's just for sanity checking; assume that whatever base |
| 162 // path we're constructed with is correct for the sync type. |
| 163 DCHECK(type == syncable::EXTENSION_SETTINGS || |
| 164 type == syncable::APP_SETTINGS); |
| 166 | 165 |
| 167 // For all extensions, get all their settings. | 166 // For all extensions, get all their settings. This has the effect |
| 168 // This has the effect of bringing in the entire state of extension settings | 167 // of bringing in the entire state of extension settings in memory; sad. |
| 169 // in memory; sad. | |
| 170 SyncDataList all_sync_data; | 168 SyncDataList all_sync_data; |
| 171 std::set<std::string> known_extension_ids(GetKnownExtensionIDs()); | 169 std::set<std::string> known_extension_ids(GetKnownExtensionIDs()); |
| 172 | 170 |
| 173 for (std::set<std::string>::const_iterator it = known_extension_ids.begin(); | 171 for (std::set<std::string>::const_iterator it = known_extension_ids.begin(); |
| 174 it != known_extension_ids.end(); ++it) { | 172 it != known_extension_ids.end(); ++it) { |
| 175 ExtensionSettingsStorage::Result maybe_settings = GetStorage(*it)->Get(); | 173 ExtensionSettingsStorage::Result maybe_settings = GetStorage(*it)->Get(); |
| 176 if (maybe_settings.HasError()) { | 174 if (maybe_settings.HasError()) { |
| 177 LOG(WARNING) << "Failed to get settings for " << *it << ": " << | 175 LOG(WARNING) << "Failed to get settings for " << *it << ": " << |
| 178 maybe_settings.GetError(); | 176 maybe_settings.GetError(); |
| 179 continue; | 177 continue; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 190 } | 188 } |
| 191 | 189 |
| 192 return all_sync_data; | 190 return all_sync_data; |
| 193 } | 191 } |
| 194 | 192 |
| 195 SyncError ExtensionSettingsBackend::MergeDataAndStartSyncing( | 193 SyncError ExtensionSettingsBackend::MergeDataAndStartSyncing( |
| 196 syncable::ModelType type, | 194 syncable::ModelType type, |
| 197 const SyncDataList& initial_sync_data, | 195 const SyncDataList& initial_sync_data, |
| 198 SyncChangeProcessor* sync_processor) { | 196 SyncChangeProcessor* sync_processor) { |
| 199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 200 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS); | 198 DCHECK(type == syncable::EXTENSION_SETTINGS || |
| 199 type == syncable::APP_SETTINGS); |
| 200 DCHECK_EQ(sync_type_, syncable::UNSPECIFIED); |
| 201 DCHECK(!sync_processor_); | 201 DCHECK(!sync_processor_); |
| 202 |
| 203 sync_type_ = type; |
| 202 sync_processor_ = sync_processor; | 204 sync_processor_ = sync_processor; |
| 203 | 205 |
| 204 // Group the initial sync data by extension id. | 206 // Group the initial sync data by extension id. |
| 205 std::map<std::string, linked_ptr<DictionaryValue> > grouped_sync_data; | 207 std::map<std::string, linked_ptr<DictionaryValue> > grouped_sync_data; |
| 206 for (SyncDataList::const_iterator it = initial_sync_data.begin(); | 208 for (SyncDataList::const_iterator it = initial_sync_data.begin(); |
| 207 it != initial_sync_data.end(); ++it) { | 209 it != initial_sync_data.end(); ++it) { |
| 208 ExtensionSettingSyncData data(*it); | 210 ExtensionSettingSyncData data(*it); |
| 209 linked_ptr<DictionaryValue> sync_data = | 211 linked_ptr<DictionaryValue> sync_data = |
| 210 grouped_sync_data[data.extension_id()]; | 212 grouped_sync_data[data.extension_id()]; |
| 211 if (!sync_data.get()) { | 213 if (!sync_data.get()) { |
| 212 sync_data = linked_ptr<DictionaryValue>(new DictionaryValue()); | 214 sync_data = linked_ptr<DictionaryValue>(new DictionaryValue()); |
| 213 grouped_sync_data[data.extension_id()] = sync_data; | 215 grouped_sync_data[data.extension_id()] = sync_data; |
| 214 } | 216 } |
| 215 DCHECK(!sync_data->HasKey(data.key())) << | 217 DCHECK(!sync_data->HasKey(data.key())) << |
| 216 "Duplicate settings for " << data.extension_id() << "/" << data.key(); | 218 "Duplicate settings for " << data.extension_id() << "/" << data.key(); |
| 217 sync_data->Set(data.key(), data.value().DeepCopy()); | 219 sync_data->Set(data.key(), data.value().DeepCopy()); |
| 218 } | 220 } |
| 219 | 221 |
| 220 // Start syncing all existing storage areas. Any storage areas created in | 222 // Start syncing all existing storage areas. Any storage areas created in |
| 221 // the future will start being synced as part of the creation process. | 223 // the future will start being synced as part of the creation process. |
| 222 for (StorageObjMap::iterator it = storage_objs_.begin(); | 224 for (StorageObjMap::iterator it = storage_objs_.begin(); |
| 223 it != storage_objs_.end(); ++it) { | 225 it != storage_objs_.end(); ++it) { |
| 224 std::map<std::string, linked_ptr<DictionaryValue> >::iterator | 226 std::map<std::string, linked_ptr<DictionaryValue> >::iterator |
| 225 maybe_sync_data = grouped_sync_data.find(it->first); | 227 maybe_sync_data = grouped_sync_data.find(it->first); |
| 226 if (maybe_sync_data != grouped_sync_data.end()) { | 228 if (maybe_sync_data != grouped_sync_data.end()) { |
| 227 // TODO(kalman): do something if StartSyncing fails. | 229 // TODO(kalman): do something if StartSyncing fails. |
| 228 ignore_result( | 230 ignore_result( |
| 229 it->second->StartSyncing(*maybe_sync_data->second, sync_processor)); | 231 it->second->StartSyncing( |
| 232 type, *maybe_sync_data->second, sync_processor)); |
| 230 grouped_sync_data.erase(it->first); | 233 grouped_sync_data.erase(it->first); |
| 231 } else { | 234 } else { |
| 232 DictionaryValue empty; | 235 DictionaryValue empty; |
| 233 // TODO(kalman): do something if StartSyncing fails. | 236 // TODO(kalman): do something if StartSyncing fails. |
| 234 ignore_result(it->second->StartSyncing(empty, sync_processor)); | 237 ignore_result(it->second->StartSyncing(type, empty, sync_processor)); |
| 235 } | 238 } |
| 236 } | 239 } |
| 237 | 240 |
| 238 // Eagerly create and init the rest of the storage areas that have sync data. | 241 // Eagerly create and init the rest of the storage areas that have sync data. |
| 239 // Under normal circumstances (i.e. not first-time sync) this will be all of | 242 // Under normal circumstances (i.e. not first-time sync) this will be all of |
| 240 // them. | 243 // them. |
| 241 for (std::map<std::string, linked_ptr<DictionaryValue> >::iterator it = | 244 for (std::map<std::string, linked_ptr<DictionaryValue> >::iterator it = |
| 242 grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) { | 245 grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) { |
| 243 GetOrCreateStorageWithSyncData(it->first, *it->second); | 246 GetOrCreateStorageWithSyncData(it->first, *it->second); |
| 244 } | 247 } |
| 245 | 248 |
| 246 return SyncError(); | 249 return SyncError(); |
| 247 } | 250 } |
| 248 | 251 |
| 249 SyncError ExtensionSettingsBackend::ProcessSyncChanges( | 252 SyncError ExtensionSettingsBackend::ProcessSyncChanges( |
| 250 const tracked_objects::Location& from_here, | 253 const tracked_objects::Location& from_here, |
| 251 const SyncChangeList& sync_changes) { | 254 const SyncChangeList& sync_changes) { |
| 252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 253 DCHECK(sync_processor_); | 256 DCHECK(sync_processor_); |
| 254 | 257 |
| 255 // Group changes by extension, to pass all changes in a single method call. | 258 // Group changes by extension, to pass all changes in a single method call. |
| 256 std::map<std::string, ExtensionSettingSyncDataList> grouped_sync_data; | 259 std::map<std::string, ExtensionSettingSyncDataList> grouped_sync_data; |
| 257 for (SyncChangeList::const_iterator it = sync_changes.begin(); | 260 for (SyncChangeList::const_iterator it = sync_changes.begin(); |
| 258 it != sync_changes.end(); ++it) { | 261 it != sync_changes.end(); ++it) { |
| 259 ExtensionSettingSyncData data(*it); | 262 ExtensionSettingSyncData data(*it); |
| 260 grouped_sync_data[data.extension_id()].push_back(data); | 263 grouped_sync_data[data.extension_id()].push_back(data); |
| 261 } | 264 } |
| 262 | 265 |
| 266 // Create any storage areas that don't exist yet but have sync data. |
| 263 DictionaryValue empty; | 267 DictionaryValue empty; |
| 264 for (std::map<std::string, ExtensionSettingSyncDataList>::iterator | 268 for (std::map<std::string, ExtensionSettingSyncDataList>::iterator |
| 265 it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) { | 269 it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) { |
| 266 // TODO(kalman): do something if ProcessSyncChanges fails. | 270 // TODO(kalman): do something if ProcessSyncChanges fails. |
| 267 ignore_result( | 271 ignore_result( |
| 268 GetOrCreateStorageWithSyncData(it->first, empty)-> | 272 GetOrCreateStorageWithSyncData(it->first, empty)-> |
| 269 ProcessSyncChanges(it->second)); | 273 ProcessSyncChanges(it->second)); |
| 270 } | 274 } |
| 271 | 275 |
| 272 return SyncError(); | 276 return SyncError(); |
| 273 } | 277 } |
| 274 | 278 |
| 275 void ExtensionSettingsBackend::StopSyncing(syncable::ModelType type) { | 279 void ExtensionSettingsBackend::StopSyncing(syncable::ModelType type) { |
| 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 281 DCHECK(type == syncable::EXTENSION_SETTINGS || |
| 282 type == syncable::APP_SETTINGS); |
| 283 DCHECK_EQ(type, sync_type_); |
| 277 DCHECK(sync_processor_); | 284 DCHECK(sync_processor_); |
| 285 |
| 286 sync_type_ = syncable::UNSPECIFIED; |
| 278 sync_processor_ = NULL; | 287 sync_processor_ = NULL; |
| 279 | 288 |
| 280 for (StorageObjMap::iterator it = storage_objs_.begin(); | 289 for (StorageObjMap::iterator it = storage_objs_.begin(); |
| 281 it != storage_objs_.end(); ++it) { | 290 it != storage_objs_.end(); ++it) { |
| 282 it->second->StopSyncing(); | 291 it->second->StopSyncing(); |
| 283 } | 292 } |
| 284 } | 293 } |
| OLD | NEW |