// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/extension_pref_value_map.h"
#include "base/prefs/pref_value_map.h"
#include "base/stl_util.h"
#include "base/values.h"
using extensions::ExtensionPrefsScope;
struct ExtensionPrefValueMap::ExtensionEntry {
// Installation time of the extension.
base::Time install_time;
// Whether extension is enabled in the profile.
bool enabled;
// Whether the extension has access to the incognito profile.
bool incognito_enabled;
// Extension controlled preferences for the regular profile.
PrefValueMap regular_profile_preferences;
// Extension controlled preferences that should *only* apply to the regular
// profile.
PrefValueMap regular_only_profile_preferences;
// Persistent extension controlled preferences for the incognito profile,
// empty for regular profile ExtensionPrefStore.
PrefValueMap incognito_profile_preferences_persistent;
// Session only extension controlled preferences for the incognito profile.
// These preferences are deleted when the incognito profile is destroyed.
PrefValueMap incognito_profile_preferences_session_only;
};
ExtensionPrefValueMap::ExtensionPrefValueMap() : destroyed_(false) {
}
ExtensionPrefValueMap::~ExtensionPrefValueMap() {
if (!destroyed_) {
NotifyOfDestruction();
destroyed_ = true;
}
STLDeleteValues(&entries_);
entries_.clear();
}
void ExtensionPrefValueMap::Shutdown() {
NotifyOfDestruction();
destroyed_ = true;
}
void ExtensionPrefValueMap::SetExtensionPref(const std::string& ext_id,
const std::string& key,
ExtensionPrefsScope scope,
base::Value* value) {
PrefValueMap* prefs = GetExtensionPrefValueMap(ext_id, scope);
if (prefs->SetValue(key, value))
NotifyPrefValueChanged(key);
}
void ExtensionPrefValueMap::RemoveExtensionPref(
const std::string& ext_id,
const std::string& key,
ExtensionPrefsScope scope) {
PrefValueMap* prefs = GetExtensionPrefValueMap(ext_id, scope);
if (prefs->RemoveValue(key))
NotifyPrefValueChanged(key);
}
bool ExtensionPrefValueMap::CanExtensionControlPref(
const std::string& extension_id,
const std::string& pref_key,
bool incognito) const {
ExtensionEntryMap::const_iterator ext = entries_.find(extension_id);
if (ext == entries_.end()) {
NOTREACHED();
return false;
}
if (incognito && !ext->second->incognito_enabled)
return false;
ExtensionEntryMap::const_iterator winner =
GetEffectivePrefValueController(pref_key, incognito, NULL);
if (winner == entries_.end())
return true;
return winner->second->install_time <= ext->second->install_time;
}
void ExtensionPrefValueMap::ClearAllIncognitoSessionOnlyPreferences() {
typedef std::set<std::string> KeySet;
KeySet deleted_keys;
ExtensionEntryMap::iterator i;
for (i = entries_.begin(); i != entries_.end(); ++i) {
PrefValueMap& inc_prefs =
i->second->incognito_profile_preferences_session_only;
PrefValueMap::iterator j;
for (j = inc_prefs.begin(); j != inc_prefs.end(); ++j)
deleted_keys.insert(j->first);
inc_prefs.Clear();
}
KeySet::iterator k;
for (k = deleted_keys.begin(); k != deleted_keys.end(); ++k)
NotifyPrefValueChanged(*k);
}
bool ExtensionPrefValueMap::DoesExtensionControlPref(
const std::string& extension_id,
const std::string& pref_key,
bool* from_incognito) const {
bool incognito = (from_incognito != NULL);
ExtensionEntryMap::const_iterator winner =
GetEffectivePrefValueController(pref_key, incognito, from_incognito);
if (winner == entries_.end())
return false;
return winner->first == extension_id;
}
void ExtensionPrefValueMap::RegisterExtension(const std::string& ext_id,
const base::Time& install_time,
bool is_enabled,
bool is_incognito_enabled) {
if (entries_.find(ext_id) == entries_.end()) {
entries_[ext_id] = new ExtensionEntry;
// Only update the install time if the extension is newly installed.
entries_[ext_id]->install_time = install_time;
}
entries_[ext_id]->enabled = is_enabled;
entries_[ext_id]->incognito_enabled = is_incognito_enabled;
}
void ExtensionPrefValueMap::UnregisterExtension(const std::string& ext_id) {
ExtensionEntryMap::iterator i = entries_.find(ext_id);
if (i == entries_.end())
return;
std::set<std::string> keys; // keys set by this extension
GetExtensionControlledKeys(*(i->second), &keys);
delete i->second;
entries_.erase(i);
NotifyPrefValueChanged(keys);
}
void ExtensionPrefValueMap::SetExtensionState(const std::string& ext_id,
bool is_enabled) {
ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
// This may happen when sync sets the extension state for an
// extension that is not installed.
if (i == entries_.end())
return;
if (i->second->enabled == is_enabled)
return;
std::set<std::string> keys; // keys set by this extension
GetExtensionControlledKeys(*(i->second), &keys);
i->second->enabled = is_enabled;
NotifyPrefValueChanged(keys);
}
void ExtensionPrefValueMap::SetExtensionIncognitoState(
const std::string& ext_id,
bool is_incognito_enabled) {
ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
// This may happen when sync sets the extension state for an
// extension that is not installed.
if (i == entries_.end())
return;
if (i->second->incognito_enabled == is_incognito_enabled)
return;
std::set<std::string> keys; // keys set by this extension
GetExtensionControlledKeys(*(i->second), &keys);
i->second->incognito_enabled = is_incognito_enabled;
NotifyPrefValueChanged(keys);
}
PrefValueMap* ExtensionPrefValueMap::GetExtensionPrefValueMap(
const std::string& ext_id,
ExtensionPrefsScope scope) {
ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
CHECK(i != entries_.end());
switch (scope) {
case extensions::kExtensionPrefsScopeRegular:
return &(i->second->regular_profile_preferences);
case extensions::kExtensionPrefsScopeRegularOnly:
return &(i->second->regular_only_profile_preferences);
case extensions::kExtensionPrefsScopeIncognitoPersistent:
return &(i->second->incognito_profile_preferences_persistent);
case extensions::kExtensionPrefsScopeIncognitoSessionOnly:
return &(i->second->incognito_profile_preferences_session_only);
}
NOTREACHED();
return NULL;
}
const PrefValueMap* ExtensionPrefValueMap::GetExtensionPrefValueMap(
const std::string& ext_id,
ExtensionPrefsScope scope) const {
ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
CHECK(i != entries_.end());
switch (scope) {
case extensions::kExtensionPrefsScopeRegular:
return &(i->second->regular_profile_preferences);
case extensions::kExtensionPrefsScopeRegularOnly:
return &(i->second->regular_only_profile_preferences);
case extensions::kExtensionPrefsScopeIncognitoPersistent:
return &(i->second->incognito_profile_preferences_persistent);
case extensions::kExtensionPrefsScopeIncognitoSessionOnly:
return &(i->second->incognito_profile_preferences_session_only);
}
NOTREACHED();
return NULL;
}
void ExtensionPrefValueMap::GetExtensionControlledKeys(
const ExtensionEntry& entry,
std::set<std::string>* out) const {
PrefValueMap::const_iterator i;
const PrefValueMap& regular_prefs = entry.regular_profile_preferences;
for (i = regular_prefs.begin(); i != regular_prefs.end(); ++i)
out->insert(i->first);
const PrefValueMap& regular_only_prefs =
entry.regular_only_profile_preferences;
for (i = regular_only_prefs.begin(); i != regular_only_prefs.end(); ++i)
out->insert(i->first);
const PrefValueMap& inc_prefs_pers =
entry.incognito_profile_preferences_persistent;
for (i = inc_prefs_pers.begin(); i != inc_prefs_pers.end(); ++i)
out->insert(i->first);
const PrefValueMap& inc_prefs_session =
entry.incognito_profile_preferences_session_only;
for (i = inc_prefs_session.begin(); i != inc_prefs_session.end(); ++i)
out->insert(i->first);
}
const base::Value* ExtensionPrefValueMap::GetEffectivePrefValue(
const std::string& key,
bool incognito,
bool* from_incognito) const {
ExtensionEntryMap::const_iterator winner =
GetEffectivePrefValueController(key, incognito, from_incognito);
if (winner == entries_.end())
return NULL;
const base::Value* value = NULL;
const std::string& ext_id = winner->first;
// First search for incognito session only preferences.
if (incognito) {
DCHECK(winner->second->incognito_enabled);
const PrefValueMap* prefs = GetExtensionPrefValueMap(
ext_id, extensions::kExtensionPrefsScopeIncognitoSessionOnly);
prefs->GetValue(key, &value);
if (value)
return value;
// If no incognito session only preference exists, fall back to persistent
// incognito preference.
prefs = GetExtensionPrefValueMap(
ext_id,
extensions::kExtensionPrefsScopeIncognitoPersistent);
prefs->GetValue(key, &value);
if (value)
return value;
} else {
// Regular-only preference.
const PrefValueMap* prefs = GetExtensionPrefValueMap(
ext_id, extensions::kExtensionPrefsScopeRegularOnly);
prefs->GetValue(key, &value);
if (value)
return value;
}
// Regular preference.
const PrefValueMap* prefs = GetExtensionPrefValueMap(
ext_id, extensions::kExtensionPrefsScopeRegular);
prefs->GetValue(key, &value);
return value;
}
ExtensionPrefValueMap::ExtensionEntryMap::const_iterator
ExtensionPrefValueMap::GetEffectivePrefValueController(
const std::string& key,
bool incognito,
bool* from_incognito) const {
ExtensionEntryMap::const_iterator winner = entries_.end();
base::Time winners_install_time;
ExtensionEntryMap::const_iterator i;
for (i = entries_.begin(); i != entries_.end(); ++i) {
const std::string& ext_id = i->first;
const base::Time& install_time = i->second->install_time;
const bool enabled = i->second->enabled;
const bool incognito_enabled = i->second->incognito_enabled;
if (!enabled)
continue;
if (install_time < winners_install_time)
continue;
if (incognito && !incognito_enabled)
continue;
const base::Value* value = NULL;
const PrefValueMap* prefs = GetExtensionPrefValueMap(
ext_id, extensions::kExtensionPrefsScopeRegular);
if (prefs->GetValue(key, &value)) {
winner = i;
winners_install_time = install_time;
if (from_incognito)
*from_incognito = false;
}
if (!incognito) {
const PrefValueMap* prefs = GetExtensionPrefValueMap(
ext_id, extensions::kExtensionPrefsScopeRegularOnly);
if (prefs->GetValue(key, &value)) {
winner = i;
winners_install_time = install_time;
if (from_incognito)
*from_incognito = false;
}
// Ignore the following prefs, because they're incognito-only.
continue;
}
prefs = GetExtensionPrefValueMap(
ext_id, extensions::kExtensionPrefsScopeIncognitoPersistent);
if (prefs->GetValue(key, &value)) {
winner = i;
winners_install_time = install_time;
if (from_incognito)
*from_incognito = true;
}
prefs = GetExtensionPrefValueMap(
ext_id, extensions::kExtensionPrefsScopeIncognitoSessionOnly);
if (prefs->GetValue(key, &value)) {
winner = i;
winners_install_time = install_time;
if (from_incognito)
*from_incognito = true;
}
}
return winner;
}
void ExtensionPrefValueMap::AddObserver(
ExtensionPrefValueMap::Observer* observer) {
observers_.AddObserver(observer);
// Collect all currently used keys and notify the new observer.
std::set<std::string> keys;
ExtensionEntryMap::const_iterator i;
for (i = entries_.begin(); i != entries_.end(); ++i)
GetExtensionControlledKeys(*(i->second), &keys);
std::set<std::string>::const_iterator j;
for (j = keys.begin(); j != keys.end(); ++j)
observer->OnPrefValueChanged(*j);
}
void ExtensionPrefValueMap::RemoveObserver(
ExtensionPrefValueMap::Observer* observer) {
observers_.RemoveObserver(observer);
}
std::string ExtensionPrefValueMap::GetExtensionControllingPref(
const std::string& pref_key) const {
ExtensionEntryMap::const_iterator winner =
GetEffectivePrefValueController(pref_key, false, NULL);
if (winner == entries_.end())
return std::string();
return winner->first;
}
void ExtensionPrefValueMap::NotifyInitializationCompleted() {
FOR_EACH_OBSERVER(ExtensionPrefValueMap::Observer, observers_,
OnInitializationCompleted());
}
void ExtensionPrefValueMap::NotifyPrefValueChanged(
const std::set<std::string>& keys) {
std::set<std::string>::const_iterator i;
for (i = keys.begin(); i != keys.end(); ++i)
NotifyPrefValueChanged(*i);
}
void ExtensionPrefValueMap::NotifyPrefValueChanged(const std::string& key) {
FOR_EACH_OBSERVER(ExtensionPrefValueMap::Observer, observers_,
OnPrefValueChanged(key));
}
void ExtensionPrefValueMap::NotifyOfDestruction() {
FOR_EACH_OBSERVER(ExtensionPrefValueMap::Observer, observers_,
OnExtensionPrefValueMapDestruction());
}