• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/state_store.h"
6 
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "content/public/browser/notification_service.h"
12 #include "content/public/browser/notification_types.h"
13 #include "extensions/browser/extension_registry.h"
14 #include "extensions/common/extension.h"
15 
16 namespace {
17 
18 // Delay, in seconds, before we should open the State Store database. We
19 // defer it to avoid slowing down startup. See http://crbug.com/161848
20 const int kInitDelaySeconds = 1;
21 
GetFullKey(const std::string & extension_id,const std::string & key)22 std::string GetFullKey(const std::string& extension_id,
23                        const std::string& key) {
24   return extension_id + "." + key;
25 }
26 
27 }  // namespace
28 
29 namespace extensions {
30 
31 // Helper class to delay tasks until we're ready to start executing them.
32 class StateStore::DelayedTaskQueue {
33  public:
DelayedTaskQueue()34   DelayedTaskQueue() : ready_(false) {}
~DelayedTaskQueue()35   ~DelayedTaskQueue() {}
36 
37   // Queues up a task for invoking once we're ready. Invokes immediately if
38   // we're already ready.
39   void InvokeWhenReady(base::Closure task);
40 
41   // Marks us ready, and invokes all pending tasks.
42   void SetReady();
43 
44   // Return whether or not the DelayedTaskQueue is |ready_|.
ready() const45   bool ready() const { return ready_; }
46 
47  private:
48   bool ready_;
49   std::vector<base::Closure> pending_tasks_;
50 };
51 
InvokeWhenReady(base::Closure task)52 void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
53   if (ready_) {
54     task.Run();
55   } else {
56     pending_tasks_.push_back(task);
57   }
58 }
59 
SetReady()60 void StateStore::DelayedTaskQueue::SetReady() {
61   ready_ = true;
62 
63   for (size_t i = 0; i < pending_tasks_.size(); ++i)
64     pending_tasks_[i].Run();
65   pending_tasks_.clear();
66 }
67 
StateStore(Profile * profile,const base::FilePath & db_path,bool deferred_load)68 StateStore::StateStore(Profile* profile,
69                        const base::FilePath& db_path,
70                        bool deferred_load)
71     : db_path_(db_path),
72       task_queue_(new DelayedTaskQueue()),
73       extension_registry_observer_(this) {
74   extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
75 
76   if (deferred_load) {
77     // Don't Init until the first page is loaded or the session restored.
78     registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
79                    content::NotificationService::
80                        AllBrowserContextsAndSources());
81     registrar_.Add(this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
82                    content::NotificationService::
83                        AllBrowserContextsAndSources());
84   } else {
85     Init();
86   }
87 }
88 
StateStore(Profile * profile,scoped_ptr<ValueStore> value_store)89 StateStore::StateStore(Profile* profile, scoped_ptr<ValueStore> value_store)
90     : store_(value_store.Pass()),
91       task_queue_(new DelayedTaskQueue()),
92       extension_registry_observer_(this) {
93   extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
94 
95   // This constructor is for testing. No need to delay Init.
96   Init();
97 }
98 
~StateStore()99 StateStore::~StateStore() {
100 }
101 
RegisterKey(const std::string & key)102 void StateStore::RegisterKey(const std::string& key) {
103   registered_keys_.insert(key);
104 }
105 
GetExtensionValue(const std::string & extension_id,const std::string & key,ReadCallback callback)106 void StateStore::GetExtensionValue(const std::string& extension_id,
107                                    const std::string& key,
108                                    ReadCallback callback) {
109   task_queue_->InvokeWhenReady(
110       base::Bind(&ValueStoreFrontend::Get, base::Unretained(&store_),
111                  GetFullKey(extension_id, key), callback));
112 }
113 
SetExtensionValue(const std::string & extension_id,const std::string & key,scoped_ptr<base::Value> value)114 void StateStore::SetExtensionValue(
115     const std::string& extension_id,
116     const std::string& key,
117     scoped_ptr<base::Value> value) {
118   task_queue_->InvokeWhenReady(
119       base::Bind(&ValueStoreFrontend::Set, base::Unretained(&store_),
120                  GetFullKey(extension_id, key), base::Passed(&value)));
121 }
122 
RemoveExtensionValue(const std::string & extension_id,const std::string & key)123 void StateStore::RemoveExtensionValue(const std::string& extension_id,
124                                       const std::string& key) {
125   task_queue_->InvokeWhenReady(
126       base::Bind(&ValueStoreFrontend::Remove, base::Unretained(&store_),
127                  GetFullKey(extension_id, key)));
128 }
129 
IsInitialized() const130 bool StateStore::IsInitialized() const { return task_queue_->ready(); }
131 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)132 void StateStore::Observe(int type,
133                          const content::NotificationSource& source,
134                          const content::NotificationDetails& details) {
135   DCHECK(type == chrome::NOTIFICATION_SESSION_RESTORE_DONE ||
136          type == content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME);
137   registrar_.RemoveAll();
138 
139   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
140       base::Bind(&StateStore::Init, AsWeakPtr()),
141       base::TimeDelta::FromSeconds(kInitDelaySeconds));
142 }
143 
OnExtensionWillBeInstalled(content::BrowserContext * browser_context,const Extension * extension,bool is_update,bool from_ephemeral,const std::string & old_name)144 void StateStore::OnExtensionWillBeInstalled(
145     content::BrowserContext* browser_context,
146     const Extension* extension,
147     bool is_update,
148     bool from_ephemeral,
149     const std::string& old_name) {
150   RemoveKeysForExtension(extension->id());
151 }
152 
OnExtensionUninstalled(content::BrowserContext * browser_context,const Extension * extension)153 void StateStore::OnExtensionUninstalled(
154     content::BrowserContext* browser_context,
155     const Extension* extension) {
156   RemoveKeysForExtension(extension->id());
157 }
158 
Init()159 void StateStore::Init() {
160   if (!db_path_.empty())
161     store_.Init(db_path_);
162   task_queue_->SetReady();
163 }
164 
RemoveKeysForExtension(const std::string & extension_id)165 void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
166   for (std::set<std::string>::iterator key = registered_keys_.begin();
167        key != registered_keys_.end(); ++key) {
168     task_queue_->InvokeWhenReady(
169         base::Bind(&ValueStoreFrontend::Remove, base::Unretained(&store_),
170                    GetFullKey(extension_id, *key)));
171   }
172 }
173 
174 }  // namespace extensions
175