Home | History | Annotate | Download | only in declarative
      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 #ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_RULES_REGISTRY_WITH_CACHE_H__
      6 #define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_RULES_REGISTRY_WITH_CACHE_H__
      7 
      8 #include "chrome/browser/extensions/api/declarative/rules_registry.h"
      9 
     10 #include <map>
     11 #include <set>
     12 #include <string>
     13 #include <vector>
     14 
     15 #include "base/compiler_specific.h"
     16 #include "base/callback_forward.h"
     17 #include "base/gtest_prod_util.h"
     18 #include "base/memory/scoped_ptr.h"
     19 #include "base/memory/weak_ptr.h"
     20 #include "content/public/browser/notification_observer.h"
     21 #include "content/public/browser/notification_registrar.h"
     22 #include "extensions/common/one_shot_event.h"
     23 
     24 class Profile;
     25 
     26 namespace base {
     27 class Value;
     28 }  // namespace base
     29 
     30 namespace extensions {
     31 
     32 // A base class for RulesRegistries that takes care of storing the
     33 // RulesRegistry::Rule objects. It contains all the methods that need to run on
     34 // the registry thread; methods that need to run on the UI thread are separated
     35 // in the RuleStorageOnUI object.
     36 class RulesRegistryWithCache : public RulesRegistry {
     37  public:
     38   // RuleStorageOnUI implements the part of the RulesRegistry which works on
     39   // the UI thread. It should only be used on the UI thread. It gets created
     40   // by the RulesRegistry, but right after that it changes owner to the
     41   // RulesRegistryService, and is deleted by the service.
     42   // If |log_storage_init_delay| is set, the delay caused by loading and
     43   // registering rules on initialization will be logged with UMA.
     44   class RuleStorageOnUI : public content::NotificationObserver {
     45    public:
     46     // This key is used to store in preferences whether there are some
     47     // declarative rules stored in the rule store.
     48     static const char kRulesStoredKey[];
     49 
     50     RuleStorageOnUI(Profile* profile,
     51                     const std::string& storage_key,
     52                     content::BrowserThread::ID rules_registry_thread,
     53                     base::WeakPtr<RulesRegistryWithCache> registry,
     54                     bool log_storage_init_delay);
     55 
     56     virtual ~RuleStorageOnUI();
     57 
     58     // Initialize the storage functionality.
     59     void Init();
     60 
     61     void WriteToStorage(const std::string& extension_id,
     62                         scoped_ptr<base::Value> value);
     63 
     64     base::WeakPtr<RuleStorageOnUI> GetWeakPtr() {
     65       DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
     66       return weak_ptr_factory_.GetWeakPtr();
     67     }
     68 
     69    private:
     70     FRIEND_TEST_ALL_PREFIXES(RulesRegistryWithCacheTest,
     71                              DeclarativeRulesStored);
     72 
     73     // NotificationObserver
     74     virtual void Observe(int type,
     75                          const content::NotificationSource& source,
     76                          const content::NotificationDetails& details) OVERRIDE;
     77 
     78     // Check if we are done reading all data from storage on startup, and notify
     79     // the RulesRegistry on its thread if so. The notification is delivered
     80     // exactly once.
     81     void CheckIfReady();
     82 
     83     // Read/write a list of rules serialized to Values.
     84     void ReadFromStorage(const std::string& extension_id);
     85     void ReadFromStorageCallback(const std::string& extension_id,
     86                                  scoped_ptr<base::Value> value);
     87 
     88     // Check the preferences whether the extension with |extension_id| has some
     89     // rules stored on disk. If this information is not in the preferences, true
     90     // is returned as a safe default value.
     91     bool GetDeclarativeRulesStored(const std::string& extension_id) const;
     92     // Modify the preference to |rules_stored|.
     93     void SetDeclarativeRulesStored(const std::string& extension_id,
     94                                    bool rules_stored);
     95 
     96     content::NotificationRegistrar registrar_;
     97 
     98     Profile* profile_;
     99 
    100     // The key under which rules are stored.
    101     const std::string storage_key_;
    102 
    103     // A set of extension IDs that have rules we are reading from storage.
    104     std::set<std::string> waiting_for_extensions_;
    105 
    106     // We measure the time spent on loading rules on init. The result is logged
    107     // with UMA once per each RuleStorageOnUI instance, unless in Incognito.
    108     base::Time storage_init_time_;
    109     bool log_storage_init_delay_;
    110 
    111     // Weak pointer to post tasks to the owning rules registry.
    112     const base::WeakPtr<RulesRegistryWithCache> registry_;
    113 
    114     // The thread |registry_| lives on.
    115     const content::BrowserThread::ID rules_registry_thread_;
    116 
    117     // We notified the RulesRegistry that the rules are loaded.
    118     bool notified_registry_;
    119 
    120     // Use this factory to generate weak pointers bound to the UI thread.
    121     base::WeakPtrFactory<RuleStorageOnUI> weak_ptr_factory_;
    122   };
    123 
    124   // After the RuleStorageOnUI object (the part of the registry which runs on
    125   // the UI thread) is created, a pointer to it is passed to |*ui_part|.
    126   // If |log_storage_init_delay| is set, the delay caused by loading and
    127   // registering rules on initialization will be logged with UMA.
    128   // In tests, |profile| and |ui_part| can be NULL (at the same time). In that
    129   // case the storage functionality disabled (no RuleStorageOnUI object
    130   // created) and the |log_storage_init_delay| flag is ignored.
    131   RulesRegistryWithCache(Profile* profile,
    132                          const char* event_name,
    133                          content::BrowserThread::ID owner_thread,
    134                          bool log_storage_init_delay,
    135                          scoped_ptr<RuleStorageOnUI>* ui_part);
    136 
    137   const OneShotEvent& ready() const {
    138     return ready_;
    139   }
    140 
    141   // RulesRegistry implementation:
    142   virtual std::string AddRules(
    143       const std::string& extension_id,
    144       const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) OVERRIDE;
    145   virtual std::string RemoveRules(
    146       const std::string& extension_id,
    147       const std::vector<std::string>& rule_identifiers) OVERRIDE;
    148   virtual std::string RemoveAllRules(
    149       const std::string& extension_id) OVERRIDE;
    150   virtual std::string GetRules(
    151       const std::string& extension_id,
    152       const std::vector<std::string>& rule_identifiers,
    153       std::vector<linked_ptr<RulesRegistry::Rule> >* out) OVERRIDE;
    154   virtual std::string GetAllRules(
    155       const std::string& extension_id,
    156       std::vector<linked_ptr<RulesRegistry::Rule> >* out) OVERRIDE;
    157   virtual void OnExtensionUnloaded(const std::string& extension_id) OVERRIDE;
    158 
    159  protected:
    160   virtual ~RulesRegistryWithCache();
    161 
    162   // These functions need to provide the same functionality as their
    163   // RulesRegistry counterparts. They need to be atomic.
    164   virtual std::string AddRulesImpl(
    165       const std::string& extension_id,
    166       const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) = 0;
    167   virtual std::string RemoveRulesImpl(
    168       const std::string& extension_id,
    169       const std::vector<std::string>& rule_identifiers) = 0;
    170   virtual std::string RemoveAllRulesImpl(
    171       const std::string& extension_id) = 0;
    172 
    173  private:
    174   typedef std::string ExtensionId;
    175   typedef std::string RuleId;
    176   typedef std::pair<ExtensionId, RuleId> RulesDictionaryKey;
    177   typedef std::map<RulesDictionaryKey, linked_ptr<RulesRegistry::Rule> >
    178       RulesDictionary;
    179   enum ProcessChangedRulesState {
    180     // ProcessChangedRules can never be called, |storage_on_ui_| is NULL.
    181     NEVER_PROCESS,
    182     // A task to call ProcessChangedRules is scheduled for future execution.
    183     SCHEDULED_FOR_PROCESSING,
    184     // No task to call ProcessChangedRules is scheduled yet, but it is possible
    185     // to schedule one.
    186     NOT_SCHEDULED_FOR_PROCESSING
    187   };
    188 
    189   // Common processing after extension's rules have changed.
    190   void ProcessChangedRules(const std::string& extension_id);
    191 
    192   // Calls ProcessChangedRules if |process_changed_rules_requested_| ==
    193   // NOT_SCHEDULED_FOR_PROCESSING.
    194   void MaybeProcessChangedRules(const std::string& extension_id);
    195 
    196   // Process the callbacks once the registry gets ready.
    197   void MarkReady(base::Time storage_init_time);
    198 
    199   // Deserialize the rules from the given Value object and add them to the
    200   // RulesRegistry.
    201   void DeserializeAndAddRules(const std::string& extension_id,
    202                               scoped_ptr<base::Value> rules);
    203 
    204 
    205   RulesDictionary rules_;
    206 
    207   // Signaled when we have finished reading from storage for all extensions that
    208   // are loaded on startup.
    209   OneShotEvent ready_;
    210 
    211   // The factory needs to be declared before |storage_on_ui_|, so that it can
    212   // produce a pointer as a construction argument for |storage_on_ui_|.
    213   base::WeakPtrFactory<RulesRegistryWithCache> weak_ptr_factory_;
    214 
    215   // |storage_on_ui_| is owned by the registry service. If |storage_on_ui_| is
    216   // NULL, then the storage functionality is disabled (this is used in tests).
    217   // This registry cannot own |storage_on_ui_| because during the time after
    218   // rules registry service shuts down on UI thread, and the registry is
    219   // destroyed on its thread, the use of the |storage_on_ui_| would not be
    220   // safe. The registry only ever associates with one RuleStorageOnUI instance.
    221   const base::WeakPtr<RuleStorageOnUI> storage_on_ui_;
    222 
    223   ProcessChangedRulesState process_changed_rules_requested_;
    224 
    225   DISALLOW_COPY_AND_ASSIGN(RulesRegistryWithCache);
    226 };
    227 
    228 }  // namespace extensions
    229 
    230 #endif  // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_RULES_REGISTRY_WITH_CACHE_H__
    231