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

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

Issue 10560013: Persist declarative rules to the extension state store. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: RegisterKey Created 8 years, 6 months 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 | Annotate | Revision Log
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_storage_deleg ate.h"
6
7 #include "base/bind.h"
8 #include "chrome/browser/extensions/extension_system.h"
9 #include "chrome/browser/extensions/state_store.h"
10 #include "chrome/common/chrome_notification_types.h"
11 #include "chrome/common/extensions/extension.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/notification_details.h"
14 #include "content/public/browser/notification_source.h"
15
16 namespace extensions {
17
18 namespace {
19
20 scoped_ptr<base::Value> RulesToValue(
21 const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) {
22 scoped_ptr<base::ListValue> list(new base::ListValue());
23 for (size_t i = 0; i < rules.size(); ++i)
24 list->Append(rules[i]->ToValue().release());
25 return list.PassAs<base::Value>();
26 }
27
28 std::vector<linked_ptr<RulesRegistry::Rule> > RulesFromValue(
29 base::Value* value) {
30 std::vector<linked_ptr<RulesRegistry::Rule> > rules;
31
32 base::ListValue* list = NULL;
33 if (!value || !value->GetAsList(&list))
34 return rules;
35
36 for (size_t i = 0; i < list->GetSize(); ++i) {
37 base::DictionaryValue* dict = NULL;
38 if (!list->GetDictionary(i, &dict))
39 continue;
40 linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule());
41 if (RulesRegistry::Rule::Populate(*dict, rule.get()))
42 rules.push_back(rule);
43 }
44
45 return rules;
46 }
47
48 } // namespace
49
50 // This class coordinates information between the UI and RulesRegistry threads.
51 // It may outlive the RulesRegistry, which owns the delegate. Methods/variables
52 // should be used on the UI thread unless otherwise noted.
53 class RulesRegistryStorageDelegate::Inner
54 : public content::NotificationObserver,
55 public base::RefCountedThreadSafe<
56 Inner, content::BrowserThread::DeleteOnUIThread> {
57 public:
58 Inner(Profile* profile,
59 RulesRegistryWithCache* rules_registry,
60 const std::string& storage_key);
61
62 private:
63 friend class RulesRegistryStorageDelegate;
64 friend struct content::BrowserThread::DeleteOnThread<
65 content::BrowserThread::UI>;
66 friend class base::DeleteHelper<Inner>;
67
68 ~Inner();
69
70 // NotificationObserver
71 virtual void Observe(
72 int type,
73 const content::NotificationSource& source,
74 const content::NotificationDetails& details) OVERRIDE;
75
76 // Read/write a list of rules serialized to Values.
77 void ReadFromStorage(const std::string& extension_id);
78 void ReadFromStorageCallback(const std::string& extension_id,
79 scoped_ptr<base::Value> value);
80 void WriteToStorage(const std::string& extension_id,
81 scoped_ptr<base::Value> value);
82
83 // Check if we are done reading all data from storage on startup, and notify
84 // the RulesRegistry on its thread if so. The notification is delivered
85 // exactly once.
86 void CheckIfReady();
87
88 // Deserialize the rules from the given Value object and add them to the
89 // RulesRegistry.
90 void ReadFromStorageOnRegistryThread(const std::string& extension_id,
91 scoped_ptr<base::Value> value);
92
93 // Notify the RulesRegistry that we are now ready.
94 void NotifyReadyOnRegistryThread();
95
96 content::NotificationRegistrar registrar_;
97 Profile* profile_;
98
99 // The key under which rules are stored.
100 const std::string storage_key_;
101
102 // A set of extension IDs that have rules we are reading from storage.
103 std::set<std::string> waiting_for_extensions_;
104
105 // The thread that our RulesRegistry lives on.
106 content::BrowserThread::ID rules_registry_thread_;
107
108 // The following are only accessible on rules_registry_thread_.
109
110 // The RulesRegistry whose delegate we are.
111 RulesRegistryWithCache* rules_registry_;
112
113 // True when we have finished reading from storage for all extensions that
114 // are loaded on startup.
115 bool ready_;
116 };
117
118 RulesRegistryStorageDelegate::RulesRegistryStorageDelegate() {
119 }
120
121 RulesRegistryStorageDelegate::~RulesRegistryStorageDelegate() {
122 // RulesRegistry owns us, which means it has been deleted.
123 inner_->rules_registry_ = NULL;
124 }
125
126 void RulesRegistryStorageDelegate::Init(Profile* profile,
127 RulesRegistryWithCache* rules_registry,
128 const std::string& storage_key) {
129 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
130 extensions::StateStore* store = ExtensionSystem::Get(profile)->state_store();
131 if (store)
132 store->RegisterKey(storage_key);
133 inner_ = new Inner(profile, rules_registry, storage_key);
134 }
135
136 bool RulesRegistryStorageDelegate::IsReady() {
137 DCHECK(content::BrowserThread::CurrentlyOn(inner_->rules_registry_thread_));
138 return inner_->ready_;
139 }
140
141 void RulesRegistryStorageDelegate::OnRulesChanged(
142 RulesRegistryWithCache* rules_registry,
143 const std::string& extension_id) {
144 DCHECK(content::BrowserThread::CurrentlyOn(inner_->rules_registry_thread_));
145 std::vector<linked_ptr<RulesRegistry::Rule> > new_rules;
146 std::string error = rules_registry->GetAllRules(extension_id, &new_rules);
147 DCHECK_EQ("", error);
148 content::BrowserThread::PostTask(
149 content::BrowserThread::UI, FROM_HERE,
150 base::Bind(&Inner::WriteToStorage, inner_.get(), extension_id,
151 base::Passed(RulesToValue(new_rules))));
152 }
153
154 RulesRegistryStorageDelegate::Inner::Inner(
155 Profile* profile,
156 RulesRegistryWithCache* rules_registry,
157 const std::string& storage_key)
158 : profile_(profile),
159 storage_key_(storage_key),
160 rules_registry_thread_(rules_registry->GetOwnerThread()),
161 rules_registry_(rules_registry),
162 ready_(false) {
163 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
164 content::Source<Profile>(profile));
165 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
166 content::Source<Profile>(profile));
167 }
168
169 RulesRegistryStorageDelegate::Inner::~Inner() {}
170
171 void RulesRegistryStorageDelegate::Inner::Observe(
172 int type,
173 const content::NotificationSource& source,
174 const content::NotificationDetails& details) {
175 if (type == chrome::NOTIFICATION_EXTENSION_LOADED) {
176 const extensions::Extension* extension =
177 content::Details<const extensions::Extension>(details).ptr();
178 // TODO(mpcomplete): This API check should generalize to any use of
179 // declarative rules, not just webRequest.
180 if (extension->HasAPIPermission(
181 ExtensionAPIPermission::kDeclarativeWebRequest)) {
182 ReadFromStorage(extension->id());
183 }
184 } else if (type == chrome::NOTIFICATION_EXTENSIONS_READY) {
185 CheckIfReady();
186 }
187 }
188
189 void RulesRegistryStorageDelegate::Inner::ReadFromStorage(
190 const std::string& extension_id) {
191 extensions::StateStore* store = ExtensionSystem::Get(profile_)->state_store();
192 if (store) {
193 waiting_for_extensions_.insert(extension_id);
194 store->GetExtensionValue(extension_id, storage_key_,
195 base::Bind(&Inner::ReadFromStorageCallback, this, extension_id));
196 }
197 }
198
199 void RulesRegistryStorageDelegate::Inner::ReadFromStorageCallback(
200 const std::string& extension_id, scoped_ptr<base::Value> value) {
201 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
202 content::BrowserThread::PostTask(
203 rules_registry_thread_, FROM_HERE,
204 base::Bind(&Inner::ReadFromStorageOnRegistryThread, this,
205 extension_id, base::Passed(value.Pass())));
206
207 waiting_for_extensions_.erase(extension_id);
208 CheckIfReady();
209 }
210
211 void RulesRegistryStorageDelegate::Inner::WriteToStorage(
212 const std::string& extension_id, scoped_ptr<base::Value> value) {
213 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
214 StateStore* store = ExtensionSystem::Get(profile_)->state_store();
215 if (store)
216 store->SetExtensionValue(extension_id, storage_key_, value.Pass());
217 }
218
219 void RulesRegistryStorageDelegate::Inner::CheckIfReady() {
220 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
221 if (!waiting_for_extensions_.empty())
222 return;
223
224 content::BrowserThread::PostTask(
225 rules_registry_thread_, FROM_HERE,
226 base::Bind(&Inner::NotifyReadyOnRegistryThread, this));
227 }
228
229 void RulesRegistryStorageDelegate::Inner::ReadFromStorageOnRegistryThread(
230 const std::string& extension_id, scoped_ptr<base::Value> value) {
231 DCHECK(content::BrowserThread::CurrentlyOn(rules_registry_thread_));
232 if (!rules_registry_)
233 return; // registry went away
234
235 rules_registry_->AddRules(extension_id, RulesFromValue(value.get()));
236 }
237
238 void RulesRegistryStorageDelegate::Inner::NotifyReadyOnRegistryThread() {
239 DCHECK(content::BrowserThread::CurrentlyOn(rules_registry_thread_));
240 if (ready_)
241 return; // we've already notified our readiness
242
243 ready_ = true;
244 rules_registry_->OnReady();
245 }
246
247 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698