OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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/api/declarative/rules_cache_delegate.h" |
| 6 |
| 7 #include "chrome/browser/chrome_notification_types.h" |
| 8 #include "chrome/browser/extensions/api/declarative/rules_registry.h" |
| 9 #include "chrome/browser/extensions/extension_info_map.h" |
| 10 #include "chrome/browser/extensions/extension_service.h" |
| 11 #include "chrome/browser/extensions/extension_system.h" |
| 12 #include "chrome/browser/extensions/extension_util.h" |
| 13 #include "chrome/browser/extensions/state_store.h" |
| 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "content/public/browser/notification_details.h" |
| 16 #include "content/public/browser/notification_source.h" |
| 17 |
| 18 namespace { |
| 19 |
| 20 // Returns the key to use for storing declarative rules in the state store. |
| 21 std::string GetDeclarativeRuleStorageKey(const std::string& event_name, |
| 22 bool incognito) { |
| 23 if (incognito) |
| 24 return "declarative_rules.incognito." + event_name; |
| 25 else |
| 26 return "declarative_rules." + event_name; |
| 27 } |
| 28 |
| 29 } // namespace |
| 30 |
| 31 namespace extensions { |
| 32 |
| 33 // RulesCacheDelegate |
| 34 |
| 35 const char RulesCacheDelegate::kRulesStoredKey[] = |
| 36 "has_declarative_rules"; |
| 37 |
| 38 RulesCacheDelegate::RulesCacheDelegate( |
| 39 Profile* profile, |
| 40 const std::string& event_name, |
| 41 content::BrowserThread::ID rules_registry_thread, |
| 42 base::WeakPtr<RulesRegistry> registry, |
| 43 bool log_storage_init_delay) |
| 44 : profile_(profile), |
| 45 storage_key_(GetDeclarativeRuleStorageKey(event_name, |
| 46 profile->IsOffTheRecord())), |
| 47 rules_stored_key_(GetRulesStoredKey(event_name, |
| 48 profile->IsOffTheRecord())), |
| 49 log_storage_init_delay_(log_storage_init_delay), |
| 50 registry_(registry), |
| 51 rules_registry_thread_(rules_registry_thread), |
| 52 notified_registry_(false), |
| 53 weak_ptr_factory_(this) {} |
| 54 |
| 55 RulesCacheDelegate::~RulesCacheDelegate() {} |
| 56 |
| 57 // Returns the key to use for storing whether the rules have been stored. |
| 58 // static |
| 59 std::string RulesCacheDelegate::GetRulesStoredKey(const std::string& event_name, |
| 60 bool incognito) { |
| 61 std::string result(kRulesStoredKey); |
| 62 result += incognito ? ".incognito." : "."; |
| 63 return result + event_name; |
| 64 } |
| 65 |
| 66 // This is called from the constructor of RulesRegistry, so it is |
| 67 // important that it both |
| 68 // 1. calls no (in particular virtual) methods of the rules registry, and |
| 69 // 2. does not create scoped_refptr holding the registry. (A short-lived |
| 70 // scoped_refptr might delete the rules registry before it is constructed.) |
| 71 void RulesCacheDelegate::Init() { |
| 72 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 73 |
| 74 ExtensionSystem& system = *ExtensionSystem::Get(profile_); |
| 75 extensions::StateStore* store = system.rules_store(); |
| 76 if (store) |
| 77 store->RegisterKey(storage_key_); |
| 78 |
| 79 registrar_.Add(this, |
| 80 chrome::NOTIFICATION_EXTENSION_LOADED, |
| 81 content::Source<Profile>(profile_->GetOriginalProfile())); |
| 82 |
| 83 if (profile_->IsOffTheRecord()) |
| 84 log_storage_init_delay_ = false; |
| 85 |
| 86 system.ready().Post( |
| 87 FROM_HERE, |
| 88 base::Bind(&RulesCacheDelegate::ReadRulesForInstalledExtensions, |
| 89 GetWeakPtr())); |
| 90 system.ready().Post(FROM_HERE, |
| 91 base::Bind(&RulesCacheDelegate::CheckIfReady, |
| 92 GetWeakPtr())); |
| 93 } |
| 94 |
| 95 void RulesCacheDelegate::WriteToStorage(const std::string& extension_id, |
| 96 scoped_ptr<base::Value> value) { |
| 97 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 98 if (!profile_) |
| 99 return; |
| 100 |
| 101 const base::ListValue* rules = NULL; |
| 102 CHECK(value->GetAsList(&rules)); |
| 103 bool rules_stored_previously = GetDeclarativeRulesStored(extension_id); |
| 104 bool store_rules = !rules->empty(); |
| 105 SetDeclarativeRulesStored(extension_id, store_rules); |
| 106 if (!rules_stored_previously && !store_rules) |
| 107 return; |
| 108 |
| 109 StateStore* store = ExtensionSystem::Get(profile_)->rules_store(); |
| 110 if (store) |
| 111 store->SetExtensionValue(extension_id, storage_key_, value.Pass()); |
| 112 } |
| 113 |
| 114 void RulesCacheDelegate::Observe( |
| 115 int type, |
| 116 const content::NotificationSource& source, |
| 117 const content::NotificationDetails& details) { |
| 118 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 119 DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED); |
| 120 |
| 121 const extensions::Extension* extension = |
| 122 content::Details<const extensions::Extension>(details).ptr(); |
| 123 // TODO(mpcomplete): This API check should generalize to any use of |
| 124 // declarative rules, not just webRequest. |
| 125 if (extension->HasAPIPermission(APIPermission::kDeclarativeContent) || |
| 126 extension->HasAPIPermission(APIPermission::kDeclarativeWebRequest)) { |
| 127 ExtensionInfoMap* extension_info_map = |
| 128 ExtensionSystem::Get(profile_)->info_map(); |
| 129 if (profile_->IsOffTheRecord() && |
| 130 !extension_info_map->IsIncognitoEnabled(extension->id())) { |
| 131 // Ignore this extension. |
| 132 } else { |
| 133 ReadFromStorage(extension->id()); |
| 134 } |
| 135 } |
| 136 } |
| 137 |
| 138 void RulesCacheDelegate::CheckIfReady() { |
| 139 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 140 if (notified_registry_ || !waiting_for_extensions_.empty()) |
| 141 return; |
| 142 |
| 143 content::BrowserThread::PostTask( |
| 144 rules_registry_thread_, |
| 145 FROM_HERE, |
| 146 base::Bind( |
| 147 &RulesRegistry::MarkReady, registry_, storage_init_time_)); |
| 148 notified_registry_ = true; |
| 149 } |
| 150 |
| 151 void RulesCacheDelegate::ReadRulesForInstalledExtensions() { |
| 152 ExtensionSystem& system = *ExtensionSystem::Get(profile_); |
| 153 ExtensionService* extension_service = system.extension_service(); |
| 154 DCHECK(extension_service); |
| 155 // In an OTR profile, we start on top of a normal profile already, so the |
| 156 // extension service should be ready. |
| 157 DCHECK(!profile_->IsOffTheRecord() || extension_service->is_ready()); |
| 158 if (extension_service->is_ready()) { |
| 159 const ExtensionSet* extensions = extension_service->extensions(); |
| 160 for (ExtensionSet::const_iterator i = extensions->begin(); |
| 161 i != extensions->end(); |
| 162 ++i) { |
| 163 bool needs_apis_storing_rules = |
| 164 (*i)->HasAPIPermission(APIPermission::kDeclarativeContent) || |
| 165 (*i)->HasAPIPermission(APIPermission::kDeclarativeWebRequest); |
| 166 bool respects_off_the_record = |
| 167 !(profile_->IsOffTheRecord()) || |
| 168 extension_util::IsIncognitoEnabled((*i)->id(), extension_service); |
| 169 if (needs_apis_storing_rules && respects_off_the_record) |
| 170 ReadFromStorage((*i)->id()); |
| 171 } |
| 172 } |
| 173 } |
| 174 |
| 175 void RulesCacheDelegate::ReadFromStorage(const std::string& extension_id) { |
| 176 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 177 if (!profile_) |
| 178 return; |
| 179 |
| 180 if (log_storage_init_delay_ && storage_init_time_.is_null()) |
| 181 storage_init_time_ = base::Time::Now(); |
| 182 |
| 183 if (!GetDeclarativeRulesStored(extension_id)) { |
| 184 ExtensionSystem::Get(profile_)->ready().Post( |
| 185 FROM_HERE, base::Bind(&RulesCacheDelegate::CheckIfReady, GetWeakPtr())); |
| 186 return; |
| 187 } |
| 188 |
| 189 extensions::StateStore* store = ExtensionSystem::Get(profile_)->rules_store(); |
| 190 if (!store) |
| 191 return; |
| 192 waiting_for_extensions_.insert(extension_id); |
| 193 store->GetExtensionValue( |
| 194 extension_id, |
| 195 storage_key_, |
| 196 base::Bind(&RulesCacheDelegate::ReadFromStorageCallback, |
| 197 weak_ptr_factory_.GetWeakPtr(), |
| 198 extension_id)); |
| 199 } |
| 200 |
| 201 void RulesCacheDelegate::ReadFromStorageCallback( |
| 202 const std::string& extension_id, |
| 203 scoped_ptr<base::Value> value) { |
| 204 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 205 content::BrowserThread::PostTask( |
| 206 rules_registry_thread_, |
| 207 FROM_HERE, |
| 208 base::Bind(&RulesRegistry::DeserializeAndAddRules, |
| 209 registry_, |
| 210 extension_id, |
| 211 base::Passed(&value))); |
| 212 |
| 213 waiting_for_extensions_.erase(extension_id); |
| 214 |
| 215 if (waiting_for_extensions_.empty()) |
| 216 ExtensionSystem::Get(profile_)->ready().Post( |
| 217 FROM_HERE, base::Bind(&RulesCacheDelegate::CheckIfReady, GetWeakPtr())); |
| 218 } |
| 219 |
| 220 bool RulesCacheDelegate::GetDeclarativeRulesStored( |
| 221 const std::string& extension_id) const { |
| 222 CHECK(profile_); |
| 223 const ExtensionScopedPrefs* extension_prefs = ExtensionPrefs::Get(profile_); |
| 224 |
| 225 bool rules_stored = true; |
| 226 if (extension_prefs->ReadPrefAsBoolean( |
| 227 extension_id, rules_stored_key_, &rules_stored)) |
| 228 return rules_stored; |
| 229 |
| 230 // Safe default -- if we don't know that the rules are not stored, we force |
| 231 // a read by returning true. |
| 232 return true; |
| 233 } |
| 234 |
| 235 void RulesCacheDelegate::SetDeclarativeRulesStored( |
| 236 const std::string& extension_id, |
| 237 bool rules_stored) { |
| 238 CHECK(profile_); |
| 239 ExtensionScopedPrefs* extension_prefs = ExtensionPrefs::Get(profile_); |
| 240 extension_prefs->UpdateExtensionPref( |
| 241 extension_id, |
| 242 rules_stored_key_, |
| 243 new base::FundamentalValue(rules_stored)); |
| 244 } |
| 245 |
| 246 } // namespace extensions |
OLD | NEW |