diff options
Diffstat (limited to 'extensions/browser/state_store.cc')
-rw-r--r-- | extensions/browser/state_store.cc | 182 |
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 |