root/extensions/browser/extension_pref_value_map.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Shutdown
  2. SetExtensionPref
  3. RemoveExtensionPref
  4. CanExtensionControlPref
  5. ClearAllIncognitoSessionOnlyPreferences
  6. DoesExtensionControlPref
  7. RegisterExtension
  8. UnregisterExtension
  9. SetExtensionState
  10. SetExtensionIncognitoState
  11. GetExtensionPrefValueMap
  12. GetExtensionPrefValueMap
  13. GetExtensionControlledKeys
  14. GetEffectivePrefValue
  15. GetEffectivePrefValueController
  16. AddObserver
  17. RemoveObserver
  18. GetExtensionControllingPref
  19. NotifyInitializationCompleted
  20. NotifyPrefValueChanged
  21. NotifyPrefValueChanged
  22. NotifyOfDestruction

// 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());
}

/* [<][>][^][v][top][bottom][index][help] */