1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/browser/state_store.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/browser/browser_context.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_types.h"
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Delay, in seconds, before we should open the State Store database. We
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// defer it to avoid slowing down startup. See http://crbug.com/161848
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kInitDelaySeconds = 1;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetFullKey(const std::string& extension_id,
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::string& key) {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extension_id + "." + key;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Helper class to delay tasks until we're ready to start executing them.
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class StateStore::DelayedTaskQueue {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DelayedTaskQueue() : ready_(false) {}
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ~DelayedTaskQueue() {}
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Queues up a task for invoking once we're ready. Invokes immediately if
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // we're already ready.
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void InvokeWhenReady(base::Closure task);
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Marks us ready, and invokes all pending tasks.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SetReady();
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Return whether or not the DelayedTaskQueue is |ready_|.
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool ready() const { return ready_; }
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool ready_;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::Closure> pending_tasks_;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ready_) {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    task.Run();
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pending_tasks_.push_back(task);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StateStore::DelayedTaskQueue::SetReady() {
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ready_ = true;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < pending_tasks_.size(); ++i)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pending_tasks_[i].Run();
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pending_tasks_.clear();
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
67116680a4aac90f2aa7413d9095a592090648e557Ben MurdochStateStore::StateStore(content::BrowserContext* context,
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       const base::FilePath& db_path,
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       bool deferred_load)
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : db_path_(db_path),
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      task_queue_(new DelayedTaskQueue()),
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      extension_registry_observer_(this) {
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  extension_registry_observer_.Add(ExtensionRegistry::Get(context));
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (deferred_load) {
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Don't Init() until the first page is loaded or the embedder explicitly
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // requests it.
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    registrar_.Add(
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this,
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        content::NotificationService::AllBrowserContextsAndSources());
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Init();
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
87116680a4aac90f2aa7413d9095a592090648e557Ben MurdochStateStore::StateStore(content::BrowserContext* context,
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       scoped_ptr<ValueStore> value_store)
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : store_(value_store.Pass()),
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      task_queue_(new DelayedTaskQueue()),
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      extension_registry_observer_(this) {
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  extension_registry_observer_.Add(ExtensionRegistry::Get(context));
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This constructor is for testing. No need to delay Init.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Init();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StateStore::~StateStore() {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void StateStore::RequestInitAfterDelay() {
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  InitAfterDelay();
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StateStore::RegisterKey(const std::string& key) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registered_keys_.insert(key);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StateStore::GetExtensionValue(const std::string& extension_id,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const std::string& key,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   ReadCallback callback) {
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Get,
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          base::Unretained(&store_),
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          GetFullKey(extension_id, key),
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          callback));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid StateStore::SetExtensionValue(const std::string& extension_id,
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   const std::string& key,
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   scoped_ptr<base::Value> value) {
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Set,
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          base::Unretained(&store_),
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          GetFullKey(extension_id, key),
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          base::Passed(&value)));
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StateStore::RemoveExtensionValue(const std::string& extension_id,
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& key) {
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          base::Unretained(&store_),
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          GetFullKey(extension_id, key)));
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool StateStore::IsInitialized() const {
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return task_queue_->ready();
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StateStore::Observe(int type,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const content::NotificationSource& source,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const content::NotificationDetails& details) {
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(type, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME);
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  registrar_.RemoveAll();
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  InitAfterDelay();
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void StateStore::OnExtensionWillBeInstalled(
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    content::BrowserContext* browser_context,
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const Extension* extension,
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    bool is_update,
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    bool from_ephemeral,
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& old_name) {
152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RemoveKeysForExtension(extension->id());
153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void StateStore::OnExtensionUninstalled(
156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    content::BrowserContext* browser_context,
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const Extension* extension,
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    extensions::UninstallReason reason) {
159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  RemoveKeysForExtension(extension->id());
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StateStore::Init() {
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Could be called twice if InitAfterDelay() is requested explicitly by the
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // embedder in addition to internally after first page load.
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (IsInitialized())
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!db_path_.empty())
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    store_.Init(db_path_);
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  task_queue_->SetReady();
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void StateStore::InitAfterDelay() {
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (IsInitialized())
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&StateStore::Init, AsWeakPtr()),
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::TimeDelta::FromSeconds(kInitDelaySeconds));
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<std::string>::iterator key = registered_keys_.begin();
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       key != registered_keys_.end();
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++key) {
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                            base::Unretained(&store_),
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                            GetFullKey(extension_id, *key)));
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
194