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