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.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/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
13 #include "base/values.h" | 13 #include "base/values.h" |
14 #include "chrome/browser/chrome_notification_types.h" | 14 #include "chrome/browser/chrome_notification_types.h" |
15 #include "chrome/browser/extensions/api/declarative/rules_cache_delegate.h" | |
15 #include "chrome/browser/extensions/extension_info_map.h" | 16 #include "chrome/browser/extensions/extension_info_map.h" |
16 #include "chrome/browser/extensions/extension_prefs.h" | 17 #include "chrome/browser/extensions/extension_prefs.h" |
17 #include "chrome/browser/extensions/extension_service.h" | 18 #include "chrome/browser/extensions/extension_service.h" |
18 #include "chrome/browser/extensions/extension_system.h" | 19 #include "chrome/browser/extensions/extension_system.h" |
19 #include "chrome/browser/extensions/extension_util.h" | 20 #include "chrome/browser/extensions/extension_util.h" |
20 #include "chrome/browser/extensions/state_store.h" | 21 #include "chrome/browser/extensions/state_store.h" |
21 #include "chrome/browser/profiles/profile.h" | 22 #include "chrome/browser/profiles/profile.h" |
22 #include "chrome/common/extensions/extension.h" | 23 #include "chrome/common/extensions/extension.h" |
23 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
24 #include "content/public/browser/notification_details.h" | 25 #include "content/public/browser/notification_details.h" |
(...skipping 27 matching lines...) Expand all Loading... | |
52 continue; | 53 continue; |
53 linked_ptr<extensions::RulesRegistry::Rule> rule( | 54 linked_ptr<extensions::RulesRegistry::Rule> rule( |
54 new extensions::RulesRegistry::Rule()); | 55 new extensions::RulesRegistry::Rule()); |
55 if (extensions::RulesRegistry::Rule::Populate(*dict, rule.get())) | 56 if (extensions::RulesRegistry::Rule::Populate(*dict, rule.get())) |
56 rules.push_back(rule); | 57 rules.push_back(rule); |
57 } | 58 } |
58 | 59 |
59 return rules; | 60 return rules; |
60 } | 61 } |
61 | 62 |
62 // Returns the key to use for storing declarative rules in the state store. | 63 std::string ToId(int identifier) { |
63 std::string GetDeclarativeRuleStorageKey(const std::string& event_name, | 64 return base::StringPrintf("_%d_", identifier); |
64 bool incognito) { | |
65 if (incognito) | |
66 return "declarative_rules.incognito." + event_name; | |
67 else | |
68 return "declarative_rules." + event_name; | |
69 } | 65 } |
70 | 66 |
71 } // namespace | 67 } // namespace |
72 | 68 |
73 | 69 |
74 namespace extensions { | 70 namespace extensions { |
75 | 71 |
76 // RulesRegistryWithCache | 72 // RulesRegistry |
77 | 73 |
78 RulesRegistryWithCache::RulesRegistryWithCache( | 74 RulesRegistry::RulesRegistry( |
79 Profile* profile, | 75 Profile* profile, |
80 const std::string& event_name, | 76 const std::string& event_name, |
81 content::BrowserThread::ID owner_thread, | 77 content::BrowserThread::ID owner_thread, |
82 bool log_storage_init_delay, | 78 bool log_storage_init_delay, |
83 scoped_ptr<RuleStorageOnUI>* ui_part) | 79 scoped_ptr<RulesCacheDelegate>* ui_part) |
84 : RulesRegistry(owner_thread, event_name), | 80 : owner_thread_(owner_thread), |
81 event_name_(event_name), | |
85 weak_ptr_factory_(profile ? this : NULL), | 82 weak_ptr_factory_(profile ? this : NULL), |
86 storage_on_ui_( | 83 cache_delegate_( |
87 (profile ? (new RuleStorageOnUI(profile, | 84 (profile ? (new RulesCacheDelegate(profile, |
88 event_name, | 85 event_name, |
89 owner_thread, | 86 owner_thread, |
90 weak_ptr_factory_.GetWeakPtr(), | 87 weak_ptr_factory_.GetWeakPtr(), |
91 log_storage_init_delay))->GetWeakPtr() | 88 log_storage_init_delay))->GetWeakPtr() |
92 : base::WeakPtr<RuleStorageOnUI>())), | 89 : base::WeakPtr<RulesCacheDelegate>())), |
93 process_changed_rules_requested_(profile ? NOT_SCHEDULED_FOR_PROCESSING | 90 process_changed_rules_requested_(profile ? NOT_SCHEDULED_FOR_PROCESSING |
94 : NEVER_PROCESS) { | 91 : NEVER_PROCESS), |
92 last_generated_rule_identifier_id_(0) { | |
95 if (!profile) { | 93 if (!profile) { |
96 CHECK(!ui_part); | 94 CHECK(!ui_part); |
97 return; | 95 return; |
98 } | 96 } |
99 | 97 |
100 ui_part->reset(storage_on_ui_.get()); | 98 ui_part->reset(cache_delegate_.get()); |
101 | 99 |
102 storage_on_ui_->Init(); | 100 cache_delegate_->Init(); |
103 } | 101 } |
104 | 102 |
105 std::string RulesRegistryWithCache::AddRules( | 103 std::string RulesRegistry::AddRules( |
106 const std::string& extension_id, | 104 const std::string& extension_id, |
107 const std::vector<linked_ptr<Rule> >& rules) { | 105 const std::vector<linked_ptr<Rule> >& rules) { |
108 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 106 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
109 | 107 |
108 std::string error = CheckAndFillInOptionalRules(extension_id, rules); | |
Jeffrey Yasskin
2013/10/30 22:30:48
This is probably fine, but note that, now that Ini
Fady Samuel
2013/10/31 14:02:24
OK. This is one time operation on browser startup
vabr (Chromium)
2013/10/31 16:35:05
Actually, the start-up time is a critical point. W
| |
109 if (!error.empty()) | |
110 return error; | |
111 FillInOptionalPriorities(rules); | |
112 | |
110 // Verify that all rule IDs are new. | 113 // Verify that all rule IDs are new. |
111 for (std::vector<linked_ptr<Rule> >::const_iterator i = | 114 for (std::vector<linked_ptr<Rule> >::const_iterator i = |
112 rules.begin(); i != rules.end(); ++i) { | 115 rules.begin(); i != rules.end(); ++i) { |
113 const RuleId& rule_id = *((*i)->id); | 116 const RuleId& rule_id = *((*i)->id); |
114 RulesDictionaryKey key(extension_id, rule_id); | 117 RulesDictionaryKey key(extension_id, rule_id); |
115 if (rules_.find(key) != rules_.end()) | 118 if (rules_.find(key) != rules_.end()) |
116 return base::StringPrintf(kDuplicateRuleId, rule_id.c_str()); | 119 return base::StringPrintf(kDuplicateRuleId, rule_id.c_str()); |
117 } | 120 } |
118 | 121 |
119 std::string error = AddRulesImpl(extension_id, rules); | 122 error = AddRulesImpl(extension_id, rules); |
120 | 123 |
121 if (!error.empty()) | 124 if (!error.empty()) |
122 return error; | 125 return error; |
123 | 126 |
124 // Commit all rules into |rules_| on success. | 127 // Commit all rules into |rules_| on success. |
125 for (std::vector<linked_ptr<Rule> >::const_iterator i = | 128 for (std::vector<linked_ptr<Rule> >::const_iterator i = |
126 rules.begin(); i != rules.end(); ++i) { | 129 rules.begin(); i != rules.end(); ++i) { |
127 const RuleId& rule_id = *((*i)->id); | 130 const RuleId& rule_id = *((*i)->id); |
128 RulesDictionaryKey key(extension_id, rule_id); | 131 RulesDictionaryKey key(extension_id, rule_id); |
129 rules_[key] = *i; | 132 rules_[key] = *i; |
130 } | 133 } |
131 | 134 |
132 MaybeProcessChangedRules(extension_id); | 135 MaybeProcessChangedRules(extension_id); |
133 return kSuccess; | 136 return kSuccess; |
134 } | 137 } |
135 | 138 |
136 std::string RulesRegistryWithCache::RemoveRules( | 139 std::string RulesRegistry::RemoveRules( |
137 const std::string& extension_id, | 140 const std::string& extension_id, |
138 const std::vector<std::string>& rule_identifiers) { | 141 const std::vector<std::string>& rule_identifiers) { |
139 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 142 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
140 | 143 |
141 std::string error = RemoveRulesImpl(extension_id, rule_identifiers); | 144 std::string error = RemoveRulesImpl(extension_id, rule_identifiers); |
142 | 145 |
143 if (!error.empty()) | 146 if (!error.empty()) |
144 return error; | 147 return error; |
145 | 148 |
146 // Commit removal of rules from |rules_| on success. | 149 // Commit removal of rules from |rules_| on success. |
147 for (std::vector<std::string>::const_iterator i = | 150 for (std::vector<std::string>::const_iterator i = |
148 rule_identifiers.begin(); i != rule_identifiers.end(); ++i) { | 151 rule_identifiers.begin(); i != rule_identifiers.end(); ++i) { |
149 RulesDictionaryKey lookup_key(extension_id, *i); | 152 RulesDictionaryKey lookup_key(extension_id, *i); |
150 rules_.erase(lookup_key); | 153 rules_.erase(lookup_key); |
151 } | 154 } |
152 | 155 |
153 MaybeProcessChangedRules(extension_id); | 156 MaybeProcessChangedRules(extension_id); |
157 RemoveUsedRuleIdentifiers(extension_id, rule_identifiers); | |
154 return kSuccess; | 158 return kSuccess; |
155 } | 159 } |
156 | 160 |
157 std::string RulesRegistryWithCache::RemoveAllRules( | 161 std::string RulesRegistry::RemoveAllRules(const std::string& extension_id) { |
158 const std::string& extension_id) { | |
159 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 162 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
160 | 163 |
161 std::string error = RemoveAllRulesImpl(extension_id); | 164 std::string error = RemoveAllRulesImpl(extension_id); |
162 | 165 |
163 if (!error.empty()) | 166 if (!error.empty()) |
164 return error; | 167 return error; |
165 | 168 |
166 // Commit removal of rules from |rules_| on success. | 169 // Commit removal of rules from |rules_| on success. |
167 for (RulesDictionary::const_iterator i = rules_.begin(); | 170 for (RulesDictionary::const_iterator i = rules_.begin(); |
168 i != rules_.end();) { | 171 i != rules_.end();) { |
169 const RulesDictionaryKey& key = i->first; | 172 const RulesDictionaryKey& key = i->first; |
170 ++i; | 173 ++i; |
171 if (key.first == extension_id) | 174 if (key.first == extension_id) |
172 rules_.erase(key); | 175 rules_.erase(key); |
173 } | 176 } |
174 | 177 |
175 MaybeProcessChangedRules(extension_id); | 178 MaybeProcessChangedRules(extension_id); |
179 RemoveAllUsedRuleIdentifiers(extension_id); | |
176 return kSuccess; | 180 return kSuccess; |
177 } | 181 } |
178 | 182 |
179 std::string RulesRegistryWithCache::GetRules( | 183 std::string RulesRegistry::GetRules( |
180 const std::string& extension_id, | 184 const std::string& extension_id, |
181 const std::vector<std::string>& rule_identifiers, | 185 const std::vector<std::string>& rule_identifiers, |
182 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { | 186 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { |
183 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 187 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
184 | 188 |
185 for (std::vector<std::string>::const_iterator i = rule_identifiers.begin(); | 189 for (std::vector<std::string>::const_iterator i = rule_identifiers.begin(); |
186 i != rule_identifiers.end(); ++i) { | 190 i != rule_identifiers.end(); ++i) { |
187 RulesDictionaryKey lookup_key(extension_id, *i); | 191 RulesDictionaryKey lookup_key(extension_id, *i); |
188 RulesDictionary::iterator entry = rules_.find(lookup_key); | 192 RulesDictionary::iterator entry = rules_.find(lookup_key); |
189 if (entry != rules_.end()) | 193 if (entry != rules_.end()) |
190 out->push_back(entry->second); | 194 out->push_back(entry->second); |
191 } | 195 } |
192 return kSuccess; | 196 return kSuccess; |
193 } | 197 } |
194 | 198 |
195 std::string RulesRegistryWithCache::GetAllRules( | 199 std::string RulesRegistry::GetAllRules( |
196 const std::string& extension_id, | 200 const std::string& extension_id, |
197 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { | 201 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { |
198 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 202 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
199 | 203 |
200 for (RulesDictionary::const_iterator i = rules_.begin(); | 204 for (RulesDictionary::const_iterator i = rules_.begin(); |
201 i != rules_.end(); ++i) { | 205 i != rules_.end(); ++i) { |
202 const RulesDictionaryKey& key = i->first; | 206 const RulesDictionaryKey& key = i->first; |
203 if (key.first == extension_id) | 207 if (key.first == extension_id) |
204 out->push_back(i->second); | 208 out->push_back(i->second); |
205 } | 209 } |
206 return kSuccess; | 210 return kSuccess; |
207 } | 211 } |
208 | 212 |
209 void RulesRegistryWithCache::OnExtensionUnloaded( | 213 void RulesRegistry::OnExtensionUnloaded(const std::string& extension_id) { |
210 const std::string& extension_id) { | |
211 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 214 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
212 std::string error = RemoveAllRules(extension_id); | 215 std::string error = RemoveAllRules(extension_id); |
213 if (!error.empty()) | 216 if (!error.empty()) |
214 LOG(ERROR) << error; | 217 LOG(ERROR) << error; |
218 used_rule_identifiers_.erase(extension_id); | |
215 } | 219 } |
216 | 220 |
217 RulesRegistryWithCache::~RulesRegistryWithCache() { | 221 size_t RulesRegistry::GetNumberOfUsedRuleIdentifiersForTesting() const { |
222 size_t entry_count = 0u; | |
223 for (RuleIdentifiersMap::const_iterator extension = | |
224 used_rule_identifiers_.begin(); | |
225 extension != used_rule_identifiers_.end(); | |
226 ++extension) { | |
227 // Each extension is counted as 1 just for being there. Otherwise we miss | |
228 // keys with empty values. | |
229 entry_count += 1u + extension->second.size(); | |
230 } | |
231 return entry_count; | |
218 } | 232 } |
219 | 233 |
220 void RulesRegistryWithCache::MarkReady(base::Time storage_init_time) { | 234 RulesRegistry::~RulesRegistry() { |
235 } | |
236 | |
237 void RulesRegistry::MarkReady(base::Time storage_init_time) { | |
221 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 238 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
222 | 239 |
223 if (!storage_init_time.is_null()) { | 240 if (!storage_init_time.is_null()) { |
224 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeRulesStorageInitialization", | 241 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeRulesStorageInitialization", |
225 base::Time::Now() - storage_init_time); | 242 base::Time::Now() - storage_init_time); |
226 } | 243 } |
227 | 244 |
228 ready_.Signal(); | 245 ready_.Signal(); |
229 } | 246 } |
230 | 247 |
231 void RulesRegistryWithCache::DeserializeAndAddRules( | 248 void RulesRegistry::DeserializeAndAddRules( |
232 const std::string& extension_id, | 249 const std::string& extension_id, |
233 scoped_ptr<base::Value> rules) { | 250 scoped_ptr<base::Value> rules) { |
234 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 251 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
235 | 252 |
236 AddRules(extension_id, RulesFromValue(rules.get())); | 253 AddRules(extension_id, RulesFromValue(rules.get())); |
237 } | 254 } |
238 | 255 |
239 void RulesRegistryWithCache::ProcessChangedRules( | 256 void RulesRegistry::ProcessChangedRules(const std::string& extension_id) { |
240 const std::string& extension_id) { | |
241 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); | 257 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread())); |
242 | 258 |
243 process_changed_rules_requested_ = NOT_SCHEDULED_FOR_PROCESSING; | 259 process_changed_rules_requested_ = NOT_SCHEDULED_FOR_PROCESSING; |
244 | 260 |
245 std::vector<linked_ptr<RulesRegistry::Rule> > new_rules; | 261 std::vector<linked_ptr<RulesRegistry::Rule> > new_rules; |
246 std::string error = GetAllRules(extension_id, &new_rules); | 262 std::string error = GetAllRules(extension_id, &new_rules); |
247 DCHECK_EQ(std::string(), error); | 263 DCHECK_EQ(std::string(), error); |
248 content::BrowserThread::PostTask( | 264 content::BrowserThread::PostTask( |
249 content::BrowserThread::UI, | 265 content::BrowserThread::UI, |
250 FROM_HERE, | 266 FROM_HERE, |
251 base::Bind(&RuleStorageOnUI::WriteToStorage, | 267 base::Bind(&RulesCacheDelegate::WriteToStorage, |
252 storage_on_ui_, | 268 cache_delegate_, |
253 extension_id, | 269 extension_id, |
254 base::Passed(RulesToValue(new_rules)))); | 270 base::Passed(RulesToValue(new_rules)))); |
255 } | 271 } |
256 | 272 |
257 void RulesRegistryWithCache::MaybeProcessChangedRules( | 273 void RulesRegistry::MaybeProcessChangedRules(const std::string& extension_id) { |
258 const std::string& extension_id) { | |
259 if (process_changed_rules_requested_ != NOT_SCHEDULED_FOR_PROCESSING) | 274 if (process_changed_rules_requested_ != NOT_SCHEDULED_FOR_PROCESSING) |
260 return; | 275 return; |
261 | 276 |
262 process_changed_rules_requested_ = SCHEDULED_FOR_PROCESSING; | 277 process_changed_rules_requested_ = SCHEDULED_FOR_PROCESSING; |
263 ready_.Post(FROM_HERE, | 278 ready_.Post(FROM_HERE, |
264 base::Bind(&RulesRegistryWithCache::ProcessChangedRules, | 279 base::Bind(&RulesRegistry::ProcessChangedRules, |
265 weak_ptr_factory_.GetWeakPtr(), | 280 weak_ptr_factory_.GetWeakPtr(), |
266 extension_id)); | 281 extension_id)); |
267 } | 282 } |
268 | 283 |
269 // RulesRegistryWithCache::RuleStorageOnUI | 284 bool RulesRegistry::IsUniqueId(const std::string& extension_id, |
270 | 285 const std::string& rule_id) const { |
271 const char RulesRegistryWithCache::RuleStorageOnUI::kRulesStoredKey[] = | 286 RuleIdentifiersMap::const_iterator identifiers = |
272 "has_declarative_rules"; | 287 used_rule_identifiers_.find(extension_id); |
273 | 288 if (identifiers == used_rule_identifiers_.end()) |
274 RulesRegistryWithCache::RuleStorageOnUI::RuleStorageOnUI( | 289 return true; |
275 Profile* profile, | 290 return identifiers->second.find(rule_id) == identifiers->second.end(); |
276 const std::string& event_name, | |
277 content::BrowserThread::ID rules_registry_thread, | |
278 base::WeakPtr<RulesRegistryWithCache> registry, | |
279 bool log_storage_init_delay) | |
280 : profile_(profile), | |
281 storage_key_(GetDeclarativeRuleStorageKey(event_name, | |
282 profile->IsOffTheRecord())), | |
283 rules_stored_key_(GetRulesStoredKey(event_name, | |
284 profile->IsOffTheRecord())), | |
285 log_storage_init_delay_(log_storage_init_delay), | |
286 registry_(registry), | |
287 rules_registry_thread_(rules_registry_thread), | |
288 notified_registry_(false), | |
289 weak_ptr_factory_(this) {} | |
290 | |
291 RulesRegistryWithCache::RuleStorageOnUI::~RuleStorageOnUI() {} | |
292 | |
293 // Returns the key to use for storing whether the rules have been stored. | |
294 // static | |
295 std::string RulesRegistryWithCache::RuleStorageOnUI::GetRulesStoredKey( | |
296 const std::string& event_name, | |
297 bool incognito) { | |
298 std::string result(kRulesStoredKey); | |
299 result += incognito ? ".incognito." : "."; | |
300 return result + event_name; | |
301 } | 291 } |
302 | 292 |
303 // This is called from the constructor of RulesRegistryWithCache, so it is | 293 std::string RulesRegistry::GenerateUniqueId(const std::string& extension_id) { |
304 // important that it both | 294 while (!IsUniqueId(extension_id, ToId(last_generated_rule_identifier_id_))) |
305 // 1. calls no (in particular virtual) methods of the rules registry, and | 295 ++last_generated_rule_identifier_id_; |
306 // 2. does not create scoped_refptr holding the registry. (A short-lived | 296 return ToId(last_generated_rule_identifier_id_); |
307 // scoped_refptr might delete the rules registry before it is constructed.) | |
308 void RulesRegistryWithCache::RuleStorageOnUI::Init() { | |
309 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
310 | |
311 ExtensionSystem& system = *ExtensionSystem::Get(profile_); | |
312 extensions::StateStore* store = system.rules_store(); | |
313 if (store) | |
314 store->RegisterKey(storage_key_); | |
315 | |
316 registrar_.Add(this, | |
317 chrome::NOTIFICATION_EXTENSION_LOADED, | |
318 content::Source<Profile>(profile_->GetOriginalProfile())); | |
319 | |
320 if (profile_->IsOffTheRecord()) | |
321 log_storage_init_delay_ = false; | |
322 | |
323 system.ready().Post( | |
324 FROM_HERE, | |
325 base::Bind(&RuleStorageOnUI::ReadRulesForInstalledExtensions, | |
326 GetWeakPtr())); | |
327 system.ready().Post(FROM_HERE, | |
328 base::Bind(&RuleStorageOnUI::CheckIfReady, GetWeakPtr())); | |
329 } | 297 } |
330 | 298 |
331 void RulesRegistryWithCache::RuleStorageOnUI::WriteToStorage( | 299 std::string RulesRegistry::CheckAndFillInOptionalRules( |
332 const std::string& extension_id, | 300 const std::string& extension_id, |
333 scoped_ptr<base::Value> value) { | 301 const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) { |
334 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 302 // IDs we have inserted, in case we need to rollback this operation. |
335 if (!profile_) | 303 std::vector<std::string> rollback_log; |
336 return; | |
337 | 304 |
338 const base::ListValue* rules = NULL; | 305 // First we insert all rules with existing identifier, so that generated |
339 CHECK(value->GetAsList(&rules)); | 306 // identifiers cannot collide with identifiers passed by the caller. |
340 bool rules_stored_previously = GetDeclarativeRulesStored(extension_id); | 307 for (std::vector<linked_ptr<RulesRegistry::Rule> >::const_iterator i = |
341 bool store_rules = !rules->empty(); | 308 rules.begin(); i != rules.end(); ++i) { |
342 SetDeclarativeRulesStored(extension_id, store_rules); | 309 RulesRegistry::Rule* rule = i->get(); |
343 if (!rules_stored_previously && !store_rules) | 310 if (rule->id.get()) { |
344 return; | 311 std::string id = *(rule->id); |
345 | 312 if (!IsUniqueId(extension_id, id)) { |
346 StateStore* store = ExtensionSystem::Get(profile_)->rules_store(); | 313 RemoveUsedRuleIdentifiers(extension_id, rollback_log); |
347 if (store) | 314 return "Id " + id + " was used multiple times."; |
348 store->SetExtensionValue(extension_id, storage_key_, value.Pass()); | 315 } |
316 used_rule_identifiers_[extension_id].insert(id); | |
317 } | |
318 } | |
319 // Now we generate IDs in case they were not specificed in the rules. This | |
Jeffrey Yasskin
2013/10/30 22:30:48
sp: specificed
Fady Samuel
2013/10/31 14:02:24
Done.
| |
320 // cannot fail so we do not need to keep track of a rollback log. | |
321 for (std::vector<linked_ptr<RulesRegistry::Rule> >::const_iterator i = | |
322 rules.begin(); i != rules.end(); ++i) { | |
323 RulesRegistry::Rule* rule = i->get(); | |
324 if (!rule->id.get()) { | |
325 rule->id.reset(new std::string(GenerateUniqueId(extension_id))); | |
326 used_rule_identifiers_[extension_id].insert(*(rule->id)); | |
327 } | |
328 } | |
329 return std::string(); | |
349 } | 330 } |
350 | 331 |
351 void RulesRegistryWithCache::RuleStorageOnUI::Observe( | 332 void RulesRegistry::FillInOptionalPriorities( |
352 int type, | 333 const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) { |
353 const content::NotificationSource& source, | 334 std::vector<linked_ptr<RulesRegistry::Rule> >::const_iterator i; |
354 const content::NotificationDetails& details) { | 335 for (i = rules.begin(); i != rules.end(); ++i) { |
355 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 336 if (!(*i)->priority.get()) |
356 DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED); | 337 (*i)->priority.reset(new int(DEFAULT_PRIORITY)); |
357 | |
358 const extensions::Extension* extension = | |
359 content::Details<const extensions::Extension>(details).ptr(); | |
360 // TODO(mpcomplete): This API check should generalize to any use of | |
361 // declarative rules, not just webRequest. | |
362 if (extension->HasAPIPermission(APIPermission::kDeclarativeContent) || | |
363 extension->HasAPIPermission(APIPermission::kDeclarativeWebRequest)) { | |
364 ExtensionInfoMap* extension_info_map = | |
365 ExtensionSystem::Get(profile_)->info_map(); | |
366 if (profile_->IsOffTheRecord() && | |
367 !extension_info_map->IsIncognitoEnabled(extension->id())) { | |
368 // Ignore this extension. | |
369 } else { | |
370 ReadFromStorage(extension->id()); | |
371 } | |
372 } | 338 } |
373 } | 339 } |
374 | 340 |
375 void RulesRegistryWithCache::RuleStorageOnUI::CheckIfReady() { | 341 void RulesRegistry::RemoveUsedRuleIdentifiers( |
376 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 342 const std::string& extension_id, |
377 if (notified_registry_ || !waiting_for_extensions_.empty()) | 343 const std::vector<std::string>& identifiers) { |
378 return; | 344 std::vector<std::string>::const_iterator i; |
379 | 345 for (i = identifiers.begin(); i != identifiers.end(); ++i) |
380 content::BrowserThread::PostTask( | 346 used_rule_identifiers_[extension_id].erase(*i); |
381 rules_registry_thread_, | |
382 FROM_HERE, | |
383 base::Bind( | |
384 &RulesRegistryWithCache::MarkReady, registry_, storage_init_time_)); | |
385 notified_registry_ = true; | |
386 } | 347 } |
387 | 348 |
388 void | 349 void RulesRegistry::RemoveAllUsedRuleIdentifiers( |
389 RulesRegistryWithCache::RuleStorageOnUI::ReadRulesForInstalledExtensions() { | |
390 ExtensionSystem& system = *ExtensionSystem::Get(profile_); | |
391 ExtensionService* extension_service = system.extension_service(); | |
392 DCHECK(extension_service); | |
393 // In an OTR profile, we start on top of a normal profile already, so the | |
394 // extension service should be ready. | |
395 DCHECK(!profile_->IsOffTheRecord() || extension_service->is_ready()); | |
396 if (extension_service->is_ready()) { | |
397 const ExtensionSet* extensions = extension_service->extensions(); | |
398 for (ExtensionSet::const_iterator i = extensions->begin(); | |
399 i != extensions->end(); | |
400 ++i) { | |
401 bool needs_apis_storing_rules = | |
402 (*i)->HasAPIPermission(APIPermission::kDeclarativeContent) || | |
403 (*i)->HasAPIPermission(APIPermission::kDeclarativeWebRequest); | |
404 bool respects_off_the_record = | |
405 !(profile_->IsOffTheRecord()) || | |
406 extension_util::IsIncognitoEnabled((*i)->id(), extension_service); | |
407 if (needs_apis_storing_rules && respects_off_the_record) | |
408 ReadFromStorage((*i)->id()); | |
409 } | |
410 } | |
411 } | |
412 | |
413 void RulesRegistryWithCache::RuleStorageOnUI::ReadFromStorage( | |
414 const std::string& extension_id) { | 350 const std::string& extension_id) { |
415 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 351 used_rule_identifiers_.erase(extension_id); |
416 if (!profile_) | |
417 return; | |
418 | |
419 if (log_storage_init_delay_ && storage_init_time_.is_null()) | |
420 storage_init_time_ = base::Time::Now(); | |
421 | |
422 if (!GetDeclarativeRulesStored(extension_id)) { | |
423 ExtensionSystem::Get(profile_)->ready().Post( | |
424 FROM_HERE, base::Bind(&RuleStorageOnUI::CheckIfReady, GetWeakPtr())); | |
425 return; | |
426 } | |
427 | |
428 extensions::StateStore* store = ExtensionSystem::Get(profile_)->rules_store(); | |
429 if (!store) | |
430 return; | |
431 waiting_for_extensions_.insert(extension_id); | |
432 store->GetExtensionValue(extension_id, | |
433 storage_key_, | |
434 base::Bind(&RuleStorageOnUI::ReadFromStorageCallback, | |
435 weak_ptr_factory_.GetWeakPtr(), | |
436 extension_id)); | |
437 } | |
438 | |
439 void RulesRegistryWithCache::RuleStorageOnUI::ReadFromStorageCallback( | |
440 const std::string& extension_id, | |
441 scoped_ptr<base::Value> value) { | |
442 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
443 content::BrowserThread::PostTask( | |
444 rules_registry_thread_, | |
445 FROM_HERE, | |
446 base::Bind(&RulesRegistryWithCache::DeserializeAndAddRules, | |
447 registry_, | |
448 extension_id, | |
449 base::Passed(&value))); | |
450 | |
451 waiting_for_extensions_.erase(extension_id); | |
452 | |
453 if (waiting_for_extensions_.empty()) | |
454 ExtensionSystem::Get(profile_)->ready().Post( | |
455 FROM_HERE, base::Bind(&RuleStorageOnUI::CheckIfReady, GetWeakPtr())); | |
456 } | |
457 | |
458 bool RulesRegistryWithCache::RuleStorageOnUI::GetDeclarativeRulesStored( | |
459 const std::string& extension_id) const { | |
460 CHECK(profile_); | |
461 const ExtensionScopedPrefs* extension_prefs = ExtensionPrefs::Get(profile_); | |
462 | |
463 bool rules_stored = true; | |
464 if (extension_prefs->ReadPrefAsBoolean( | |
465 extension_id, rules_stored_key_, &rules_stored)) | |
466 return rules_stored; | |
467 | |
468 // Safe default -- if we don't know that the rules are not stored, we force | |
469 // a read by returning true. | |
470 return true; | |
471 } | |
472 | |
473 void RulesRegistryWithCache::RuleStorageOnUI::SetDeclarativeRulesStored( | |
474 const std::string& extension_id, | |
475 bool rules_stored) { | |
476 CHECK(profile_); | |
477 ExtensionScopedPrefs* extension_prefs = ExtensionPrefs::Get(profile_); | |
478 extension_prefs->UpdateExtensionPref( | |
479 extension_id, | |
480 rules_stored_key_, | |
481 new base::FundamentalValue(rules_stored)); | |
482 } | 352 } |
483 | 353 |
484 } // namespace extensions | 354 } // namespace extensions |
OLD | NEW |