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/declarative/rules_registry.h" 6 7 #include <utility> 8 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/metrics/histogram.h" 13 #include "base/stl_util.h" 14 #include "base/strings/stringprintf.h" 15 #include "base/time/time.h" 16 #include "base/values.h" 17 #include "chrome/browser/chrome_notification_types.h" 18 #include "chrome/browser/extensions/api/declarative/rules_cache_delegate.h" 19 #include "chrome/browser/extensions/extension_service.h" 20 #include "chrome/browser/extensions/extension_util.h" 21 #include "chrome/browser/extensions/state_store.h" 22 #include "chrome/browser/profiles/profile.h" 23 #include "content/public/browser/browser_thread.h" 24 #include "content/public/browser/notification_details.h" 25 #include "content/public/browser/notification_source.h" 26 #include "extensions/browser/extension_prefs.h" 27 #include "extensions/browser/extension_system.h" 28 #include "extensions/common/extension.h" 29 30 namespace { 31 32 const char kSuccess[] = ""; 33 const char kDuplicateRuleId[] = "Duplicate rule ID: %s"; 34 35 scoped_ptr<base::Value> RulesToValue( 36 const std::vector<linked_ptr<extensions::RulesRegistry::Rule> >& rules) { 37 scoped_ptr<base::ListValue> list(new base::ListValue()); 38 for (size_t i = 0; i < rules.size(); ++i) 39 list->Append(rules[i]->ToValue().release()); 40 return list.PassAs<base::Value>(); 41 } 42 43 std::vector<linked_ptr<extensions::RulesRegistry::Rule> > RulesFromValue( 44 const base::Value* value) { 45 std::vector<linked_ptr<extensions::RulesRegistry::Rule> > rules; 46 47 const base::ListValue* list = NULL; 48 if (!value || !value->GetAsList(&list)) 49 return rules; 50 51 rules.reserve(list->GetSize()); 52 for (size_t i = 0; i < list->GetSize(); ++i) { 53 const base::DictionaryValue* dict = NULL; 54 if (!list->GetDictionary(i, &dict)) 55 continue; 56 linked_ptr<extensions::RulesRegistry::Rule> rule( 57 new extensions::RulesRegistry::Rule()); 58 if (extensions::RulesRegistry::Rule::Populate(*dict, rule.get())) 59 rules.push_back(rule); 60 } 61 62 return rules; 63 } 64 65 std::string ToId(int identifier) { 66 return base::StringPrintf("_%d_", identifier); 67 } 68 69 } // namespace 70 71 72 namespace extensions { 73 74 // RulesRegistry 75 76 RulesRegistry::RulesRegistry(Profile* profile, 77 const std::string& event_name, 78 content::BrowserThread::ID owner_thread, 79 RulesCacheDelegate* cache_delegate, 80 const WebViewKey& webview_key) 81 : profile_(profile), 82 owner_thread_(owner_thread), 83 event_name_(event_name), 84 webview_key_(webview_key), 85 ready_(/*signaled=*/!cache_delegate), // Immediately ready if no cache 86 // delegate to wait for. 87 weak_ptr_factory_(profile ? this : NULL), 88 last_generated_rule_identifier_id_(0) { 89 if (cache_delegate) { 90 cache_delegate_ = cache_delegate->GetWeakPtr(); 91 cache_delegate->Init(this); 92 } 93 } 94 95 std::string RulesRegistry::AddRulesNoFill( 96 const std::string& extension_id, 97 const std::vector<linked_ptr<Rule> >& rules) { 98 DCHECK_CURRENTLY_ON(owner_thread()); 99 100 // Verify that all rule IDs are new. 101 for (std::vector<linked_ptr<Rule> >::const_iterator i = 102 rules.begin(); i != rules.end(); ++i) { 103 const RuleId& rule_id = *((*i)->id); 104 // Every rule should have a priority assigned. 105 DCHECK((*i)->priority); 106 RulesDictionaryKey key(extension_id, rule_id); 107 if (rules_.find(key) != rules_.end()) 108 return base::StringPrintf(kDuplicateRuleId, rule_id.c_str()); 109 } 110 111 std::string error = AddRulesImpl(extension_id, rules); 112 113 if (!error.empty()) 114 return error; 115 116 // Commit all rules into |rules_| on success. 117 for (std::vector<linked_ptr<Rule> >::const_iterator i = 118 rules.begin(); i != rules.end(); ++i) { 119 const RuleId& rule_id = *((*i)->id); 120 RulesDictionaryKey key(extension_id, rule_id); 121 rules_[key] = *i; 122 } 123 124 MaybeProcessChangedRules(extension_id); 125 return kSuccess; 126 } 127 128 std::string RulesRegistry::AddRules( 129 const std::string& extension_id, 130 const std::vector<linked_ptr<Rule> >& rules) { 131 DCHECK_CURRENTLY_ON(owner_thread()); 132 133 std::string error = CheckAndFillInOptionalRules(extension_id, rules); 134 if (!error.empty()) 135 return error; 136 FillInOptionalPriorities(rules); 137 138 return AddRulesNoFill(extension_id, rules); 139 } 140 141 std::string RulesRegistry::RemoveRules( 142 const std::string& extension_id, 143 const std::vector<std::string>& rule_identifiers) { 144 DCHECK_CURRENTLY_ON(owner_thread()); 145 146 std::string error = RemoveRulesImpl(extension_id, rule_identifiers); 147 148 if (!error.empty()) 149 return error; 150 151 for (std::vector<std::string>::const_iterator i = rule_identifiers.begin(); 152 i != rule_identifiers.end(); 153 ++i) { 154 RulesDictionaryKey lookup_key(extension_id, *i); 155 rules_.erase(lookup_key); 156 } 157 158 MaybeProcessChangedRules(extension_id); 159 RemoveUsedRuleIdentifiers(extension_id, rule_identifiers); 160 return kSuccess; 161 } 162 163 std::string RulesRegistry::RemoveAllRules(const std::string& extension_id) { 164 std::string result = RulesRegistry::RemoveAllRulesNoStoreUpdate(extension_id); 165 MaybeProcessChangedRules(extension_id); // Now update the prefs and store. 166 return result; 167 } 168 169 std::string RulesRegistry::RemoveAllRulesNoStoreUpdate( 170 const std::string& extension_id) { 171 DCHECK_CURRENTLY_ON(owner_thread()); 172 173 std::string error = RemoveAllRulesImpl(extension_id); 174 175 if (!error.empty()) 176 return error; 177 178 for (RulesDictionary::const_iterator i = rules_.begin(); 179 i != rules_.end();) { 180 const RulesDictionaryKey& key = i->first; 181 ++i; 182 if (key.first == extension_id) 183 rules_.erase(key); 184 } 185 186 RemoveAllUsedRuleIdentifiers(extension_id); 187 return kSuccess; 188 } 189 190 void RulesRegistry::GetRules(const std::string& extension_id, 191 const std::vector<std::string>& rule_identifiers, 192 std::vector<linked_ptr<Rule> >* out) { 193 DCHECK_CURRENTLY_ON(owner_thread()); 194 195 for (std::vector<std::string>::const_iterator i = rule_identifiers.begin(); 196 i != rule_identifiers.end(); ++i) { 197 RulesDictionaryKey lookup_key(extension_id, *i); 198 RulesDictionary::iterator entry = rules_.find(lookup_key); 199 if (entry != rules_.end()) 200 out->push_back(entry->second); 201 } 202 } 203 204 void RulesRegistry::GetAllRules(const std::string& extension_id, 205 std::vector<linked_ptr<Rule> >* out) { 206 DCHECK_CURRENTLY_ON(owner_thread()); 207 208 for (RulesDictionary::const_iterator i = rules_.begin(); 209 i != rules_.end(); ++i) { 210 const RulesDictionaryKey& key = i->first; 211 if (key.first == extension_id) 212 out->push_back(i->second); 213 } 214 } 215 216 void RulesRegistry::OnExtensionUnloaded(const std::string& extension_id) { 217 DCHECK_CURRENTLY_ON(owner_thread()); 218 std::string error = RemoveAllRulesImpl(extension_id); 219 if (!error.empty()) 220 LOG(ERROR) << error; 221 } 222 223 void RulesRegistry::OnExtensionUninstalled(const std::string& extension_id) { 224 DCHECK_CURRENTLY_ON(owner_thread()); 225 std::string error = RemoveAllRulesNoStoreUpdate(extension_id); 226 if (!error.empty()) 227 LOG(ERROR) << error; 228 } 229 230 void RulesRegistry::OnExtensionLoaded(const std::string& extension_id) { 231 DCHECK_CURRENTLY_ON(owner_thread()); 232 std::vector<linked_ptr<Rule> > rules; 233 GetAllRules(extension_id, &rules); 234 std::string error = AddRulesImpl(extension_id, rules); 235 if (!error.empty()) 236 LOG(ERROR) << error; 237 } 238 239 size_t RulesRegistry::GetNumberOfUsedRuleIdentifiersForTesting() const { 240 size_t entry_count = 0u; 241 for (RuleIdentifiersMap::const_iterator extension = 242 used_rule_identifiers_.begin(); 243 extension != used_rule_identifiers_.end(); 244 ++extension) { 245 // Each extension is counted as 1 just for being there. Otherwise we miss 246 // keys with empty values. 247 entry_count += 1u + extension->second.size(); 248 } 249 return entry_count; 250 } 251 252 void RulesRegistry::DeserializeAndAddRules( 253 const std::string& extension_id, 254 scoped_ptr<base::Value> rules) { 255 DCHECK_CURRENTLY_ON(owner_thread()); 256 257 AddRulesNoFill(extension_id, RulesFromValue(rules.get())); 258 } 259 260 RulesRegistry::~RulesRegistry() { 261 } 262 263 void RulesRegistry::MarkReady(base::Time storage_init_time) { 264 DCHECK_CURRENTLY_ON(owner_thread()); 265 266 if (!storage_init_time.is_null()) { 267 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeRulesStorageInitialization", 268 base::Time::Now() - storage_init_time); 269 } 270 271 ready_.Signal(); 272 } 273 274 void RulesRegistry::ProcessChangedRules(const std::string& extension_id) { 275 DCHECK_CURRENTLY_ON(owner_thread()); 276 277 DCHECK(ContainsKey(process_changed_rules_requested_, extension_id)); 278 process_changed_rules_requested_[extension_id] = NOT_SCHEDULED_FOR_PROCESSING; 279 280 std::vector<linked_ptr<Rule> > new_rules; 281 GetAllRules(extension_id, &new_rules); 282 content::BrowserThread::PostTask( 283 content::BrowserThread::UI, 284 FROM_HERE, 285 base::Bind(&RulesCacheDelegate::WriteToStorage, 286 cache_delegate_, 287 extension_id, 288 base::Passed(RulesToValue(new_rules)))); 289 } 290 291 void RulesRegistry::MaybeProcessChangedRules(const std::string& extension_id) { 292 // Read and initialize |process_changed_rules_requested_[extension_id]| if 293 // necessary. (Note that the insertion below will not overwrite 294 // |process_changed_rules_requested_[extension_id]| if that already exists. 295 std::pair<ProcessStateMap::iterator, bool> insertion = 296 process_changed_rules_requested_.insert(std::make_pair( 297 extension_id, 298 profile_ ? NOT_SCHEDULED_FOR_PROCESSING : NEVER_PROCESS)); 299 if (insertion.first->second != NOT_SCHEDULED_FOR_PROCESSING) 300 return; 301 302 process_changed_rules_requested_[extension_id] = SCHEDULED_FOR_PROCESSING; 303 ready_.Post(FROM_HERE, 304 base::Bind(&RulesRegistry::ProcessChangedRules, 305 weak_ptr_factory_.GetWeakPtr(), 306 extension_id)); 307 } 308 309 bool RulesRegistry::IsUniqueId(const std::string& extension_id, 310 const std::string& rule_id) const { 311 RuleIdentifiersMap::const_iterator identifiers = 312 used_rule_identifiers_.find(extension_id); 313 if (identifiers == used_rule_identifiers_.end()) 314 return true; 315 return identifiers->second.find(rule_id) == identifiers->second.end(); 316 } 317 318 std::string RulesRegistry::GenerateUniqueId(const std::string& extension_id) { 319 while (!IsUniqueId(extension_id, ToId(last_generated_rule_identifier_id_))) 320 ++last_generated_rule_identifier_id_; 321 return ToId(last_generated_rule_identifier_id_); 322 } 323 324 std::string RulesRegistry::CheckAndFillInOptionalRules( 325 const std::string& extension_id, 326 const std::vector<linked_ptr<Rule> >& rules) { 327 // IDs we have inserted, in case we need to rollback this operation. 328 std::vector<std::string> rollback_log; 329 330 // First we insert all rules with existing identifier, so that generated 331 // identifiers cannot collide with identifiers passed by the caller. 332 for (std::vector<linked_ptr<Rule> >::const_iterator i = rules.begin(); 333 i != rules.end(); 334 ++i) { 335 Rule* rule = i->get(); 336 if (rule->id.get()) { 337 std::string id = *(rule->id); 338 if (!IsUniqueId(extension_id, id)) { 339 RemoveUsedRuleIdentifiers(extension_id, rollback_log); 340 return "Id " + id + " was used multiple times."; 341 } 342 used_rule_identifiers_[extension_id].insert(id); 343 } 344 } 345 // Now we generate IDs in case they were not specified in the rules. This 346 // cannot fail so we do not need to keep track of a rollback log. 347 for (std::vector<linked_ptr<Rule> >::const_iterator i = rules.begin(); 348 i != rules.end(); 349 ++i) { 350 Rule* rule = i->get(); 351 if (!rule->id.get()) { 352 rule->id.reset(new std::string(GenerateUniqueId(extension_id))); 353 used_rule_identifiers_[extension_id].insert(*(rule->id)); 354 } 355 } 356 return std::string(); 357 } 358 359 void RulesRegistry::FillInOptionalPriorities( 360 const std::vector<linked_ptr<Rule> >& rules) { 361 std::vector<linked_ptr<Rule> >::const_iterator i; 362 for (i = rules.begin(); i != rules.end(); ++i) { 363 if (!(*i)->priority.get()) 364 (*i)->priority.reset(new int(DEFAULT_PRIORITY)); 365 } 366 } 367 368 void RulesRegistry::RemoveUsedRuleIdentifiers( 369 const std::string& extension_id, 370 const std::vector<std::string>& identifiers) { 371 std::vector<std::string>::const_iterator i; 372 for (i = identifiers.begin(); i != identifiers.end(); ++i) 373 used_rule_identifiers_[extension_id].erase(*i); 374 } 375 376 void RulesRegistry::RemoveAllUsedRuleIdentifiers( 377 const std::string& extension_id) { 378 used_rule_identifiers_.erase(extension_id); 379 } 380 381 } // namespace extensions 382