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