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