普通文本  |  404行  |  13.39 KB

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