Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(700)

Side by Side Diff: chrome/browser/extensions/api/declarative/rules_registry.cc

Issue 49693003: Refactor RulesRegistryWithCache to RulesRegistry (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Tests mostly work Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/time/time.h"
13 #include "base/values.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/extensions/api/declarative/rules_cache_delegate.h"
16 #include "chrome/browser/extensions/extension_info_map.h"
17 #include "chrome/browser/extensions/extension_prefs.h"
18 #include "chrome/browser/extensions/extension_service.h"
19 #include "chrome/browser/extensions/extension_system.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 "chrome/common/extensions/extension.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/notification_details.h"
26 #include "content/public/browser/notification_source.h"
27
28 namespace {
29
30 const char kSuccess[] = "";
31 const char kDuplicateRuleId[] = "Duplicate rule ID: %s";
32
33 scoped_ptr<base::Value> RulesToValue(
34 const std::vector<linked_ptr<extensions::RulesRegistry::Rule> >& rules) {
35 scoped_ptr<base::ListValue> list(new base::ListValue());
36 for (size_t i = 0; i < rules.size(); ++i)
37 list->Append(rules[i]->ToValue().release());
38 return list.PassAs<base::Value>();
39 }
40
41 std::vector<linked_ptr<extensions::RulesRegistry::Rule> > RulesFromValue(
42 const base::Value* value) {
43 std::vector<linked_ptr<extensions::RulesRegistry::Rule> > rules;
44
45 const base::ListValue* list = NULL;
46 if (!value || !value->GetAsList(&list))
47 return rules;
48
49 rules.reserve(list->GetSize());
50 for (size_t i = 0; i < list->GetSize(); ++i) {
51 const base::DictionaryValue* dict = NULL;
52 if (!list->GetDictionary(i, &dict))
53 continue;
54 linked_ptr<extensions::RulesRegistry::Rule> rule(
55 new extensions::RulesRegistry::Rule());
56 if (extensions::RulesRegistry::Rule::Populate(*dict, rule.get()))
57 rules.push_back(rule);
58 }
59
60 return rules;
61 }
62
63 std::string ToId(int identifier) {
64 return base::StringPrintf("_%d_", identifier);
65 }
66
67 } // namespace
68
69
70 namespace extensions {
71
72 // RulesRegistry
73
74 RulesRegistry::RulesRegistry(
75 Profile* profile,
76 const std::string& event_name,
77 content::BrowserThread::ID owner_thread,
78 bool log_storage_init_delay,
79 scoped_ptr<RulesCacheDelegate>* ui_part)
80 : owner_thread_(owner_thread),
81 event_name_(event_name),
82 weak_ptr_factory_(profile ? this : NULL),
83 cache_delegate_(
84 (profile ? (new RulesCacheDelegate(profile,
85 event_name,
86 owner_thread,
87 weak_ptr_factory_.GetWeakPtr(),
88 log_storage_init_delay))->GetWeakPtr()
89 : base::WeakPtr<RulesCacheDelegate>())),
90 process_changed_rules_requested_(profile ? NOT_SCHEDULED_FOR_PROCESSING
91 : NEVER_PROCESS),
92 last_generated_rule_identifier_id_(0) {
93 if (!profile) {
94 CHECK(!ui_part);
95 return;
96 }
97
98 ui_part->reset(cache_delegate_.get());
99
100 cache_delegate_->Init();
101 }
102
103 std::string RulesRegistry::AddRules(
104 const std::string& extension_id,
105 const std::vector<linked_ptr<Rule> >& rules) {
106 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread()));
107
108 std::string error = CheckAndFillInOptionalRules(extension_id, rules);
109 if (!error.empty())
110 return error;
111 FillInOptionalPriorities(rules);
112
113 // Verify that all rule IDs are new.
114 for (std::vector<linked_ptr<Rule> >::const_iterator i =
115 rules.begin(); i != rules.end(); ++i) {
116 const RuleId& rule_id = *((*i)->id);
117 RulesDictionaryKey key(extension_id, rule_id);
118 if (rules_.find(key) != rules_.end())
119 return base::StringPrintf(kDuplicateRuleId, rule_id.c_str());
120 }
121
122 error = AddRulesImpl(extension_id, rules);
123
124 if (!error.empty())
125 return error;
126
127 // Commit all rules into |rules_| on success.
vabr (Chromium) 2013/10/29 16:05:54 This is one of the parts when the rules caching co
128 for (std::vector<linked_ptr<Rule> >::const_iterator i =
129 rules.begin(); i != rules.end(); ++i) {
130 const RuleId& rule_id = *((*i)->id);
131 RulesDictionaryKey key(extension_id, rule_id);
132 rules_[key] = *i;
133 }
134
135 MaybeProcessChangedRules(extension_id);
136 return kSuccess;
137 }
138
139 std::string RulesRegistry::RemoveRules(
140 const std::string& extension_id,
141 const std::vector<std::string>& rule_identifiers) {
142 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread()));
143
144 std::string error = RemoveRulesImpl(extension_id, rule_identifiers);
145
146 if (!error.empty())
147 return error;
148
149 // Commit removal of rules from |rules_| on success.
150 for (std::vector<std::string>::const_iterator i =
151 rule_identifiers.begin(); i != rule_identifiers.end(); ++i) {
152 RulesDictionaryKey lookup_key(extension_id, *i);
153 rules_.erase(lookup_key);
154 }
155
156 MaybeProcessChangedRules(extension_id);
157 RemoveUsedRuleIdentifiers(extension_id, rule_identifiers);
158 return kSuccess;
159 }
160
161 std::string RulesRegistry::RemoveAllRules(const std::string& extension_id) {
162 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread()));
163
164 std::string error = RemoveAllRulesImpl(extension_id);
165
166 if (!error.empty())
167 return error;
168
169 // Commit removal of rules from |rules_| on success.
170 for (RulesDictionary::const_iterator i = rules_.begin();
171 i != rules_.end();) {
172 const RulesDictionaryKey& key = i->first;
173 ++i;
174 if (key.first == extension_id)
175 rules_.erase(key);
176 }
177
178 MaybeProcessChangedRules(extension_id);
179 RemoveAllUsedRuleIdentifiers(extension_id);
180 return kSuccess;
181 }
182
183 std::string RulesRegistry::GetRules(
184 const std::string& extension_id,
185 const std::vector<std::string>& rule_identifiers,
186 std::vector<linked_ptr<RulesRegistry::Rule> >* out) {
187 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread()));
188
189 for (std::vector<std::string>::const_iterator i = rule_identifiers.begin();
190 i != rule_identifiers.end(); ++i) {
191 RulesDictionaryKey lookup_key(extension_id, *i);
192 RulesDictionary::iterator entry = rules_.find(lookup_key);
193 if (entry != rules_.end())
194 out->push_back(entry->second);
195 }
196 return kSuccess;
197 }
198
199 std::string RulesRegistry::GetAllRules(
200 const std::string& extension_id,
201 std::vector<linked_ptr<RulesRegistry::Rule> >* out) {
202 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread()));
203
204 for (RulesDictionary::const_iterator i = rules_.begin();
205 i != rules_.end(); ++i) {
206 const RulesDictionaryKey& key = i->first;
207 if (key.first == extension_id)
208 out->push_back(i->second);
209 }
210 return kSuccess;
211 }
212
213 void RulesRegistry::OnExtensionUnloaded(const std::string& extension_id) {
214 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread()));
215 std::string error = RemoveAllRules(extension_id);
216 if (!error.empty())
217 LOG(ERROR) << error;
218 used_rule_identifiers_.erase(extension_id);
219 }
220
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;
232 }
233
234 RulesRegistry::~RulesRegistry() {
235 }
236
237 void RulesRegistry::MarkReady(base::Time storage_init_time) {
238 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread()));
239
240 if (!storage_init_time.is_null()) {
241 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeRulesStorageInitialization",
242 base::Time::Now() - storage_init_time);
243 }
244
245 ready_.Signal();
246 }
247
248 void RulesRegistry::DeserializeAndAddRules(
249 const std::string& extension_id,
250 scoped_ptr<base::Value> rules) {
251 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread()));
252
253 AddRules(extension_id, RulesFromValue(rules.get()));
254 }
255
256 void RulesRegistry::ProcessChangedRules(const std::string& extension_id) {
257 DCHECK(content::BrowserThread::CurrentlyOn(owner_thread()));
258
259 process_changed_rules_requested_ = NOT_SCHEDULED_FOR_PROCESSING;
260
261 std::vector<linked_ptr<RulesRegistry::Rule> > new_rules;
262 std::string error = GetAllRules(extension_id, &new_rules);
263 DCHECK_EQ(std::string(), error);
264 content::BrowserThread::PostTask(
265 content::BrowserThread::UI,
266 FROM_HERE,
267 base::Bind(&RulesCacheDelegate::WriteToStorage,
268 cache_delegate_,
269 extension_id,
270 base::Passed(RulesToValue(new_rules))));
271 }
272
273 void RulesRegistry::MaybeProcessChangedRules(const std::string& extension_id) {
274 if (process_changed_rules_requested_ != NOT_SCHEDULED_FOR_PROCESSING)
275 return;
276
277 process_changed_rules_requested_ = SCHEDULED_FOR_PROCESSING;
278 ready_.Post(FROM_HERE,
279 base::Bind(&RulesRegistry::ProcessChangedRules,
280 weak_ptr_factory_.GetWeakPtr(),
281 extension_id));
282 }
283
284 bool RulesRegistry::IsUniqueId(const std::string& extension_id,
285 const std::string& rule_id) const {
286 RuleIdentifiersMap::const_iterator identifiers =
287 used_rule_identifiers_.find(extension_id);
288 if (identifiers == used_rule_identifiers_.end())
289 return true;
290 return identifiers->second.find(rule_id) == identifiers->second.end();
291 }
292
293 std::string RulesRegistry::GenerateUniqueId(const std::string& extension_id) {
294 while (!IsUniqueId(extension_id, ToId(last_generated_rule_identifier_id_)))
295 ++last_generated_rule_identifier_id_;
296 return ToId(last_generated_rule_identifier_id_);
297 }
298
299 std::string RulesRegistry::CheckAndFillInOptionalRules(
300 const std::string& extension_id,
301 const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) {
302 // IDs we have inserted, in case we need to rollback this operation.
303 std::vector<std::string> rollback_log;
304
305 // First we insert all rules with existing identifier, so that generated
306 // identifiers cannot collide with identifiers passed by the caller.
307 for (std::vector<linked_ptr<RulesRegistry::Rule> >::const_iterator i =
308 rules.begin(); i != rules.end(); ++i) {
309 RulesRegistry::Rule* rule = i->get();
310 if (rule->id.get()) {
311 std::string id = *(rule->id);
312 if (!IsUniqueId(extension_id, id)) {
313 RemoveUsedRuleIdentifiers(extension_id, rollback_log);
314 return "Id " + id + " was used multiple times.";
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
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();
330 }
331
332 void RulesRegistry::FillInOptionalPriorities(
333 const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) {
334 std::vector<linked_ptr<RulesRegistry::Rule> >::const_iterator i;
335 for (i = rules.begin(); i != rules.end(); ++i) {
336 if (!(*i)->priority.get())
337 (*i)->priority.reset(new int(DEFAULT_PRIORITY));
338 }
339 }
340
341 void RulesRegistry::RemoveUsedRuleIdentifiers(
342 const std::string& extension_id,
343 const std::vector<std::string>& identifiers) {
344 std::vector<std::string>::const_iterator i;
345 for (i = identifiers.begin(); i != identifiers.end(); ++i)
346 used_rule_identifiers_[extension_id].erase(*i);
347 }
348
349 void RulesRegistry::RemoveAllUsedRuleIdentifiers(
350 const std::string& extension_id) {
351 used_rule_identifiers_.erase(extension_id);
352 }
353
354 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698