blob: c4fb85db7eaa177db37fd06ab5752311d87f3675 [file] [log] [blame]
[email protected]90e800c2012-06-12 23:11:001// 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
[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]90e800c2012-06-12 23:11:0010#include "content/public/browser/notification_service.h"
11#include "content/public/browser/notification_types.h"
[email protected]e4452d32013-11-15 23:07:4112#include "extensions/common/extension.h"
[email protected]90e800c2012-06-12 23:11:0013
14namespace {
15
[email protected]ebaa018d2012-12-11 21:42:5316// 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
[email protected]87093442013-01-12 16:34:0518const int kInitDelaySeconds = 1;
[email protected]ebaa018d2012-12-11 21:42:5319
[email protected]90e800c2012-06-12 23:11:0020std::string GetFullKey(const std::string& extension_id,
21 const std::string& key) {
22 return extension_id + "." + key;
23}
24
25} // namespace
26
27namespace extensions {
28
[email protected]ebaa018d2012-12-11 21:42:5329// Helper class to delay tasks until we're ready to start executing them.
30class StateStore::DelayedTaskQueue {
31 public:
32 DelayedTaskQueue() : ready_(false) {}
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
[email protected]c6ea4b42014-03-10 23:25:1142 // Return whether or not the DelayedTaskQueue is |ready_|.
43 bool ready() const { return ready_; }
44
[email protected]ebaa018d2012-12-11 21:42:5345 private:
46 bool ready_;
47 std::vector<base::Closure> pending_tasks_;
48};
49
50void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
51 if (ready_) {
52 task.Run();
53 } else {
54 pending_tasks_.push_back(task);
55 }
56}
57
58void StateStore::DelayedTaskQueue::SetReady() {
59 ready_ = true;
60
61 for (size_t i = 0; i < pending_tasks_.size(); ++i)
62 pending_tasks_[i].Run();
63 pending_tasks_.clear();
64}
65
[email protected]a690e292012-12-19 19:22:4966StateStore::StateStore(Profile* profile,
[email protected]650b2d52013-02-10 03:41:4567 const base::FilePath& db_path,
[email protected]a690e292012-12-19 19:22:4968 bool deferred_load)
[email protected]87093442013-01-12 16:34:0569 : db_path_(db_path), task_queue_(new DelayedTaskQueue()) {
[email protected]90e800c2012-06-12 23:11:0070 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
71 content::Source<Profile>(profile));
72 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
73 content::Source<Profile>(profile));
[email protected]ebaa018d2012-12-11 21:42:5374
[email protected]a690e292012-12-19 19:22:4975 if (deferred_load) {
[email protected]ac7ba322013-04-12 23:12:2476 // Don't Init until the first page is loaded or the session restored.
[email protected]87093442013-01-12 16:34:0577 registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
78 content::NotificationService::
79 AllBrowserContextsAndSources());
[email protected]ac7ba322013-04-12 23:12:2480 registrar_.Add(this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
81 content::NotificationService::
82 AllBrowserContextsAndSources());
[email protected]a690e292012-12-19 19:22:4983 } else {
[email protected]87093442013-01-12 16:34:0584 Init();
[email protected]a690e292012-12-19 19:22:4985 }
[email protected]90e800c2012-06-12 23:11:0086}
87
[email protected]da2b622c2013-09-27 21:30:4088StateStore::StateStore(Profile* profile, scoped_ptr<ValueStore> value_store)
89 : store_(value_store.Pass()), task_queue_(new DelayedTaskQueue()) {
[email protected]bec64552012-06-13 20:25:4990 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
91 content::Source<Profile>(profile));
92 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
93 content::Source<Profile>(profile));
[email protected]ebaa018d2012-12-11 21:42:5394
95 // This constructor is for testing. No need to delay Init.
[email protected]87093442013-01-12 16:34:0596 Init();
[email protected]bec64552012-06-13 20:25:4997}
98
[email protected]90e800c2012-06-12 23:11:0099StateStore::~StateStore() {
100}
101
102void StateStore::RegisterKey(const std::string& key) {
103 registered_keys_.insert(key);
104}
105
106void StateStore::GetExtensionValue(const std::string& extension_id,
107 const std::string& key,
108 ReadCallback callback) {
[email protected]ebaa018d2012-12-11 21:42:53109 task_queue_->InvokeWhenReady(
110 base::Bind(&ValueStoreFrontend::Get, base::Unretained(&store_),
111 GetFullKey(extension_id, key), callback));
[email protected]90e800c2012-06-12 23:11:00112}
113
114void StateStore::SetExtensionValue(
115 const std::string& extension_id,
116 const std::string& key,
117 scoped_ptr<base::Value> value) {
[email protected]ebaa018d2012-12-11 21:42:53118 task_queue_->InvokeWhenReady(
119 base::Bind(&ValueStoreFrontend::Set, base::Unretained(&store_),
[email protected]c02087b512013-02-04 03:09:20120 GetFullKey(extension_id, key), base::Passed(&value)));
[email protected]90e800c2012-06-12 23:11:00121}
122
[email protected]a690e292012-12-19 19:22:49123void 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
[email protected]c6ea4b42014-03-10 23:25:11130bool StateStore::IsInitialized() const { return task_queue_->ready(); }
131
[email protected]90e800c2012-06-12 23:11:00132void StateStore::Observe(int type,
133 const content::NotificationSource& source,
134 const content::NotificationDetails& details) {
[email protected]90e800c2012-06-12 23:11:00135 switch (type) {
136 case chrome::NOTIFICATION_EXTENSION_INSTALLED:
[email protected]41bb80bd2013-05-03 10:56:02137 RemoveKeysForExtension(
138 content::Details<const InstalledExtensionInfo>(details)->extension->
139 id());
140 break;
[email protected]90e800c2012-06-12 23:11:00141 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
[email protected]a690e292012-12-19 19:22:49142 RemoveKeysForExtension(
[email protected]41bb80bd2013-05-03 10:56:02143 content::Details<const Extension>(details)->id());
[email protected]90e800c2012-06-12 23:11:00144 break;
[email protected]ac7ba322013-04-12 23:12:24145 case chrome::NOTIFICATION_SESSION_RESTORE_DONE:
[email protected]87093442013-01-12 16:34:05146 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME:
147 registrar_.Remove(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
148 content::NotificationService::AllSources());
[email protected]ac7ba322013-04-12 23:12:24149 registrar_.Remove(this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
150 content::NotificationService::AllSources());
[email protected]b3a25092013-05-28 22:08:16151 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
[email protected]87093442013-01-12 16:34:05152 base::Bind(&StateStore::Init, AsWeakPtr()),
153 base::TimeDelta::FromSeconds(kInitDelaySeconds));
154 break;
[email protected]90e800c2012-06-12 23:11:00155 default:
156 NOTREACHED();
157 return;
158 }
[email protected]a690e292012-12-19 19:22:49159}
[email protected]90e800c2012-06-12 23:11:00160
[email protected]87093442013-01-12 16:34:05161void StateStore::Init() {
162 if (!db_path_.empty())
163 store_.Init(db_path_);
164 task_queue_->SetReady();
165}
166
[email protected]a690e292012-12-19 19:22:49167void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
[email protected]90e800c2012-06-12 23:11:00168 for (std::set<std::string>::iterator key = registered_keys_.begin();
169 key != registered_keys_.end(); ++key) {
[email protected]ebaa018d2012-12-11 21:42:53170 task_queue_->InvokeWhenReady(
171 base::Bind(&ValueStoreFrontend::Remove, base::Unretained(&store_),
172 GetFullKey(extension_id, *key)));
[email protected]90e800c2012-06-12 23:11:00173 }
174}
175
[email protected]90e800c2012-06-12 23:11:00176} // namespace extensions