blob: e31333732f564bcc6a2c320fece235c146e588f2 [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"
fdoraye6609ac82016-06-06 19:21:4012#include "base/location.h"
13#include "base/single_thread_task_runner.h"
14#include "base/threading/thread_task_runner_handle.h"
[email protected]daf3ffda2014-06-25 06:44:5715#include "content/public/browser/browser_context.h"
[email protected]90e800c2012-06-12 23:11:0016#include "content/public/browser/notification_service.h"
17#include "content/public/browser/notification_types.h"
[email protected]3cb79a52014-06-15 04:54:4518#include "extensions/browser/extension_registry.h"
cmumford6ae8d462016-03-24 20:35:2719#include "extensions/browser/value_store/value_store_factory.h"
[email protected]e4452d32013-11-15 23:07:4120#include "extensions/common/extension.h"
[email protected]90e800c2012-06-12 23:11:0021
22namespace {
23
[email protected]ebaa018d2012-12-11 21:42:5324// Delay, in seconds, before we should open the State Store database. We
25// defer it to avoid slowing down startup. See http://crbug.com/161848
[email protected]87093442013-01-12 16:34:0526const int kInitDelaySeconds = 1;
[email protected]ebaa018d2012-12-11 21:42:5327
[email protected]90e800c2012-06-12 23:11:0028std::string GetFullKey(const std::string& extension_id,
29 const std::string& key) {
30 return extension_id + "." + key;
31}
32
33} // namespace
34
35namespace extensions {
36
[email protected]ebaa018d2012-12-11 21:42:5337// Helper class to delay tasks until we're ready to start executing them.
38class StateStore::DelayedTaskQueue {
39 public:
40 DelayedTaskQueue() : ready_(false) {}
41 ~DelayedTaskQueue() {}
42
43 // Queues up a task for invoking once we're ready. Invokes immediately if
44 // we're already ready.
rdevlin.cronin0a0942f2016-07-08 22:22:3545 void InvokeWhenReady(const base::Closure& task);
[email protected]ebaa018d2012-12-11 21:42:5346
47 // Marks us ready, and invokes all pending tasks.
48 void SetReady();
49
[email protected]c6ea4b42014-03-10 23:25:1150 // Return whether or not the DelayedTaskQueue is |ready_|.
51 bool ready() const { return ready_; }
52
[email protected]ebaa018d2012-12-11 21:42:5353 private:
54 bool ready_;
55 std::vector<base::Closure> pending_tasks_;
56};
57
rdevlin.cronin0a0942f2016-07-08 22:22:3558void StateStore::DelayedTaskQueue::InvokeWhenReady(const base::Closure& task) {
[email protected]ebaa018d2012-12-11 21:42:5359 if (ready_) {
60 task.Run();
61 } else {
62 pending_tasks_.push_back(task);
63 }
64}
65
66void StateStore::DelayedTaskQueue::SetReady() {
67 ready_ = true;
68
69 for (size_t i = 0; i < pending_tasks_.size(); ++i)
70 pending_tasks_[i].Run();
71 pending_tasks_.clear();
72}
73
[email protected]daf3ffda2014-06-25 06:44:5774StateStore::StateStore(content::BrowserContext* context,
cmumford6ae8d462016-03-24 20:35:2775 const scoped_refptr<ValueStoreFactory>& store_factory,
76 ValueStoreFrontend::BackendType backend_type,
[email protected]a690e292012-12-19 19:22:4977 bool deferred_load)
cmumford6ae8d462016-03-24 20:35:2778 : store_(new ValueStoreFrontend(store_factory, backend_type)),
[email protected]3cb79a52014-06-15 04:54:4579 task_queue_(new DelayedTaskQueue()),
80 extension_registry_observer_(this) {
[email protected]daf3ffda2014-06-25 06:44:5781 extension_registry_observer_.Add(ExtensionRegistry::Get(context));
[email protected]ebaa018d2012-12-11 21:42:5382
[email protected]a690e292012-12-19 19:22:4983 if (deferred_load) {
[email protected]479e3922014-07-30 07:12:5784 // Don't Init() until the first page is loaded or the embedder explicitly
85 // requests it.
[email protected]daf3ffda2014-06-25 06:44:5786 registrar_.Add(
87 this,
88 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
89 content::NotificationService::AllBrowserContextsAndSources());
[email protected]a690e292012-12-19 19:22:4990 } else {
[email protected]87093442013-01-12 16:34:0591 Init();
[email protected]a690e292012-12-19 19:22:4992 }
[email protected]90e800c2012-06-12 23:11:0093}
94
[email protected]90e800c2012-06-12 23:11:0095StateStore::~StateStore() {
96}
97
[email protected]479e3922014-07-30 07:12:5798void StateStore::RequestInitAfterDelay() {
99 InitAfterDelay();
100}
101
[email protected]90e800c2012-06-12 23:11:00102void 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) {
cmumford6ae8d462016-03-24 20:35:27109 task_queue_->InvokeWhenReady(
110 base::Bind(&ValueStoreFrontend::Get, base::Unretained(store_.get()),
111 GetFullKey(extension_id, key), callback));
[email protected]90e800c2012-06-12 23:11:00112}
113
[email protected]daf3ffda2014-06-25 06:44:57114void StateStore::SetExtensionValue(const std::string& extension_id,
115 const std::string& key,
dchengf5d241082016-04-21 03:43:11116 std::unique_ptr<base::Value> value) {
cmumford6ae8d462016-03-24 20:35:27117 task_queue_->InvokeWhenReady(
118 base::Bind(&ValueStoreFrontend::Set, base::Unretained(store_.get()),
119 GetFullKey(extension_id, key), base::Passed(&value)));
[email protected]90e800c2012-06-12 23:11:00120}
121
[email protected]a690e292012-12-19 19:22:49122void StateStore::RemoveExtensionValue(const std::string& extension_id,
123 const std::string& key) {
[email protected]daf3ffda2014-06-25 06:44:57124 task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
cmumford6ae8d462016-03-24 20:35:27125 base::Unretained(store_.get()),
[email protected]daf3ffda2014-06-25 06:44:57126 GetFullKey(extension_id, key)));
[email protected]a690e292012-12-19 19:22:49127}
128
[email protected]daf3ffda2014-06-25 06:44:57129bool StateStore::IsInitialized() const {
130 return task_queue_->ready();
131}
[email protected]c6ea4b42014-03-10 23:25:11132
[email protected]90e800c2012-06-12 23:11:00133void StateStore::Observe(int type,
134 const content::NotificationSource& source,
135 const content::NotificationDetails& details) {
[email protected]479e3922014-07-30 07:12:57136 DCHECK_EQ(type, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME);
[email protected]3cb79a52014-06-15 04:54:45137 registrar_.RemoveAll();
[email protected]479e3922014-07-30 07:12:57138 InitAfterDelay();
[email protected]3cb79a52014-06-15 04:54:45139}
140
141void StateStore::OnExtensionWillBeInstalled(
142 content::BrowserContext* browser_context,
143 const Extension* extension,
144 bool is_update,
[email protected]3cb79a52014-06-15 04:54:45145 const std::string& old_name) {
146 RemoveKeysForExtension(extension->id());
147}
148
149void StateStore::OnExtensionUninstalled(
150 content::BrowserContext* browser_context,
[email protected]e43c61f2014-07-20 21:46:34151 const Extension* extension,
152 extensions::UninstallReason reason) {
[email protected]3cb79a52014-06-15 04:54:45153 RemoveKeysForExtension(extension->id());
[email protected]a690e292012-12-19 19:22:49154}
[email protected]90e800c2012-06-12 23:11:00155
[email protected]87093442013-01-12 16:34:05156void StateStore::Init() {
[email protected]479e3922014-07-30 07:12:57157 // Could be called twice if InitAfterDelay() is requested explicitly by the
158 // embedder in addition to internally after first page load.
159 if (IsInitialized())
160 return;
161
cmumford6ae8d462016-03-24 20:35:27162 // TODO(cmumford): The store now always lazily initializes upon first access.
163 // A follow-on CL will remove this deferred initialization implementation
164 // which is now vestigial.
[email protected]87093442013-01-12 16:34:05165 task_queue_->SetReady();
166}
167
[email protected]479e3922014-07-30 07:12:57168void StateStore::InitAfterDelay() {
169 if (IsInitialized())
170 return;
171
fdoraye6609ac82016-06-06 19:21:40172 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
173 FROM_HERE, base::Bind(&StateStore::Init, AsWeakPtr()),
[email protected]479e3922014-07-30 07:12:57174 base::TimeDelta::FromSeconds(kInitDelaySeconds));
175}
176
[email protected]a690e292012-12-19 19:22:49177void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
[email protected]90e800c2012-06-12 23:11:00178 for (std::set<std::string>::iterator key = registered_keys_.begin();
[email protected]daf3ffda2014-06-25 06:44:57179 key != registered_keys_.end();
180 ++key) {
181 task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
cmumford6ae8d462016-03-24 20:35:27182 base::Unretained(store_.get()),
[email protected]daf3ffda2014-06-25 06:44:57183 GetFullKey(extension_id, *key)));
[email protected]90e800c2012-06-12 23:11:00184 }
185}
186
[email protected]90e800c2012-06-12 23:11:00187} // namespace extensions