blob: 2c8c9f9f1c86a13626c5f66a634ec344a197c6c1 [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
avic9cec102015-12-23 00:39:267#include <stddef.h>
8
dchenge59eca1602015-12-18 17:48:009#include <utility>
10
[email protected]ebaa018d2012-12-11 21:42:5311#include "base/bind.h"
[email protected]b19fe572013-07-18 04:54:2612#include "base/message_loop/message_loop.h"
[email protected]daf3ffda2014-06-25 06:44:5713#include "content/public/browser/browser_context.h"
[email protected]90e800c2012-06-12 23:11:0014#include "content/public/browser/notification_service.h"
15#include "content/public/browser/notification_types.h"
[email protected]3cb79a52014-06-15 04:54:4516#include "extensions/browser/extension_registry.h"
cmumford6ae8d462016-03-24 20:35:2717#include "extensions/browser/value_store/value_store_factory.h"
[email protected]e4452d32013-11-15 23:07:4118#include "extensions/common/extension.h"
[email protected]90e800c2012-06-12 23:11:0019
20namespace {
21
[email protected]ebaa018d2012-12-11 21:42:5322// Delay, in seconds, before we should open the State Store database. We
23// defer it to avoid slowing down startup. See http://crbug.com/161848
[email protected]87093442013-01-12 16:34:0524const int kInitDelaySeconds = 1;
[email protected]ebaa018d2012-12-11 21:42:5325
[email protected]90e800c2012-06-12 23:11:0026std::string GetFullKey(const std::string& extension_id,
27 const std::string& key) {
28 return extension_id + "." + key;
29}
30
31} // namespace
32
33namespace extensions {
34
[email protected]ebaa018d2012-12-11 21:42:5335// Helper class to delay tasks until we're ready to start executing them.
36class StateStore::DelayedTaskQueue {
37 public:
38 DelayedTaskQueue() : ready_(false) {}
39 ~DelayedTaskQueue() {}
40
41 // Queues up a task for invoking once we're ready. Invokes immediately if
42 // we're already ready.
43 void InvokeWhenReady(base::Closure task);
44
45 // Marks us ready, and invokes all pending tasks.
46 void SetReady();
47
[email protected]c6ea4b42014-03-10 23:25:1148 // Return whether or not the DelayedTaskQueue is |ready_|.
49 bool ready() const { return ready_; }
50
[email protected]ebaa018d2012-12-11 21:42:5351 private:
52 bool ready_;
53 std::vector<base::Closure> pending_tasks_;
54};
55
56void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
57 if (ready_) {
58 task.Run();
59 } else {
60 pending_tasks_.push_back(task);
61 }
62}
63
64void StateStore::DelayedTaskQueue::SetReady() {
65 ready_ = true;
66
67 for (size_t i = 0; i < pending_tasks_.size(); ++i)
68 pending_tasks_[i].Run();
69 pending_tasks_.clear();
70}
71
[email protected]daf3ffda2014-06-25 06:44:5772StateStore::StateStore(content::BrowserContext* context,
cmumford6ae8d462016-03-24 20:35:2773 const scoped_refptr<ValueStoreFactory>& store_factory,
74 ValueStoreFrontend::BackendType backend_type,
[email protected]a690e292012-12-19 19:22:4975 bool deferred_load)
cmumford6ae8d462016-03-24 20:35:2776 : store_(new ValueStoreFrontend(store_factory, backend_type)),
[email protected]3cb79a52014-06-15 04:54:4577 task_queue_(new DelayedTaskQueue()),
78 extension_registry_observer_(this) {
[email protected]daf3ffda2014-06-25 06:44:5779 extension_registry_observer_.Add(ExtensionRegistry::Get(context));
[email protected]ebaa018d2012-12-11 21:42:5380
[email protected]a690e292012-12-19 19:22:4981 if (deferred_load) {
[email protected]479e3922014-07-30 07:12:5782 // Don't Init() until the first page is loaded or the embedder explicitly
83 // requests it.
[email protected]daf3ffda2014-06-25 06:44:5784 registrar_.Add(
85 this,
86 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
87 content::NotificationService::AllBrowserContextsAndSources());
[email protected]a690e292012-12-19 19:22:4988 } else {
[email protected]87093442013-01-12 16:34:0589 Init();
[email protected]a690e292012-12-19 19:22:4990 }
[email protected]90e800c2012-06-12 23:11:0091}
92
[email protected]90e800c2012-06-12 23:11:0093StateStore::~StateStore() {
94}
95
[email protected]479e3922014-07-30 07:12:5796void StateStore::RequestInitAfterDelay() {
97 InitAfterDelay();
98}
99
[email protected]90e800c2012-06-12 23:11:00100void StateStore::RegisterKey(const std::string& key) {
101 registered_keys_.insert(key);
102}
103
104void StateStore::GetExtensionValue(const std::string& extension_id,
105 const std::string& key,
106 ReadCallback callback) {
cmumford6ae8d462016-03-24 20:35:27107 task_queue_->InvokeWhenReady(
108 base::Bind(&ValueStoreFrontend::Get, base::Unretained(store_.get()),
109 GetFullKey(extension_id, key), callback));
[email protected]90e800c2012-06-12 23:11:00110}
111
[email protected]daf3ffda2014-06-25 06:44:57112void StateStore::SetExtensionValue(const std::string& extension_id,
113 const std::string& key,
114 scoped_ptr<base::Value> value) {
cmumford6ae8d462016-03-24 20:35:27115 task_queue_->InvokeWhenReady(
116 base::Bind(&ValueStoreFrontend::Set, base::Unretained(store_.get()),
117 GetFullKey(extension_id, key), base::Passed(&value)));
[email protected]90e800c2012-06-12 23:11:00118}
119
[email protected]a690e292012-12-19 19:22:49120void StateStore::RemoveExtensionValue(const std::string& extension_id,
121 const std::string& key) {
[email protected]daf3ffda2014-06-25 06:44:57122 task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
cmumford6ae8d462016-03-24 20:35:27123 base::Unretained(store_.get()),
[email protected]daf3ffda2014-06-25 06:44:57124 GetFullKey(extension_id, key)));
[email protected]a690e292012-12-19 19:22:49125}
126
[email protected]daf3ffda2014-06-25 06:44:57127bool StateStore::IsInitialized() const {
128 return task_queue_->ready();
129}
[email protected]c6ea4b42014-03-10 23:25:11130
[email protected]90e800c2012-06-12 23:11:00131void StateStore::Observe(int type,
132 const content::NotificationSource& source,
133 const content::NotificationDetails& details) {
[email protected]479e3922014-07-30 07:12:57134 DCHECK_EQ(type, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME);
[email protected]3cb79a52014-06-15 04:54:45135 registrar_.RemoveAll();
[email protected]479e3922014-07-30 07:12:57136 InitAfterDelay();
[email protected]3cb79a52014-06-15 04:54:45137}
138
139void StateStore::OnExtensionWillBeInstalled(
140 content::BrowserContext* browser_context,
141 const Extension* extension,
142 bool is_update,
[email protected]3cb79a52014-06-15 04:54:45143 const std::string& old_name) {
144 RemoveKeysForExtension(extension->id());
145}
146
147void StateStore::OnExtensionUninstalled(
148 content::BrowserContext* browser_context,
[email protected]e43c61f2014-07-20 21:46:34149 const Extension* extension,
150 extensions::UninstallReason reason) {
[email protected]3cb79a52014-06-15 04:54:45151 RemoveKeysForExtension(extension->id());
[email protected]a690e292012-12-19 19:22:49152}
[email protected]90e800c2012-06-12 23:11:00153
[email protected]87093442013-01-12 16:34:05154void StateStore::Init() {
[email protected]479e3922014-07-30 07:12:57155 // Could be called twice if InitAfterDelay() is requested explicitly by the
156 // embedder in addition to internally after first page load.
157 if (IsInitialized())
158 return;
159
cmumford6ae8d462016-03-24 20:35:27160 // TODO(cmumford): The store now always lazily initializes upon first access.
161 // A follow-on CL will remove this deferred initialization implementation
162 // which is now vestigial.
[email protected]87093442013-01-12 16:34:05163 task_queue_->SetReady();
164}
165
[email protected]479e3922014-07-30 07:12:57166void StateStore::InitAfterDelay() {
167 if (IsInitialized())
168 return;
169
170 base::MessageLoop::current()->PostDelayedTask(
171 FROM_HERE,
172 base::Bind(&StateStore::Init, AsWeakPtr()),
173 base::TimeDelta::FromSeconds(kInitDelaySeconds));
174}
175
[email protected]a690e292012-12-19 19:22:49176void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
[email protected]90e800c2012-06-12 23:11:00177 for (std::set<std::string>::iterator key = registered_keys_.begin();
[email protected]daf3ffda2014-06-25 06:44:57178 key != registered_keys_.end();
179 ++key) {
180 task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
cmumford6ae8d462016-03-24 20:35:27181 base::Unretained(store_.get()),
[email protected]daf3ffda2014-06-25 06:44:57182 GetFullKey(extension_id, *key)));
[email protected]90e800c2012-06-12 23:11:00183 }
184}
185
[email protected]90e800c2012-06-12 23:11:00186} // namespace extensions