Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/state_store.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "chrome/browser/chrome_notification_types.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "content/public/browser/notification_service.h"
     12 #include "content/public/browser/notification_types.h"
     13 #include "extensions/browser/extension_registry.h"
     14 #include "extensions/common/extension.h"
     15 
     16 namespace {
     17 
     18 // Delay, in seconds, before we should open the State Store database. We
     19 // defer it to avoid slowing down startup. See http://crbug.com/161848
     20 const int kInitDelaySeconds = 1;
     21 
     22 std::string GetFullKey(const std::string& extension_id,
     23                        const std::string& key) {
     24   return extension_id + "." + key;
     25 }
     26 
     27 }  // namespace
     28 
     29 namespace extensions {
     30 
     31 // Helper class to delay tasks until we're ready to start executing them.
     32 class StateStore::DelayedTaskQueue {
     33  public:
     34   DelayedTaskQueue() : ready_(false) {}
     35   ~DelayedTaskQueue() {}
     36 
     37   // Queues up a task for invoking once we're ready. Invokes immediately if
     38   // we're already ready.
     39   void InvokeWhenReady(base::Closure task);
     40 
     41   // Marks us ready, and invokes all pending tasks.
     42   void SetReady();
     43 
     44   // Return whether or not the DelayedTaskQueue is |ready_|.
     45   bool ready() const { return ready_; }
     46 
     47  private:
     48   bool ready_;
     49   std::vector<base::Closure> pending_tasks_;
     50 };
     51 
     52 void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
     53   if (ready_) {
     54     task.Run();
     55   } else {
     56     pending_tasks_.push_back(task);
     57   }
     58 }
     59 
     60 void StateStore::DelayedTaskQueue::SetReady() {
     61   ready_ = true;
     62 
     63   for (size_t i = 0; i < pending_tasks_.size(); ++i)
     64     pending_tasks_[i].Run();
     65   pending_tasks_.clear();
     66 }
     67 
     68 StateStore::StateStore(Profile* profile,
     69                        const base::FilePath& db_path,
     70                        bool deferred_load)
     71     : db_path_(db_path),
     72       task_queue_(new DelayedTaskQueue()),
     73       extension_registry_observer_(this) {
     74   extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
     75 
     76   if (deferred_load) {
     77     // Don't Init until the first page is loaded or the session restored.
     78     registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
     79                    content::NotificationService::
     80                        AllBrowserContextsAndSources());
     81     registrar_.Add(this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
     82                    content::NotificationService::
     83                        AllBrowserContextsAndSources());
     84   } else {
     85     Init();
     86   }
     87 }
     88 
     89 StateStore::StateStore(Profile* profile, scoped_ptr<ValueStore> value_store)
     90     : store_(value_store.Pass()),
     91       task_queue_(new DelayedTaskQueue()),
     92       extension_registry_observer_(this) {
     93   extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
     94 
     95   // This constructor is for testing. No need to delay Init.
     96   Init();
     97 }
     98 
     99 StateStore::~StateStore() {
    100 }
    101 
    102 void StateStore::RegisterKey(const std::string& key) {
    103   registered_keys_.insert(key);
    104 }
    105 
    106 void StateStore::GetExtensionValue(const std::string& extension_id,
    107                                    const std::string& key,
    108                                    ReadCallback callback) {
    109   task_queue_->InvokeWhenReady(
    110       base::Bind(&ValueStoreFrontend::Get, base::Unretained(&store_),
    111                  GetFullKey(extension_id, key), callback));
    112 }
    113 
    114 void StateStore::SetExtensionValue(
    115     const std::string& extension_id,
    116     const std::string& key,
    117     scoped_ptr<base::Value> value) {
    118   task_queue_->InvokeWhenReady(
    119       base::Bind(&ValueStoreFrontend::Set, base::Unretained(&store_),
    120                  GetFullKey(extension_id, key), base::Passed(&value)));
    121 }
    122 
    123 void StateStore::RemoveExtensionValue(const std::string& extension_id,
    124                                       const std::string& key) {
    125   task_queue_->InvokeWhenReady(
    126       base::Bind(&ValueStoreFrontend::Remove, base::Unretained(&store_),
    127                  GetFullKey(extension_id, key)));
    128 }
    129 
    130 bool StateStore::IsInitialized() const { return task_queue_->ready(); }
    131 
    132 void StateStore::Observe(int type,
    133                          const content::NotificationSource& source,
    134                          const content::NotificationDetails& details) {
    135   DCHECK(type == chrome::NOTIFICATION_SESSION_RESTORE_DONE ||
    136          type == content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME);
    137   registrar_.RemoveAll();
    138 
    139   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
    140       base::Bind(&StateStore::Init, AsWeakPtr()),
    141       base::TimeDelta::FromSeconds(kInitDelaySeconds));
    142 }
    143 
    144 void StateStore::OnExtensionWillBeInstalled(
    145     content::BrowserContext* browser_context,
    146     const Extension* extension,
    147     bool is_update,
    148     bool from_ephemeral,
    149     const std::string& old_name) {
    150   RemoveKeysForExtension(extension->id());
    151 }
    152 
    153 void StateStore::OnExtensionUninstalled(
    154     content::BrowserContext* browser_context,
    155     const Extension* extension) {
    156   RemoveKeysForExtension(extension->id());
    157 }
    158 
    159 void StateStore::Init() {
    160   if (!db_path_.empty())
    161     store_.Init(db_path_);
    162   task_queue_->SetReady();
    163 }
    164 
    165 void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
    166   for (std::set<std::string>::iterator key = registered_keys_.begin();
    167        key != registered_keys_.end(); ++key) {
    168     task_queue_->InvokeWhenReady(
    169         base::Bind(&ValueStoreFrontend::Remove, base::Unretained(&store_),
    170                    GetFullKey(extension_id, *key)));
    171   }
    172 }
    173 
    174 }  // namespace extensions
    175