| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/api/declarative/rules_registry_with_cache.h" | 5 #include "chrome/browser/extensions/api/declarative/rules_registry_with_cache.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 } | 35 } |
| 36 | 36 |
| 37 std::vector<linked_ptr<extensions::RulesRegistry::Rule> > RulesFromValue( | 37 std::vector<linked_ptr<extensions::RulesRegistry::Rule> > RulesFromValue( |
| 38 const base::Value* value) { | 38 const base::Value* value) { |
| 39 std::vector<linked_ptr<extensions::RulesRegistry::Rule> > rules; | 39 std::vector<linked_ptr<extensions::RulesRegistry::Rule> > rules; |
| 40 | 40 |
| 41 const base::ListValue* list = NULL; | 41 const base::ListValue* list = NULL; |
| 42 if (!value || !value->GetAsList(&list)) | 42 if (!value || !value->GetAsList(&list)) |
| 43 return rules; | 43 return rules; |
| 44 | 44 |
| 45 rules.reserve(list->GetSize()); |
| 45 for (size_t i = 0; i < list->GetSize(); ++i) { | 46 for (size_t i = 0; i < list->GetSize(); ++i) { |
| 46 const base::DictionaryValue* dict = NULL; | 47 const base::DictionaryValue* dict = NULL; |
| 47 if (!list->GetDictionary(i, &dict)) | 48 if (!list->GetDictionary(i, &dict)) |
| 48 continue; | 49 continue; |
| 49 linked_ptr<extensions::RulesRegistry::Rule> rule( | 50 linked_ptr<extensions::RulesRegistry::Rule> rule( |
| 50 new extensions::RulesRegistry::Rule()); | 51 new extensions::RulesRegistry::Rule()); |
| 51 if (extensions::RulesRegistry::Rule::Populate(*dict, rule.get())) | 52 if (extensions::RulesRegistry::Rule::Populate(*dict, rule.get())) |
| 52 rules.push_back(rule); | 53 rules.push_back(rule); |
| 53 } | 54 } |
| 54 | 55 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 } | 105 } |
| 105 | 106 |
| 106 void RulesRegistryWithCache::AddReadyCallback(const base::Closure& callback) { | 107 void RulesRegistryWithCache::AddReadyCallback(const base::Closure& callback) { |
| 107 ready_callbacks_.push_back(callback); | 108 ready_callbacks_.push_back(callback); |
| 108 } | 109 } |
| 109 | 110 |
| 110 std::string RulesRegistryWithCache::AddRules( | 111 std::string RulesRegistryWithCache::AddRules( |
| 111 const std::string& extension_id, | 112 const std::string& extension_id, |
| 112 const std::vector<linked_ptr<Rule> >& rules) { | 113 const std::vector<linked_ptr<Rule> >& rules) { |
| 113 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 114 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
| 115 RulesDictionary& current_rules = rules_[extension_id]; |
| 114 | 116 |
| 115 // Verify that all rule IDs are new. | 117 // Verify that all rule IDs are new. |
| 116 for (std::vector<linked_ptr<Rule> >::const_iterator i = | 118 for (std::vector<linked_ptr<Rule> >::const_iterator i = |
| 117 rules.begin(); i != rules.end(); ++i) { | 119 rules.begin(); i != rules.end(); ++i) { |
| 118 const RuleId& rule_id = *((*i)->id); | 120 const RuleId& rule_id = *((*i)->id); |
| 119 RulesDictionaryKey key(extension_id, rule_id); | 121 if (current_rules.find(rule_id) != current_rules.end()) |
| 120 if (rules_.find(key) != rules_.end()) | |
| 121 return base::StringPrintf(kDuplicateRuleId, rule_id.c_str()); | 122 return base::StringPrintf(kDuplicateRuleId, rule_id.c_str()); |
| 122 } | 123 } |
| 123 | 124 |
| 124 std::string error = AddRulesImpl(extension_id, rules); | 125 std::string error = AddRulesImpl(extension_id, rules); |
| 125 | 126 |
| 126 if (!error.empty()) | 127 if (!error.empty()) |
| 127 return error; | 128 return error; |
| 128 | 129 |
| 129 // Commit all rules into |rules_| on success. | 130 // Commit all rules into |rules_| on success. |
| 130 for (std::vector<linked_ptr<Rule> >::const_iterator i = | 131 for (std::vector<linked_ptr<Rule> >::const_iterator i = |
| 131 rules.begin(); i != rules.end(); ++i) { | 132 rules.begin(); i != rules.end(); ++i) { |
| 132 const RuleId& rule_id = *((*i)->id); | 133 const RuleId& rule_id = *((*i)->id); |
| 133 RulesDictionaryKey key(extension_id, rule_id); | 134 current_rules[rule_id] = *i; |
| 134 rules_[key] = *i; | |
| 135 } | 135 } |
| 136 | 136 |
| 137 ProcessChangedRules(extension_id); | 137 ProcessChangedRules(extension_id); |
| 138 return kSuccess; | 138 return kSuccess; |
| 139 } | 139 } |
| 140 | 140 |
| 141 std::string RulesRegistryWithCache::RemoveRules( | 141 std::string RulesRegistryWithCache::RemoveRules( |
| 142 const std::string& extension_id, | 142 const std::string& extension_id, |
| 143 const std::vector<std::string>& rule_identifiers) { | 143 const std::vector<std::string>& rule_identifiers) { |
| 144 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 144 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
| 145 | 145 |
| 146 std::string error = RemoveRulesImpl(extension_id, rule_identifiers); | 146 std::string error = RemoveRulesImpl(extension_id, rule_identifiers); |
| 147 | 147 |
| 148 if (!error.empty()) | 148 if (!error.empty()) |
| 149 return error; | 149 return error; |
| 150 | 150 |
| 151 // Commit removal of rules from |rules_| on success. | 151 // Commit removal of rules from |rules_| on success. |
| 152 RulesDictionary& current_rules = rules_[extension_id]; |
| 152 for (std::vector<std::string>::const_iterator i = | 153 for (std::vector<std::string>::const_iterator i = |
| 153 rule_identifiers.begin(); i != rule_identifiers.end(); ++i) { | 154 rule_identifiers.begin(); i != rule_identifiers.end(); ++i) { |
| 154 RulesDictionaryKey lookup_key(extension_id, *i); | 155 current_rules.erase(*i); |
| 155 rules_.erase(lookup_key); | |
| 156 } | 156 } |
| 157 if (current_rules.empty()) |
| 158 rules_.erase(extension_id); |
| 157 | 159 |
| 158 ProcessChangedRules(extension_id); | 160 ProcessChangedRules(extension_id); |
| 159 return kSuccess; | 161 return kSuccess; |
| 160 } | 162 } |
| 161 | 163 |
| 162 std::string RulesRegistryWithCache::RemoveAllRules( | 164 std::string RulesRegistryWithCache::RemoveAllRules( |
| 163 const std::string& extension_id) { | 165 const std::string& extension_id) { |
| 164 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 166 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
| 165 | 167 |
| 166 std::string error = RemoveAllRulesImpl(extension_id); | 168 std::string error = RemoveAllRulesImpl(extension_id); |
| 167 | 169 |
| 168 if (!error.empty()) | 170 if (!error.empty()) |
| 169 return error; | 171 return error; |
| 170 | 172 |
| 171 // Commit removal of rules from |rules_| on success. | 173 // Commit removal of rules from |rules_| on success. |
| 172 for (RulesDictionary::const_iterator i = rules_.begin(); | 174 rules_.erase(extension_id); |
| 173 i != rules_.end();) { | |
| 174 const RulesDictionaryKey& key = i->first; | |
| 175 ++i; | |
| 176 if (key.first == extension_id) | |
| 177 rules_.erase(key); | |
| 178 } | |
| 179 | 175 |
| 180 ProcessChangedRules(extension_id); | 176 ProcessChangedRules(extension_id); |
| 181 return kSuccess; | 177 return kSuccess; |
| 182 } | 178 } |
| 183 | 179 |
| 184 std::string RulesRegistryWithCache::GetRules( | 180 std::string RulesRegistryWithCache::GetRules( |
| 185 const std::string& extension_id, | 181 const std::string& extension_id, |
| 186 const std::vector<std::string>& rule_identifiers, | 182 const std::vector<std::string>& rule_identifiers, |
| 187 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { | 183 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { |
| 188 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 184 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
| 189 | 185 |
| 186 RulesDictionary& current_rules = rules_[extension_id]; |
| 190 for (std::vector<std::string>::const_iterator i = rule_identifiers.begin(); | 187 for (std::vector<std::string>::const_iterator i = rule_identifiers.begin(); |
| 191 i != rule_identifiers.end(); ++i) { | 188 i != rule_identifiers.end(); ++i) { |
| 192 RulesDictionaryKey lookup_key(extension_id, *i); | 189 RulesDictionary::iterator entry = current_rules.find(*i); |
| 193 RulesDictionary::iterator entry = rules_.find(lookup_key); | 190 if (entry != current_rules.end()) |
| 194 if (entry != rules_.end()) | |
| 195 out->push_back(entry->second); | 191 out->push_back(entry->second); |
| 196 } | 192 } |
| 197 return kSuccess; | 193 return kSuccess; |
| 198 } | 194 } |
| 199 | 195 |
| 200 std::string RulesRegistryWithCache::GetAllRules( | 196 std::string RulesRegistryWithCache::GetAllRules( |
| 201 const std::string& extension_id, | 197 const std::string& extension_id, |
| 202 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { | 198 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { |
| 203 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 199 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
| 204 | 200 |
| 205 for (RulesDictionary::const_iterator i = rules_.begin(); | 201 RulesDictionary& current_rules = rules_[extension_id]; |
| 206 i != rules_.end(); ++i) { | 202 out->reserve(out->size() + current_rules.size()); |
| 207 const RulesDictionaryKey& key = i->first; | 203 for (RulesDictionary::const_iterator i = current_rules.begin(); |
| 208 if (key.first == extension_id) | 204 i != current_rules.end(); ++i) { |
| 209 out->push_back(i->second); | 205 out->push_back(i->second); |
| 210 } | 206 } |
| 211 return kSuccess; | 207 return kSuccess; |
| 212 } | 208 } |
| 213 | 209 |
| 214 void RulesRegistryWithCache::OnExtensionUnloaded( | 210 void RulesRegistryWithCache::OnExtensionUnloaded( |
| 215 const std::string& extension_id) { | 211 const std::string& extension_id) { |
| 216 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 212 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
| 217 std::string error = RemoveAllRules(extension_id); | 213 std::string error = RemoveAllRules(extension_id); |
| 218 if (!error.empty()) | 214 if (!error.empty()) |
| 219 LOG(ERROR) << error; | 215 LOG(ERROR) << error; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 243 scoped_ptr<base::Value> rules) { | 239 scoped_ptr<base::Value> rules) { |
| 244 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 240 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
| 245 | 241 |
| 246 AddRules(extension_id, RulesFromValue(rules.get())); | 242 AddRules(extension_id, RulesFromValue(rules.get())); |
| 247 } | 243 } |
| 248 | 244 |
| 249 void RulesRegistryWithCache::ProcessChangedRules( | 245 void RulesRegistryWithCache::ProcessChangedRules( |
| 250 const std::string& extension_id) { | 246 const std::string& extension_id) { |
| 251 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 247 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
| 252 | 248 |
| 253 std::vector<linked_ptr<RulesRegistry::Rule> > new_rules; | 249 scoped_ptr<RulesVector> new_rules(new RulesVector()); |
| 254 std::string error = GetAllRules(extension_id, &new_rules); | 250 std::string error = GetAllRules(extension_id, new_rules.get()); |
| 255 DCHECK_EQ(std::string(), error); | 251 DCHECK_EQ(std::string(), error); |
| 256 content::BrowserThread::PostTask( | 252 content::BrowserThread::PostTask( |
| 257 content::BrowserThread::UI, | 253 content::BrowserThread::UI, |
| 258 FROM_HERE, | 254 FROM_HERE, |
| 259 base::Bind(&RuleStorageOnUI::WriteToStorage, | 255 base::Bind(&RuleStorageOnUI::WriteToStorage, |
| 260 storage_on_ui_, | 256 storage_on_ui_, |
| 261 extension_id, | 257 extension_id, |
| 262 base::Passed(RulesToValue(new_rules)))); | 258 base::Passed(&new_rules))); |
| 263 } | 259 } |
| 264 | 260 |
| 265 // RulesRegistryWithCache::RuleStorageOnUI | 261 // RulesRegistryWithCache::RuleStorageOnUI |
| 266 | 262 |
| 267 RulesRegistryWithCache::RuleStorageOnUI::RuleStorageOnUI( | 263 RulesRegistryWithCache::RuleStorageOnUI::RuleStorageOnUI( |
| 268 Profile* profile, | 264 Profile* profile, |
| 269 const std::string& storage_key, | 265 const std::string& storage_key, |
| 270 content::BrowserThread::ID rules_registry_thread, | 266 content::BrowserThread::ID rules_registry_thread, |
| 271 base::WeakPtr<RulesRegistryWithCache> registry, | 267 base::WeakPtr<RulesRegistryWithCache> registry, |
| 272 bool log_storage_init_delay) | 268 bool log_storage_init_delay) |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 // can post tasks for the not-yet-initialized registry to run, we need to | 315 // can post tasks for the not-yet-initialized registry to run, we need to |
| 320 // postpone checking for being ready (=all rules loaded), on the registry's | 316 // postpone checking for being ready (=all rules loaded), on the registry's |
| 321 // thread. | 317 // thread. |
| 322 base::MessageLoop::current()->PostTask( | 318 base::MessageLoop::current()->PostTask( |
| 323 FROM_HERE, base::Bind(&RuleStorageOnUI::CheckIfReady, GetWeakPtr())); | 319 FROM_HERE, base::Bind(&RuleStorageOnUI::CheckIfReady, GetWeakPtr())); |
| 324 } | 320 } |
| 325 } | 321 } |
| 326 | 322 |
| 327 void RulesRegistryWithCache::RuleStorageOnUI::WriteToStorage( | 323 void RulesRegistryWithCache::RuleStorageOnUI::WriteToStorage( |
| 328 const std::string& extension_id, | 324 const std::string& extension_id, |
| 329 scoped_ptr<base::Value> value) { | 325 scoped_ptr<RulesVector> new_rules) { |
| 330 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 326 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 331 if (!profile_) | 327 if (!profile_) |
| 332 return; | 328 return; |
| 333 | 329 |
| 334 StateStore* store = ExtensionSystem::Get(profile_)->rules_store(); | 330 StateStore* store = ExtensionSystem::Get(profile_)->rules_store(); |
| 335 if (store) | 331 if (store) { |
| 336 store->SetExtensionValue(extension_id, storage_key_, value.Pass()); | 332 store->SetExtensionValue( |
| 333 extension_id, storage_key_, RulesToValue(*new_rules)); |
| 334 } |
| 337 } | 335 } |
| 338 | 336 |
| 339 void RulesRegistryWithCache::RuleStorageOnUI::Observe( | 337 void RulesRegistryWithCache::RuleStorageOnUI::Observe( |
| 340 int type, | 338 int type, |
| 341 const content::NotificationSource& source, | 339 const content::NotificationSource& source, |
| 342 const content::NotificationDetails& details) { | 340 const content::NotificationDetails& details) { |
| 343 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 341 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 344 if (type == chrome::NOTIFICATION_EXTENSION_LOADED) { | 342 if (type == chrome::NOTIFICATION_EXTENSION_LOADED) { |
| 345 const extensions::Extension* extension = | 343 const extensions::Extension* extension = |
| 346 content::Details<const extensions::Extension>(details).ptr(); | 344 content::Details<const extensions::Extension>(details).ptr(); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 407 registry_, | 405 registry_, |
| 408 extension_id, | 406 extension_id, |
| 409 base::Passed(&value))); | 407 base::Passed(&value))); |
| 410 | 408 |
| 411 waiting_for_extensions_.erase(extension_id); | 409 waiting_for_extensions_.erase(extension_id); |
| 412 | 410 |
| 413 CheckIfReady(); | 411 CheckIfReady(); |
| 414 } | 412 } |
| 415 | 413 |
| 416 } // namespace extensions | 414 } // namespace extensions |
| OLD | NEW |