blob: 82d7caaa4e92e33c8e5eddff238a49bf9e3f8582 [file] [log] [blame]
[email protected]daf3ffda2014-06-25 06:44:571// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]90e800c2012-06-12 23:11:002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]daf3ffda2014-06-25 06:44:575#include "extensions/browser/state_store.h"
[email protected]90e800c2012-06-12 23:11:006
[email protected]ebaa018d2012-12-11 21:42:537#include "base/bind.h"
[email protected]b19fe572013-07-18 04:54:268#include "base/message_loop/message_loop.h"
[email protected]49a01e642013-07-12 00:29:459#include "chrome/browser/chrome_notification_types.h"
[email protected]daf3ffda2014-06-25 06:44:5710#include "content/public/browser/browser_context.h"
[email protected]90e800c2012-06-12 23:11:0011#include "content/public/browser/notification_service.h"
12#include "content/public/browser/notification_types.h"
[email protected]3cb79a52014-06-15 04:54:4513#include "extensions/browser/extension_registry.h"
[email protected]e4452d32013-11-15 23:07:4114#include "extensions/common/extension.h"
[email protected]90e800c2012-06-12 23:11:0015
16namespace {
17
[email protected]ebaa018d2012-12-11 21:42:5318// 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
[email protected]87093442013-01-12 16:34:0520const int kInitDelaySeconds = 1;
[email protected]ebaa018d2012-12-11 21:42:5321
[email protected]90e800c2012-06-12 23:11:0022std::string GetFullKey(const std::string& extension_id,
23 const std::string& key) {
24 return extension_id + "." + key;
25}
26
27} // namespace
28
29namespace extensions {
30
[email protected]ebaa018d2012-12-11 21:42:5331// Helper class to delay tasks until we're ready to start executing them.
32class StateStore::DelayedTaskQueue {
33 public:
34 DelayedTaskQueue() : ready_(false) {}
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
[email protected]c6ea4b42014-03-10 23:25:1144 // Return whether or not the DelayedTaskQueue is |ready_|.
45 bool ready() const { return ready_; }
46
[email protected]ebaa018d2012-12-11 21:42:5347 private:
48 bool ready_;
49 std::vector<base::Closure> pending_tasks_;
50};
51
52void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
53 if (ready_) {
54 task.Run();
55 } else {
56 pending_tasks_.push_back(task);
57 }
58}
59
60void 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
[email protected]daf3ffda2014-06-25 06:44:5768StateStore::StateStore(content::BrowserContext* context,
[email protected]650b2d52013-02-10 03:41:4569 const base::FilePath& db_path,
[email protected]a690e292012-12-19 19:22:4970 bool deferred_load)
[email protected]3cb79a52014-06-15 04:54:4571 : db_path_(db_path),
72 task_queue_(new DelayedTaskQueue()),
73 extension_registry_observer_(this) {
[email protected]daf3ffda2014-06-25 06:44:5774 extension_registry_observer_.Add(ExtensionRegistry::Get(context));
[email protected]ebaa018d2012-12-11 21:42:5375
[email protected]a690e292012-12-19 19:22:4976 if (deferred_load) {
[email protected]ac7ba322013-04-12 23:12:2477 // Don't Init until the first page is loaded or the session restored.
[email protected]daf3ffda2014-06-25 06:44:5778 registrar_.Add(
79 this,
80 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
81 content::NotificationService::AllBrowserContextsAndSources());
82 registrar_.Add(
83 this,
84 chrome::NOTIFICATION_SESSION_RESTORE_DONE,
85 content::NotificationService::AllBrowserContextsAndSources());
[email protected]a690e292012-12-19 19:22:4986 } else {
[email protected]87093442013-01-12 16:34:0587 Init();
[email protected]a690e292012-12-19 19:22:4988 }
[email protected]90e800c2012-06-12 23:11:0089}
90
[email protected]daf3ffda2014-06-25 06:44:5791StateStore::StateStore(content::BrowserContext* context,
92 scoped_ptr<ValueStore> value_store)
[email protected]3cb79a52014-06-15 04:54:4593 : store_(value_store.Pass()),
94 task_queue_(new DelayedTaskQueue()),
95 extension_registry_observer_(this) {
[email protected]daf3ffda2014-06-25 06:44:5796 extension_registry_observer_.Add(ExtensionRegistry::Get(context));
[email protected]ebaa018d2012-12-11 21:42:5397
98 // This constructor is for testing. No need to delay Init.
[email protected]87093442013-01-12 16:34:0599 Init();
[email protected]bec64552012-06-13 20:25:49100}
101
[email protected]90e800c2012-06-12 23:11:00102StateStore::~StateStore() {
103}
104
105void StateStore::RegisterKey(const std::string& key) {
106 registered_keys_.insert(key);
107}
108
109void StateStore::GetExtensionValue(const std::string& extension_id,
110 const std::string& key,
111 ReadCallback callback) {
[email protected]daf3ffda2014-06-25 06:44:57112 task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Get,
113 base::Unretained(&store_),
114 GetFullKey(extension_id, key),
115 callback));
[email protected]90e800c2012-06-12 23:11:00116}
117
[email protected]daf3ffda2014-06-25 06:44:57118void 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)));
[email protected]90e800c2012-06-12 23:11:00125}
126
[email protected]a690e292012-12-19 19:22:49127void StateStore::RemoveExtensionValue(const std::string& extension_id,
128 const std::string& key) {
[email protected]daf3ffda2014-06-25 06:44:57129 task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
130 base::Unretained(&store_),
131 GetFullKey(extension_id, key)));
[email protected]a690e292012-12-19 19:22:49132}
133
[email protected]daf3ffda2014-06-25 06:44:57134bool StateStore::IsInitialized() const {
135 return task_queue_->ready();
136}
[email protected]c6ea4b42014-03-10 23:25:11137
[email protected]90e800c2012-06-12 23:11:00138void StateStore::Observe(int type,
139 const content::NotificationSource& source,
140 const content::NotificationDetails& details) {
[email protected]3cb79a52014-06-15 04:54:45141 DCHECK(type == chrome::NOTIFICATION_SESSION_RESTORE_DONE ||
142 type == content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME);
143 registrar_.RemoveAll();
144
[email protected]daf3ffda2014-06-25 06:44:57145 base::MessageLoop::current()->PostDelayedTask(
146 FROM_HERE,
[email protected]3cb79a52014-06-15 04:54:45147 base::Bind(&StateStore::Init, AsWeakPtr()),
148 base::TimeDelta::FromSeconds(kInitDelaySeconds));
149}
150
151void StateStore::OnExtensionWillBeInstalled(
152 content::BrowserContext* browser_context,
153 const Extension* extension,
154 bool is_update,
155 bool from_ephemeral,
156 const std::string& old_name) {
157 RemoveKeysForExtension(extension->id());
158}
159
160void StateStore::OnExtensionUninstalled(
161 content::BrowserContext* browser_context,
[email protected]e43c61f2014-07-20 21:46:34162 const Extension* extension,
163 extensions::UninstallReason reason) {
[email protected]3cb79a52014-06-15 04:54:45164 RemoveKeysForExtension(extension->id());
[email protected]a690e292012-12-19 19:22:49165}
[email protected]90e800c2012-06-12 23:11:00166
[email protected]87093442013-01-12 16:34:05167void StateStore::Init() {
168 if (!db_path_.empty())
169 store_.Init(db_path_);
170 task_queue_->SetReady();
171}
172
[email protected]a690e292012-12-19 19:22:49173void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
[email protected]90e800c2012-06-12 23:11:00174 for (std::set<std::string>::iterator key = registered_keys_.begin();
[email protected]daf3ffda2014-06-25 06:44:57175 key != registered_keys_.end();
176 ++key) {
177 task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
178 base::Unretained(&store_),
179 GetFullKey(extension_id, *key)));
[email protected]90e800c2012-06-12 23:11:00180 }
181}
182
[email protected]90e800c2012-06-12 23:11:00183} // namespace extensions