summaryrefslogtreecommitdiffstats
path: root/extensions/browser/state_store.cc
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/browser/state_store.cc')
-rw-r--r--extensions/browser/state_store.cc182
1 files changed, 182 insertions, 0 deletions
diff --git a/extensions/browser/state_store.cc b/extensions/browser/state_store.cc
new file mode 100644
index 0000000..ced256a
--- /dev/null
+++ b/extensions/browser/state_store.cc
@@ -0,0 +1,182 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/state_store.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/extension.h"
+
+namespace {
+
+// Delay, in seconds, before we should open the State Store database. We
+// defer it to avoid slowing down startup. See http://crbug.com/161848
+const int kInitDelaySeconds = 1;
+
+std::string GetFullKey(const std::string& extension_id,
+ const std::string& key) {
+ return extension_id + "." + key;
+}
+
+} // namespace
+
+namespace extensions {
+
+// Helper class to delay tasks until we're ready to start executing them.
+class StateStore::DelayedTaskQueue {
+ public:
+ DelayedTaskQueue() : ready_(false) {}
+ ~DelayedTaskQueue() {}
+
+ // Queues up a task for invoking once we're ready. Invokes immediately if
+ // we're already ready.
+ void InvokeWhenReady(base::Closure task);
+
+ // Marks us ready, and invokes all pending tasks.
+ void SetReady();
+
+ // Return whether or not the DelayedTaskQueue is |ready_|.
+ bool ready() const { return ready_; }
+
+ private:
+ bool ready_;
+ std::vector<base::Closure> pending_tasks_;
+};
+
+void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
+ if (ready_) {
+ task.Run();
+ } else {
+ pending_tasks_.push_back(task);
+ }
+}
+
+void StateStore::DelayedTaskQueue::SetReady() {
+ ready_ = true;
+
+ for (size_t i = 0; i < pending_tasks_.size(); ++i)
+ pending_tasks_[i].Run();
+ pending_tasks_.clear();
+}
+
+StateStore::StateStore(content::BrowserContext* context,
+ const base::FilePath& db_path,
+ bool deferred_load)
+ : db_path_(db_path),
+ task_queue_(new DelayedTaskQueue()),
+ extension_registry_observer_(this) {
+ extension_registry_observer_.Add(ExtensionRegistry::Get(context));
+
+ if (deferred_load) {
+ // Don't Init until the first page is loaded or the session restored.
+ registrar_.Add(
+ this,
+ content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+ content::NotificationService::AllBrowserContextsAndSources());
+ registrar_.Add(
+ this,
+ chrome::NOTIFICATION_SESSION_RESTORE_DONE,
+ content::NotificationService::AllBrowserContextsAndSources());
+ } else {
+ Init();
+ }
+}
+
+StateStore::StateStore(content::BrowserContext* context,
+ scoped_ptr<ValueStore> value_store)
+ : store_(value_store.Pass()),
+ task_queue_(new DelayedTaskQueue()),
+ extension_registry_observer_(this) {
+ extension_registry_observer_.Add(ExtensionRegistry::Get(context));
+
+ // This constructor is for testing. No need to delay Init.
+ Init();
+}
+
+StateStore::~StateStore() {
+}
+
+void StateStore::RegisterKey(const std::string& key) {
+ registered_keys_.insert(key);
+}
+
+void StateStore::GetExtensionValue(const std::string& extension_id,
+ const std::string& key,
+ ReadCallback callback) {
+ task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Get,
+ base::Unretained(&store_),
+ GetFullKey(extension_id, key),
+ callback));
+}
+
+void StateStore::SetExtensionValue(const std::string& extension_id,
+ const std::string& key,
+ scoped_ptr<base::Value> value) {
+ task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Set,
+ base::Unretained(&store_),
+ GetFullKey(extension_id, key),
+ base::Passed(&value)));
+}
+
+void StateStore::RemoveExtensionValue(const std::string& extension_id,
+ const std::string& key) {
+ task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
+ base::Unretained(&store_),
+ GetFullKey(extension_id, key)));
+}
+
+bool StateStore::IsInitialized() const {
+ return task_queue_->ready();
+}
+
+void StateStore::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK(type == chrome::NOTIFICATION_SESSION_RESTORE_DONE ||
+ type == content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME);
+ registrar_.RemoveAll();
+
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&StateStore::Init, AsWeakPtr()),
+ base::TimeDelta::FromSeconds(kInitDelaySeconds));
+}
+
+void StateStore::OnExtensionWillBeInstalled(
+ content::BrowserContext* browser_context,
+ const Extension* extension,
+ bool is_update,
+ bool from_ephemeral,
+ const std::string& old_name) {
+ RemoveKeysForExtension(extension->id());
+}
+
+void StateStore::OnExtensionUninstalled(
+ content::BrowserContext* browser_context,
+ const Extension* extension) {
+ RemoveKeysForExtension(extension->id());
+}
+
+void StateStore::Init() {
+ if (!db_path_.empty())
+ store_.Init(db_path_);
+ task_queue_->SetReady();
+}
+
+void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
+ for (std::set<std::string>::iterator key = registered_keys_.begin();
+ key != registered_keys_.end();
+ ++key) {
+ task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
+ base::Unretained(&store_),
+ GetFullKey(extension_id, *key)));
+ }
+}
+
+} // namespace extensions