summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
authorderat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-22 18:20:03 +0000
committerderat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-22 18:20:03 +0000
commit489db0845d8070c3882a945fed1108acfb170185 (patch)
treef0a3a145789a6ba18c8fa4ebb4e786ae9360d1e5 /extensions
parenta78957254f0072472366a75531f7e585cb23ff2c (diff)
downloadchromium_src-489db0845d8070c3882a945fed1108acfb170185.zip
chromium_src-489db0845d8070c3882a945fed1108acfb170185.tar.gz
chromium_src-489db0845d8070c3882a945fed1108acfb170185.tar.bz2
Move ExtensionPrefs and friends to extensions/ directory.
Move ExtensionPrefs and related classes from chrome/browser/extensions/ to the top-level extensions/ directory. The following classes are moved: ExtensionPrefStore ExtensionPrefValueMap ExtensionPrefValueMapFactory ExtensionPrefs ExtensionPrefsFactory ExtensionScopedPref The TestExtensionPrefs helper class and the ExtensionPrefsTest unit tests remain in chrome/browser/extensions, since TestExtensionPrefs has a dependency on Chrome's PrefServiceSyncable that seems like it will be difficult to break (more explanation at https://codereview.chromium.org/108643002/). BUG=313284 TBR=sky@chromium.org,pam@chromium.org Review URL: https://codereview.chromium.org/46853004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@246373 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions')
-rw-r--r--extensions/browser/DEPS4
-rw-r--r--extensions/browser/app_sorting.h3
-rw-r--r--extensions/browser/event_router.cc2
-rw-r--r--extensions/browser/extension_pref_store.cc43
-rw-r--r--extensions/browser/extension_pref_store.h38
-rw-r--r--extensions/browser/extension_pref_value_map.cc376
-rw-r--r--extensions/browser/extension_pref_value_map.h198
-rw-r--r--extensions/browser/extension_pref_value_map_factory.cc35
-rw-r--r--extensions/browser/extension_pref_value_map_factory.h31
-rw-r--r--extensions/browser/extension_pref_value_map_unittest.cc400
-rw-r--r--extensions/browser/extension_prefs.cc1892
-rw-r--r--extensions/browser/extension_prefs.h638
-rw-r--r--extensions/browser/extension_prefs_factory.cc61
-rw-r--r--extensions/browser/extension_prefs_factory.h39
-rw-r--r--extensions/browser/extension_scoped_prefs.h56
-rw-r--r--extensions/browser/extensions_browser_client.h2
-rw-r--r--extensions/extensions.gyp13
17 files changed, 3826 insertions, 5 deletions
diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS
index a2c9650..65d427b 100644
--- a/extensions/browser/DEPS
+++ b/extensions/browser/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+components/browser_context_keyed_service",
+ "+components/user_prefs",
"+content/public/browser",
"+sync",
@@ -10,11 +11,12 @@ include_rules = [
#
# TODO(jamescook): Remove these. http://crbug.com/162530
"+chrome/browser/chrome_notification_types.h",
+ "+chrome/browser/extensions/api/content_settings/content_settings_store.h",
+ "+chrome/browser/extensions/api/preference/preference_api.h",
"+chrome/browser/extensions/api/runtime/runtime_api.h",
"+chrome/browser/extensions/extension_function_dispatcher.h",
"+chrome/browser/extensions/extension_function_histogram_value.h",
"+chrome/browser/extensions/extension_host.h",
- "+chrome/browser/extensions/extension_prefs.h",
"+chrome/browser/extensions/extension_service.h",
"+chrome/browser/extensions/extension_system.h",
"+chrome/browser/extensions/extension_util.h",
diff --git a/extensions/browser/app_sorting.h b/extensions/browser/app_sorting.h
index 967fb46..ede93f1 100644
--- a/extensions/browser/app_sorting.h
+++ b/extensions/browser/app_sorting.h
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 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.
@@ -8,6 +8,7 @@
#include <string>
#include "base/basictypes.h"
+#include "extensions/browser/extension_prefs.h"
#include "extensions/common/extension.h"
#include "sync/api/string_ordinal.h"
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc
index dbef450..763b3ff 100644
--- a/extensions/browser/event_router.cc
+++ b/extensions/browser/event_router.cc
@@ -13,13 +13,13 @@
#include "base/values.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/common/extensions/extension_messages.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_process_host.h"
+#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/lazy_background_task_queue.h"
diff --git a/extensions/browser/extension_pref_store.cc b/extensions/browser/extension_pref_store.cc
new file mode 100644
index 0000000..3f26cbb3
--- /dev/null
+++ b/extensions/browser/extension_pref_store.cc
@@ -0,0 +1,43 @@
+// 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_store.h"
+
+#include "base/values.h"
+#include "extensions/browser/extension_pref_value_map.h"
+
+ExtensionPrefStore::ExtensionPrefStore(
+ ExtensionPrefValueMap* extension_pref_value_map,
+ bool incognito_pref_store)
+ : extension_pref_value_map_(extension_pref_value_map),
+ incognito_pref_store_(incognito_pref_store) {
+ extension_pref_value_map_->AddObserver(this);
+}
+
+void ExtensionPrefStore::OnInitializationCompleted() {
+ NotifyInitializationCompleted();
+}
+
+void ExtensionPrefStore::OnPrefValueChanged(const std::string& key) {
+ CHECK(extension_pref_value_map_);
+ const base::Value *winner =
+ extension_pref_value_map_->GetEffectivePrefValue(key,
+ incognito_pref_store_,
+ NULL);
+ if (winner)
+ SetValue(key, winner->DeepCopy());
+ else
+ RemoveValue(key);
+}
+
+void ExtensionPrefStore::OnExtensionPrefValueMapDestruction() {
+ CHECK(extension_pref_value_map_);
+ extension_pref_value_map_->RemoveObserver(this);
+ extension_pref_value_map_ = NULL;
+}
+
+ExtensionPrefStore::~ExtensionPrefStore() {
+ if (extension_pref_value_map_)
+ extension_pref_value_map_->RemoveObserver(this);
+}
diff --git a/extensions/browser/extension_pref_store.h b/extensions/browser/extension_pref_store.h
new file mode 100644
index 0000000..d93018c
--- /dev/null
+++ b/extensions/browser/extension_pref_store.h
@@ -0,0 +1,38 @@
+// 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.
+
+#ifndef EXTENSIONS_BROWSER_EXTENSION_PREF_STORE_H_
+#define EXTENSIONS_BROWSER_EXTENSION_PREF_STORE_H_
+
+#include <string>
+
+#include "base/prefs/value_map_pref_store.h"
+#include "extensions/browser/extension_pref_value_map.h"
+
+// A (non-persistent) PrefStore implementation that holds effective preferences
+// set by extensions. These preferences are managed by and fetched from an
+// ExtensionPrefValueMap.
+class ExtensionPrefStore : public ValueMapPrefStore,
+ public ExtensionPrefValueMap::Observer {
+ public:
+ // Constructs an ExtensionPrefStore for a regular or an incognito profile.
+ ExtensionPrefStore(ExtensionPrefValueMap* extension_pref_value_map,
+ bool incognito_pref_store);
+
+ // Overrides for ExtensionPrefValueMap::Observer:
+ virtual void OnInitializationCompleted() OVERRIDE;
+ virtual void OnPrefValueChanged(const std::string& key) OVERRIDE;
+ virtual void OnExtensionPrefValueMapDestruction() OVERRIDE;
+
+ protected:
+ virtual ~ExtensionPrefStore();
+
+ private:
+ ExtensionPrefValueMap* extension_pref_value_map_; // Weak pointer.
+ bool incognito_pref_store_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionPrefStore);
+};
+
+#endif // EXTENSIONS_BROWSER_EXTENSION_PREF_STORE_H_
diff --git a/extensions/browser/extension_pref_value_map.cc b/extensions/browser/extension_pref_value_map.cc
new file mode 100644
index 0000000..5cba7e5
--- /dev/null
+++ b/extensions/browser/extension_pref_value_map.cc
@@ -0,0 +1,376 @@
+// 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;
+ // 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;
+ }
+
+ 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) {
+ 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;
+}
+
+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);
+}
+
+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) {
+ 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;
+
+ if (!enabled)
+ continue;
+ if (install_time < winners_install_time)
+ 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());
+}
diff --git a/extensions/browser/extension_pref_value_map.h b/extensions/browser/extension_pref_value_map.h
new file mode 100644
index 0000000..48f30d9
--- /dev/null
+++ b/extensions/browser/extension_pref_value_map.h
@@ -0,0 +1,198 @@
+// 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.
+
+#ifndef EXTENSIONS_BROWSER_EXTENSION_PREF_VALUE_MAP_H_
+#define EXTENSIONS_BROWSER_EXTENSION_PREF_VALUE_MAP_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/observer_list.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "extensions/browser/extension_prefs_scope.h"
+
+// Non-persistent data container that is shared by ExtensionPrefStores. All
+// extension pref values (incognito and regular) are stored herein and
+// provided to ExtensionPrefStores.
+//
+// The semantics of the ExtensionPrefValueMap are:
+// - A regular setting applies to regular browsing sessions as well as incognito
+// browsing sessions.
+// - An incognito setting applies only to incognito browsing sessions, not to
+// regular ones. It takes precedence over a regular setting set by the same
+// extension.
+// - A regular-only setting applies only to regular browsing sessions, not to
+// incognito ones. It takes precedence over a regular setting set by the same
+// extension.
+// - If two different extensions set a value for the same preference (and both
+// values apply to the regular/incognito browsing session), the extension that
+// was installed later takes precedence, regardless of whether the settings
+// are regular, incognito or regular-only.
+//
+// The following table illustrates the behavior:
+// A.reg | A.reg_only | A.inc | B.reg | B.reg_only | B.inc | E.reg | E.inc
+// 1 | - | - | - | - | - | 1 | 1
+// 1 | 2 | - | - | - | - | 2 | 1
+// 1 | - | 3 | - | - | - | 1 | 3
+// 1 | 2 | 3 | - | - | - | 2 | 3
+// 1 | - | - | 4 | - | - | 4 | 4
+// 1 | 2 | 3 | 4 | - | - | 4 | 4
+// 1 | - | - | - | 5 | - | 5 | 1
+// 1 | - | 3 | 4 | 5 | - | 5 | 4
+// 1 | - | - | - | - | 6 | 1 | 6
+// 1 | 2 | - | 4 | - | 6 | 4 | 6
+// 1 | 2 | 3 | - | 5 | 6 | 5 | 6
+//
+// A = extension A, B = extension B, E = effective value
+// .reg = regular value
+// .reg_only = regular-only value
+// .inc = incognito value
+// Extension B has higher precedence than A.
+class ExtensionPrefValueMap : public BrowserContextKeyedService {
+ public:
+ // Observer interface for monitoring ExtensionPrefValueMap.
+ class Observer {
+ public:
+ // Called when the value for the given |key| set by one of the extensions
+ // changes. This does not necessarily mean that the effective value has
+ // changed.
+ virtual void OnPrefValueChanged(const std::string& key) = 0;
+ // Notification about the ExtensionPrefValueMap being fully initialized.
+ virtual void OnInitializationCompleted() = 0;
+ // Called when the ExtensionPrefValueMap is being destroyed. When called,
+ // observers must unsubscribe.
+ virtual void OnExtensionPrefValueMapDestruction() = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ ExtensionPrefValueMap();
+ virtual ~ExtensionPrefValueMap();
+
+ // BrowserContextKeyedService implementation.
+ virtual void Shutdown() OVERRIDE;
+
+ // Set an extension preference |value| for |key| of extension |ext_id|.
+ // Takes ownership of |value|.
+ // Note that regular extension pref values need to be reported to
+ // incognito and to regular ExtensionPrefStores.
+ // Precondition: the extension must be registered.
+ void SetExtensionPref(const std::string& ext_id,
+ const std::string& key,
+ extensions::ExtensionPrefsScope scope,
+ base::Value* value);
+
+ // Remove the extension preference value for |key| of extension |ext_id|.
+ // Precondition: the extension must be registered.
+ void RemoveExtensionPref(const std::string& ext_id,
+ const std::string& key,
+ extensions::ExtensionPrefsScope scope);
+
+ // Returns true if currently no extension with higher precedence controls the
+ // preference.
+ // Note that the this function does does not consider the existence of
+ // policies. An extension is only really able to control a preference if
+ // PrefService::Preference::IsExtensionModifiable() returns true as well.
+ bool CanExtensionControlPref(const std::string& extension_id,
+ const std::string& pref_key,
+ bool incognito) const;
+
+ // Removes all "incognito session only" preference values.
+ void ClearAllIncognitoSessionOnlyPreferences();
+
+ // Returns true if an extension identified by |extension_id| controls the
+ // preference. This means this extension has set a preference value and no
+ // other extension with higher precedence overrides it. If |from_incognito|
+ // is not NULL, looks at incognito preferences first, and |from_incognito| is
+ // set to true if the effective pref value is coming from the incognito
+ // preferences, false if it is coming from the normal ones.
+ // Note that the this function does does not consider the existence of
+ // policies. An extension is only really able to control a preference if
+ // PrefService::Preference::IsExtensionModifiable() returns true as well.
+ bool DoesExtensionControlPref(const std::string& extension_id,
+ const std::string& pref_key,
+ bool* from_incognito) const;
+
+ // Returns the ID of the extension that currently controls this preference.
+ // Returns an empty string if this preference is not controlled by an
+ // extension.
+ std::string GetExtensionControllingPref(const std::string& pref_key) const;
+
+ // Tell the store it's now fully initialized.
+ void NotifyInitializationCompleted();
+
+ // Registers the time when an extension |ext_id| is installed.
+ void RegisterExtension(const std::string& ext_id,
+ const base::Time& install_time,
+ bool is_enabled);
+
+ // Deletes all entries related to extension |ext_id|.
+ void UnregisterExtension(const std::string& ext_id);
+
+ // Hides or makes the extension preference values of the specified extension
+ // visible.
+ void SetExtensionState(const std::string& ext_id, bool is_enabled);
+
+ // Adds an observer and notifies it about the currently stored keys.
+ void AddObserver(Observer* observer);
+
+ void RemoveObserver(Observer* observer);
+
+ const base::Value* GetEffectivePrefValue(const std::string& key,
+ bool incognito,
+ bool* from_incognito) const;
+
+ private:
+ struct ExtensionEntry;
+
+ typedef std::map<std::string, ExtensionEntry*> ExtensionEntryMap;
+
+ const PrefValueMap* GetExtensionPrefValueMap(
+ const std::string& ext_id,
+ extensions::ExtensionPrefsScope scope) const;
+
+ PrefValueMap* GetExtensionPrefValueMap(
+ const std::string& ext_id,
+ extensions::ExtensionPrefsScope scope);
+
+ // Returns all keys of pref values that are set by the extension of |entry|,
+ // regardless whether they are set for incognito or regular pref values.
+ void GetExtensionControlledKeys(const ExtensionEntry& entry,
+ std::set<std::string>* out) const;
+
+ // Returns an iterator to the extension which controls the preference |key|.
+ // If |incognito| is true, looks at incognito preferences first. In that case,
+ // if |from_incognito| is not NULL, it is set to true if the effective pref
+ // value is coming from the incognito preferences, false if it is coming from
+ // the normal ones.
+ ExtensionEntryMap::const_iterator GetEffectivePrefValueController(
+ const std::string& key,
+ bool incognito,
+ bool* from_incognito) const;
+
+ void NotifyOfDestruction();
+ void NotifyPrefValueChanged(const std::string& key);
+ void NotifyPrefValueChanged(const std::set<std::string>& keys);
+
+ // Mapping of which extension set which preference value. The effective
+ // preferences values (i.e. the ones with the highest precedence)
+ // are stored in ExtensionPrefStores.
+ ExtensionEntryMap entries_;
+
+ // In normal Profile shutdown, Shutdown() notifies observers that we are
+ // being destroyed. In tests, it isn't called, so the notification must
+ // be done in the destructor. This bit tracks whether it has been done yet.
+ bool destroyed_;
+
+ ObserverList<Observer, true> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionPrefValueMap);
+};
+
+#endif // EXTENSIONS_BROWSER_EXTENSION_PREF_VALUE_MAP_H_
diff --git a/extensions/browser/extension_pref_value_map_factory.cc b/extensions/browser/extension_pref_value_map_factory.cc
new file mode 100644
index 0000000..c8d3bfb
--- /dev/null
+++ b/extensions/browser/extension_pref_value_map_factory.cc
@@ -0,0 +1,35 @@
+// 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_factory.h"
+
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+#include "extensions/browser/extension_pref_value_map.h"
+
+ExtensionPrefValueMapFactory::ExtensionPrefValueMapFactory()
+ : BrowserContextKeyedServiceFactory(
+ "ExtensionPrefValueMap",
+ BrowserContextDependencyManager::GetInstance()) {
+}
+
+ExtensionPrefValueMapFactory::~ExtensionPrefValueMapFactory() {
+}
+
+// static
+ExtensionPrefValueMap* ExtensionPrefValueMapFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<ExtensionPrefValueMap*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+ExtensionPrefValueMapFactory* ExtensionPrefValueMapFactory::GetInstance() {
+ return Singleton<ExtensionPrefValueMapFactory>::get();
+}
+
+BrowserContextKeyedService*
+ExtensionPrefValueMapFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new ExtensionPrefValueMap();
+}
diff --git a/extensions/browser/extension_pref_value_map_factory.h b/extensions/browser/extension_pref_value_map_factory.h
new file mode 100644
index 0000000..84537d3
--- /dev/null
+++ b/extensions/browser/extension_pref_value_map_factory.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef EXTENSIONS_BROWSER_EXTENSION_PREF_VALUE_MAP_FACTORY_H_
+#define EXTENSIONS_BROWSER_EXTENSION_PREF_VALUE_MAP_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+class ExtensionPrefValueMap;
+
+// The usual factory boilerplate for ExtensionPrefValueMap.
+class ExtensionPrefValueMapFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ static ExtensionPrefValueMap* GetForBrowserContext(
+ content::BrowserContext* context);
+
+ static ExtensionPrefValueMapFactory* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<ExtensionPrefValueMapFactory>;
+
+ ExtensionPrefValueMapFactory();
+ virtual ~ExtensionPrefValueMapFactory();
+
+ virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const OVERRIDE;
+};
+
+#endif // EXTENSIONS_BROWSER_EXTENSION_PREF_VALUE_MAP_FACTORY_H_
diff --git a/extensions/browser/extension_pref_value_map_unittest.cc b/extensions/browser/extension_pref_value_map_unittest.cc
new file mode 100644
index 0000000..35fa3c6
--- /dev/null
+++ b/extensions/browser/extension_pref_value_map_unittest.cc
@@ -0,0 +1,400 @@
+// 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 "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_store_observer_mock.h"
+#include "base/values.h"
+#include "extensions/browser/extension_pref_value_map.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const char kExt1[] = "ext1";
+const char kExt2[] = "ext2";
+const char kExt3[] = "ext3";
+
+const char kPref1[] = "path1.subpath";
+const char kPref2[] = "path2";
+const char kPref3[] = "path3";
+const char kPref4[] = "path4";
+} // namespace
+
+static base::Value* CreateVal(const char* str) {
+ return new base::StringValue(str);
+}
+
+static base::Time CreateTime(int64 t) {
+ return base::Time::FromInternalValue(t);
+}
+
+template <typename BASECLASS>
+class ExtensionPrefValueMapTestBase : public BASECLASS {
+ public:
+ static const extensions::ExtensionPrefsScope kRegular =
+ extensions::kExtensionPrefsScopeRegular;
+ static const extensions::ExtensionPrefsScope kRegularOnly =
+ extensions::kExtensionPrefsScopeRegularOnly;
+ static const extensions::ExtensionPrefsScope kIncognitoPersistent =
+ extensions::kExtensionPrefsScopeIncognitoPersistent;
+ static const extensions::ExtensionPrefsScope kIncognitoSessionOnly =
+ extensions::kExtensionPrefsScopeIncognitoSessionOnly;
+
+ // Returns an empty string if the key is not set.
+ std::string GetValue(const char * key, bool incognito) const {
+ const base::Value *value =
+ epvm_.GetEffectivePrefValue(key, incognito, NULL);
+ std::string string_value;
+ if (value)
+ value->GetAsString(&string_value);
+ return string_value;
+ }
+
+ protected:
+ ExtensionPrefValueMap epvm_;
+};
+
+class ExtensionPrefValueMapTest
+ : public ExtensionPrefValueMapTestBase<testing::Test> {
+};
+
+// A gmock-ified implementation of PrefStore::Observer.
+class ExtensionPrefValueMapObserverMock
+ : public ExtensionPrefValueMap::Observer {
+ public:
+ ExtensionPrefValueMapObserverMock() {}
+ virtual ~ExtensionPrefValueMapObserverMock() {}
+
+ MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
+ MOCK_METHOD0(OnInitializationCompleted, void());
+ MOCK_METHOD0(OnExtensionPrefValueMapDestruction, void());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ExtensionPrefValueMapObserverMock);
+};
+
+TEST_F(ExtensionPrefValueMapTest, SetAndGetPrefValue) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ EXPECT_EQ("val1", GetValue(kPref1, false));
+};
+
+TEST_F(ExtensionPrefValueMapTest, GetNotSetPrefValue) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ EXPECT_EQ("", GetValue(kPref1, false));
+};
+
+// Make sure the last-installed extension wins for each preference.
+TEST_F(ExtensionPrefValueMapTest, Override) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.RegisterExtension(kExt2, CreateTime(20), true);
+ epvm_.RegisterExtension(kExt3, CreateTime(30), true);
+
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ epvm_.SetExtensionPref(kExt2, kPref1, kRegular, CreateVal("val2"));
+ epvm_.SetExtensionPref(kExt3, kPref1, kRegular, CreateVal("val3"));
+
+ epvm_.SetExtensionPref(kExt1, kPref2, kRegular, CreateVal("val4"));
+ epvm_.SetExtensionPref(kExt2, kPref2, kRegular, CreateVal("val5"));
+
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val6"));
+ epvm_.SetExtensionPref(kExt1, kPref2, kRegular, CreateVal("val7"));
+ epvm_.SetExtensionPref(kExt1, kPref3, kRegular, CreateVal("val8"));
+
+ EXPECT_EQ("val3", GetValue(kPref1, false));
+ EXPECT_EQ("val5", GetValue(kPref2, false));
+ EXPECT_EQ("val8", GetValue(kPref3, false));
+}
+
+TEST_F(ExtensionPrefValueMapTest, OverrideChecks) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.RegisterExtension(kExt2, CreateTime(20), true);
+ epvm_.RegisterExtension(kExt3, CreateTime(30), true);
+
+ EXPECT_FALSE(epvm_.DoesExtensionControlPref(kExt1, kPref1, NULL));
+ EXPECT_FALSE(epvm_.DoesExtensionControlPref(kExt2, kPref1, NULL));
+ EXPECT_FALSE(epvm_.DoesExtensionControlPref(kExt3, kPref1, NULL));
+ EXPECT_TRUE(epvm_.CanExtensionControlPref(kExt1, kPref1, false));
+ EXPECT_TRUE(epvm_.CanExtensionControlPref(kExt2, kPref1, false));
+ EXPECT_TRUE(epvm_.CanExtensionControlPref(kExt3, kPref1, false));
+
+ epvm_.SetExtensionPref(kExt2, kPref1, kRegular, CreateVal("val1"));
+
+ EXPECT_FALSE(epvm_.DoesExtensionControlPref(kExt1, kPref1, NULL));
+ EXPECT_TRUE(epvm_.DoesExtensionControlPref(kExt2, kPref1, NULL));
+ EXPECT_FALSE(epvm_.DoesExtensionControlPref(kExt3, kPref1, NULL));
+ EXPECT_FALSE(epvm_.CanExtensionControlPref(kExt1, kPref1, false));
+ EXPECT_TRUE(epvm_.CanExtensionControlPref(kExt2, kPref1, false));
+ EXPECT_TRUE(epvm_.CanExtensionControlPref(kExt3, kPref1, false));
+}
+
+TEST_F(ExtensionPrefValueMapTest, SetAndGetPrefValueIncognito) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ EXPECT_EQ("val1", GetValue(kPref1, true));
+}
+
+TEST_F(ExtensionPrefValueMapTest, UninstallOnlyExtension) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ epvm_.UnregisterExtension(kExt1);
+
+ EXPECT_EQ("", GetValue(kPref1, false));
+}
+
+// Tests uninstalling an extension that wasn't winning for any preferences.
+TEST_F(ExtensionPrefValueMapTest, UninstallIrrelevantExtension) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.RegisterExtension(kExt2, CreateTime(10), true);
+
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ epvm_.SetExtensionPref(kExt2, kPref1, kRegular, CreateVal("val2"));
+
+ epvm_.SetExtensionPref(kExt1, kPref2, kRegular, CreateVal("val3"));
+ epvm_.SetExtensionPref(kExt2, kPref2, kRegular, CreateVal("val4"));
+
+ epvm_.UnregisterExtension(kExt1);
+
+ EXPECT_EQ("val2", GetValue(kPref1, false));
+ EXPECT_EQ("val4", GetValue(kPref2, false));
+}
+
+// Tests uninstalling an extension that was winning for all preferences.
+TEST_F(ExtensionPrefValueMapTest, UninstallExtensionFromTop) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.RegisterExtension(kExt2, CreateTime(20), true);
+ epvm_.RegisterExtension(kExt3, CreateTime(30), true);
+
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ epvm_.SetExtensionPref(kExt2, kPref1, kRegular, CreateVal("val2"));
+ epvm_.SetExtensionPref(kExt3, kPref1, kRegular, CreateVal("val3"));
+
+ epvm_.SetExtensionPref(kExt1, kPref2, kRegular, CreateVal("val4"));
+ epvm_.SetExtensionPref(kExt3, kPref2, kRegular, CreateVal("val5"));
+
+ epvm_.UnregisterExtension(kExt3);
+
+ EXPECT_EQ("val2", GetValue(kPref1, false));
+ EXPECT_EQ("val4", GetValue(kPref2, false));
+}
+
+// Tests uninstalling an extension that was winning for only some preferences.
+TEST_F(ExtensionPrefValueMapTest, UninstallExtensionFromMiddle) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.RegisterExtension(kExt2, CreateTime(20), true);
+ epvm_.RegisterExtension(kExt3, CreateTime(30), true);
+
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ epvm_.SetExtensionPref(kExt2, kPref1, kRegular, CreateVal("val2"));
+ epvm_.SetExtensionPref(kExt3, kPref1, kRegular, CreateVal("val3"));
+
+ epvm_.SetExtensionPref(kExt1, kPref2, kRegular, CreateVal("val4"));
+ epvm_.SetExtensionPref(kExt2, kPref2, kRegular, CreateVal("val5"));
+
+ epvm_.SetExtensionPref(kExt1, kPref3, kRegular, CreateVal("val6"));
+
+ epvm_.SetExtensionPref(kExt2, kPref4, kRegular, CreateVal("val7"));
+
+ epvm_.UnregisterExtension(kExt2);
+
+ EXPECT_EQ("val3", GetValue(kPref1, false));
+ EXPECT_EQ("val4", GetValue(kPref2, false));
+ EXPECT_EQ("val6", GetValue(kPref3, false));
+ EXPECT_EQ("", GetValue(kPref4, false));
+}
+
+// Tests triggering of notifications to registered observers.
+TEST_F(ExtensionPrefValueMapTest, NotifyWhenNeeded) {
+ using testing::Mock;
+ using testing::StrEq;
+
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+
+ ExtensionPrefValueMapObserverMock observer;
+ epvm_.AddObserver(&observer);
+
+ EXPECT_CALL(observer, OnPrefValueChanged(std::string(kPref1)));
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Write the same value again.
+ EXPECT_CALL(observer, OnPrefValueChanged(std::string(kPref1))).Times(0);
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Override incognito value.
+ EXPECT_CALL(observer, OnPrefValueChanged(std::string(kPref1)));
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val2"));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Override non-incognito value.
+ EXPECT_CALL(observer, OnPrefValueChanged(std::string(kPref1)));
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val3"));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Disable.
+ EXPECT_CALL(observer, OnPrefValueChanged(std::string(kPref1)));
+ epvm_.SetExtensionState(kExt1, false);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Enable.
+ EXPECT_CALL(observer, OnPrefValueChanged(std::string(kPref1)));
+ epvm_.SetExtensionState(kExt1, true);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Uninstall
+ EXPECT_CALL(observer, OnPrefValueChanged(std::string(kPref1)));
+ epvm_.UnregisterExtension(kExt1);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ epvm_.RemoveObserver(&observer);
+
+ // Write new value --> no notification after removing observer.
+ EXPECT_CALL(observer, OnPrefValueChanged(std::string(kPref1))).Times(0);
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val4"));
+ Mock::VerifyAndClearExpectations(&observer);
+}
+
+// Tests disabling an extension.
+TEST_F(ExtensionPrefValueMapTest, DisableExt) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ epvm_.SetExtensionState(kExt1, false);
+ EXPECT_EQ("", GetValue(kPref1, false));
+}
+
+// Tests disabling and reenabling an extension.
+TEST_F(ExtensionPrefValueMapTest, ReenableExt) {
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular, CreateVal("val1"));
+ epvm_.SetExtensionState(kExt1, false);
+ epvm_.SetExtensionState(kExt1, true);
+ EXPECT_EQ("val1", GetValue(kPref1, false));
+}
+
+struct OverrideIncognitoTestCase {
+ OverrideIncognitoTestCase(int val_ext1_regular,
+ int val_ext1_regular_only,
+ int val_ext1_incognito_pers,
+ int val_ext1_incognito_sess,
+ int val_ext2_regular,
+ int val_ext2_regular_only,
+ int val_ext2_incognito_pers,
+ int val_ext2_incognito_sess,
+ int effective_value_regular,
+ int effective_value_incognito)
+ : val_ext1_regular_(val_ext1_regular),
+ val_ext1_regular_only_(val_ext1_regular_only),
+ val_ext1_incognito_pers_(val_ext1_incognito_pers),
+ val_ext1_incognito_sess_(val_ext1_incognito_sess),
+ val_ext2_regular_(val_ext2_regular),
+ val_ext2_regular_only_(val_ext2_regular_only),
+ val_ext2_incognito_pers_(val_ext2_incognito_pers),
+ val_ext2_incognito_sess_(val_ext2_incognito_sess),
+ effective_value_regular_(effective_value_regular),
+ effective_value_incognito_(effective_value_incognito) {}
+
+ // pers. = persistent
+ // sess. = session only
+ int val_ext1_regular_; // pref value of extension 1
+ int val_ext1_regular_only_; // pref value of extension 1 regular-only.
+ int val_ext1_incognito_pers_; // pref value of extension 1 incognito pers.
+ int val_ext1_incognito_sess_; // pref value of extension 1 incognito sess.
+ int val_ext2_regular_; // pref value of extension 2
+ int val_ext2_regular_only_; // pref value of extension 2 regular-only.
+ int val_ext2_incognito_pers_; // pref value of extension 2 incognito pers.
+ int val_ext2_incognito_sess_; // pref value of extension 2 incognito sess.
+ int effective_value_regular_; // desired winner regular
+ int effective_value_incognito_; // desired winner incognito
+};
+
+class ExtensionPrefValueMapTestIncognitoTests
+ : public ExtensionPrefValueMapTestBase<
+ testing::TestWithParam<OverrideIncognitoTestCase> > {
+};
+
+TEST_P(ExtensionPrefValueMapTestIncognitoTests, OverrideIncognito) {
+ OverrideIncognitoTestCase test = GetParam();
+ const char* strings[] = {
+ "undefined",
+ "val1",
+ "val2",
+ "val3",
+ "val4",
+ "val5",
+ "val6",
+ "val7",
+ "val8",
+ };
+
+ epvm_.RegisterExtension(kExt1, CreateTime(10), true);
+ epvm_.RegisterExtension(kExt2, CreateTime(20), true);
+ if (test.val_ext1_regular_) {
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegular,
+ CreateVal(strings[test.val_ext1_regular_]));
+ }
+ if (test.val_ext1_regular_only_) {
+ epvm_.SetExtensionPref(kExt1, kPref1, kRegularOnly,
+ CreateVal(strings[test.val_ext1_regular_only_]));
+ }
+ if (test.val_ext1_incognito_pers_) {
+ epvm_.SetExtensionPref(kExt1, kPref1, kIncognitoPersistent,
+ CreateVal(strings[test.val_ext1_incognito_pers_]));
+ }
+ if (test.val_ext1_incognito_sess_) {
+ epvm_.SetExtensionPref(kExt1, kPref1, kIncognitoSessionOnly,
+ CreateVal(strings[test.val_ext1_incognito_sess_]));
+ }
+ if (test.val_ext2_regular_) {
+ epvm_.SetExtensionPref(kExt2, kPref1, kRegular,
+ CreateVal(strings[test.val_ext2_regular_]));
+ }
+ if (test.val_ext2_regular_only_) {
+ epvm_.SetExtensionPref(kExt2, kPref1, kRegularOnly,
+ CreateVal(strings[test.val_ext2_regular_only_]));
+ }
+ if (test.val_ext2_incognito_pers_) {
+ epvm_.SetExtensionPref(kExt2, kPref1, kIncognitoPersistent,
+ CreateVal(strings[test.val_ext2_incognito_pers_]));
+ }
+ if (test.val_ext2_incognito_sess_) {
+ epvm_.SetExtensionPref(kExt2, kPref1, kIncognitoSessionOnly,
+ CreateVal(strings[test.val_ext2_incognito_sess_]));
+ }
+ std::string actual;
+ EXPECT_EQ(strings[test.effective_value_regular_], GetValue(kPref1, false));
+ EXPECT_EQ(strings[test.effective_value_incognito_], GetValue(kPref1, true));
+ epvm_.UnregisterExtension(kExt1);
+ epvm_.UnregisterExtension(kExt2);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ ExtensionPrefValueMapTestIncognitoTestsInstance,
+ ExtensionPrefValueMapTestIncognitoTests,
+ testing::Values(
+ // e.g. (1, 0, 0, 0, 0, 0, 7, 0, 1, 7), means:
+ // ext1 regular is set to "val1", ext2 incognito persistent is set to
+ // "val7"
+ // --> the winning regular value is "val1", the winning incognito
+ // value is "val7".
+ OverrideIncognitoTestCase(1, 0, 0, 0, 0, 0, 0, 0, 1, 1),
+ OverrideIncognitoTestCase(1, 2, 0, 0, 0, 0, 0, 0, 2, 1),
+ OverrideIncognitoTestCase(1, 0, 3, 0, 0, 0, 0, 0, 1, 3),
+ OverrideIncognitoTestCase(1, 0, 0, 4, 0, 0, 0, 0, 1, 4),
+ OverrideIncognitoTestCase(1, 0, 3, 4, 0, 0, 0, 0, 1, 4),
+ OverrideIncognitoTestCase(1, 2, 3, 0, 0, 0, 0, 0, 2, 3),
+ OverrideIncognitoTestCase(1, 0, 0, 0, 5, 0, 0, 0, 5, 5),
+ OverrideIncognitoTestCase(1, 2, 3, 0, 5, 0, 0, 0, 5, 5),
+ OverrideIncognitoTestCase(1, 0, 0, 0, 0, 6, 0, 0, 6, 1),
+ OverrideIncognitoTestCase(1, 0, 3, 0, 5, 6, 0, 0, 6, 5),
+ OverrideIncognitoTestCase(1, 0, 0, 4, 5, 6, 0, 0, 6, 5),
+ OverrideIncognitoTestCase(1, 0, 0, 0, 0, 0, 7, 0, 1, 7),
+ OverrideIncognitoTestCase(1, 2, 0, 0, 5, 0, 7, 0, 5, 7),
+ OverrideIncognitoTestCase(1, 2, 0, 0, 5, 0, 0, 8, 5, 8),
+ OverrideIncognitoTestCase(1, 2, 0, 0, 5, 0, 7, 8, 5, 8),
+ OverrideIncognitoTestCase(1, 2, 3, 0, 0, 6, 7, 0, 6, 7)));
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
new file mode 100644
index 0000000..8e56ed7
--- /dev/null
+++ b/extensions/browser/extension_prefs.cc
@@ -0,0 +1,1892 @@
+// 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_prefs.h"
+
+#include <iterator>
+
+#include "base/command_line.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/value_conversions.h"
+#include "chrome/browser/extensions/api/content_settings/content_settings_store.h"
+#include "chrome/browser/extensions/api/preference/preference_api.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+#include "extensions/browser/admin_policy.h"
+#include "extensions/browser/app_sorting.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_pref_store.h"
+#include "extensions/browser/extension_prefs_factory.h"
+#include "extensions/browser/pref_names.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "extensions/common/url_pattern.h"
+#include "extensions/common/user_script.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using base::Value;
+using base::DictionaryValue;
+using base::ListValue;
+
+namespace extensions {
+
+namespace {
+
+// Additional preferences keys, which are not needed by external clients.
+
+// True if this extension is running. Note this preference stops getting updated
+// during Chrome shutdown (and won't be updated on a browser crash) and so can
+// be used at startup to determine whether the extension was running when Chrome
+// was last terminated.
+const char kPrefRunning[] = "running";
+
+// Whether this extension had windows when it was last running.
+const char kIsActive[] = "is_active";
+
+// Where an extension was installed from. (see Manifest::Location)
+const char kPrefLocation[] = "location";
+
+// Enabled, disabled, killed, etc. (see Extension::State)
+const char kPrefState[] = "state";
+
+// The path to the current version's manifest file.
+const char kPrefPath[] = "path";
+
+// The dictionary containing the extension's manifest.
+const char kPrefManifest[] = "manifest";
+
+// The version number.
+const char kPrefVersion[] = "manifest.version";
+
+// Indicates whether an extension is blacklisted.
+const char kPrefBlacklist[] = "blacklist";
+
+// The count of how many times we prompted the user to acknowledge an
+// extension.
+const char kPrefAcknowledgePromptCount[] = "ack_prompt_count";
+
+// Indicates whether the user has acknowledged various types of extensions.
+const char kPrefExternalAcknowledged[] = "ack_external";
+const char kPrefBlacklistAcknowledged[] = "ack_blacklist";
+const char kPrefWipeoutAcknowledged[] = "ack_wiped";
+
+// Indicates whether the external extension was installed during the first
+// run of this profile.
+const char kPrefExternalInstallFirstRun[] = "external_first_run";
+
+// Indicates whether to show an install warning when the user enables.
+const char kExtensionDidEscalatePermissions[] = "install_warning_on_enable";
+
+// DO NOT USE, use kPrefDisableReasons instead.
+// Indicates whether the extension was updated while it was disabled.
+const char kDeprecatedPrefDisableReason[] = "disable_reason";
+
+// A bitmask of all the reasons an extension is disabled.
+const char kPrefDisableReasons[] = "disable_reasons";
+
+// The key for a serialized Time value indicating the start of the day (from the
+// server's perspective) an extension last included a "ping" parameter during
+// its update check.
+const char kLastPingDay[] = "lastpingday";
+
+// Similar to kLastPingDay, but for "active" instead of "rollcall" pings.
+const char kLastActivePingDay[] = "last_active_pingday";
+
+// A bit we use to keep track of whether we need to do an "active" ping.
+const char kActiveBit[] = "active_bit";
+
+// Path for settings specific to blacklist update.
+const char kExtensionsBlacklistUpdate[] = "extensions.blacklistupdate";
+
+// Path for the delayed install info dictionary preference. The actual string
+// value is a legacy artifact for when delayed installs only pertained to
+// updates that were waiting for idle.
+const char kDelayedInstallInfo[] = "idle_install_info";
+
+// Reason why the extension's install was delayed.
+const char kDelayedInstallReason[] = "delay_install_reason";
+
+// Path for the suggested page ordinal of a delayed extension install.
+const char kPrefSuggestedPageOrdinal[] = "suggested_page_ordinal";
+
+// A preference that, if true, will allow this extension to run in incognito
+// mode.
+const char kPrefIncognitoEnabled[] = "incognito";
+
+// A preference to control whether an extension is allowed to inject script in
+// pages with file URLs.
+const char kPrefAllowFileAccess[] = "newAllowFileAccess";
+// TODO(jstritar): As part of fixing http://crbug.com/91577, we revoked all
+// extension file access by renaming the pref. We should eventually clean up
+// the old flag and possibly go back to that name.
+// const char kPrefAllowFileAccessOld[] = "allowFileAccess";
+
+// A preference specifying if the user dragged the app on the NTP.
+const char kPrefUserDraggedApp[] = "user_dragged_app_ntp";
+
+// Preferences that hold which permissions the user has granted the extension.
+// We explicitly keep track of these so that extensions can contain unknown
+// permissions, for backwards compatibility reasons, and we can still prompt
+// the user to accept them once recognized. We store the active permission
+// permissions because they may differ from those defined in the manifest.
+const char kPrefActivePermissions[] = "active_permissions";
+const char kPrefGrantedPermissions[] = "granted_permissions";
+
+// The preference names for PermissionSet values.
+const char kPrefAPIs[] = "api";
+const char kPrefManifestPermissions[] = "manifest_permissions";
+const char kPrefExplicitHosts[] = "explicit_host";
+const char kPrefScriptableHosts[] = "scriptable_host";
+
+// The preference names for the old granted permissions scheme.
+const char kPrefOldGrantedFullAccess[] = "granted_permissions.full";
+const char kPrefOldGrantedHosts[] = "granted_permissions.host";
+const char kPrefOldGrantedAPIs[] = "granted_permissions.api";
+
+// A preference that indicates when an extension was installed.
+const char kPrefInstallTime[] = "install_time";
+
+// A preference which saves the creation flags for extensions.
+const char kPrefCreationFlags[] = "creation_flags";
+
+// A preference that indicates whether the extension was installed from the
+// Chrome Web Store.
+const char kPrefFromWebStore[] = "from_webstore";
+
+// A preference that indicates whether the extension was installed from a
+// mock App created from a bookmark.
+const char kPrefFromBookmark[] = "from_bookmark";
+
+// A preference that indicates whether the extension was installed as
+// default apps.
+const char kPrefWasInstalledByDefault[] = "was_installed_by_default";
+
+// Key for Geometry Cache preference.
+const char kPrefGeometryCache[] = "geometry_cache";
+
+// A preference that indicates when an extension is last launched.
+const char kPrefLastLaunchTime[] = "last_launch_time";
+
+// A list of installed ids and a signature.
+const char kInstallSignature[] = "extensions.install_signature";
+
+// Provider of write access to a dictionary storing extension prefs.
+class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate {
+ public:
+ ScopedExtensionPrefUpdate(PrefService* service,
+ const std::string& extension_id) :
+ DictionaryPrefUpdate(service, pref_names::kExtensions),
+ extension_id_(extension_id) {}
+
+ virtual ~ScopedExtensionPrefUpdate() {
+ }
+
+ // DictionaryPrefUpdate overrides:
+ virtual base::DictionaryValue* Get() OVERRIDE {
+ base::DictionaryValue* dict = DictionaryPrefUpdate::Get();
+ base::DictionaryValue* extension = NULL;
+ if (!dict->GetDictionary(extension_id_, &extension)) {
+ // Extension pref does not exist, create it.
+ extension = new base::DictionaryValue();
+ dict->SetWithoutPathExpansion(extension_id_, extension);
+ }
+ return extension;
+ }
+
+ private:
+ const std::string extension_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedExtensionPrefUpdate);
+};
+
+std::string JoinPrefs(const std::string& parent, const char* child) {
+ return parent + "." + child;
+}
+
+// Checks if kPrefBlacklist is set to true in the base::DictionaryValue.
+// Return false if the value is false or kPrefBlacklist does not exist.
+// This is used to decide if an extension is blacklisted.
+bool IsBlacklistBitSet(const base::DictionaryValue* ext) {
+ bool bool_value;
+ return ext->GetBoolean(kPrefBlacklist, &bool_value) && bool_value;
+}
+
+} // namespace
+
+//
+// TimeProvider
+//
+
+ExtensionPrefs::TimeProvider::TimeProvider() {
+}
+
+ExtensionPrefs::TimeProvider::~TimeProvider() {
+}
+
+base::Time ExtensionPrefs::TimeProvider::GetCurrentTime() const {
+ return base::Time::Now();
+}
+
+//
+// ScopedUpdate
+//
+template <typename T, base::Value::Type type_enum_value>
+ExtensionPrefs::ScopedUpdate<T, type_enum_value>::ScopedUpdate(
+ ExtensionPrefs* prefs,
+ const std::string& extension_id,
+ const std::string& key)
+ : update_(prefs->pref_service(), pref_names::kExtensions),
+ extension_id_(extension_id),
+ key_(key) {
+ DCHECK(Extension::IdIsValid(extension_id_));
+}
+
+template <typename T, base::Value::Type type_enum_value>
+ExtensionPrefs::ScopedUpdate<T, type_enum_value>::~ScopedUpdate() {
+}
+
+template <typename T, base::Value::Type type_enum_value>
+T* ExtensionPrefs::ScopedUpdate<T, type_enum_value>::Get() {
+ base::DictionaryValue* dict = update_.Get();
+ base::DictionaryValue* extension = NULL;
+ base::Value* key_value = NULL;
+ if (!dict->GetDictionary(extension_id_, &extension) ||
+ !extension->Get(key_, &key_value)) {
+ return NULL;
+ }
+ return key_value->GetType() == type_enum_value ?
+ static_cast<T*>(key_value) :
+ NULL;
+}
+
+template <typename T, base::Value::Type type_enum_value>
+T* ExtensionPrefs::ScopedUpdate<T, type_enum_value>::Create() {
+ base::DictionaryValue* dict = update_.Get();
+ base::DictionaryValue* extension = NULL;
+ base::Value* key_value = NULL;
+ T* value_as_t = NULL;
+ if (!dict->GetDictionary(extension_id_, &extension)) {
+ extension = new base::DictionaryValue;
+ dict->SetWithoutPathExpansion(extension_id_, extension);
+ }
+ if (!extension->Get(key_, &key_value)) {
+ value_as_t = new T;
+ extension->SetWithoutPathExpansion(key_, value_as_t);
+ } else {
+ CHECK(key_value->GetType() == type_enum_value);
+ value_as_t = static_cast<T*>(key_value);
+ }
+ return value_as_t;
+}
+
+// Explicit instantiations for Dictionary and List value types.
+template class ExtensionPrefs::ScopedUpdate<base::DictionaryValue,
+ base::Value::TYPE_DICTIONARY>;
+template class ExtensionPrefs::ScopedUpdate<base::ListValue,
+ base::Value::TYPE_LIST>;
+
+//
+// ExtensionPrefs
+//
+
+// static
+ExtensionPrefs* ExtensionPrefs::Create(
+ PrefService* prefs,
+ const base::FilePath& root_dir,
+ ExtensionPrefValueMap* extension_pref_value_map,
+ scoped_ptr<AppSorting> app_sorting,
+ bool extensions_disabled) {
+ return ExtensionPrefs::Create(prefs,
+ root_dir,
+ extension_pref_value_map,
+ app_sorting.Pass(),
+ extensions_disabled,
+ make_scoped_ptr(new TimeProvider()));
+}
+
+// static
+ExtensionPrefs* ExtensionPrefs::Create(
+ PrefService* pref_service,
+ const base::FilePath& root_dir,
+ ExtensionPrefValueMap* extension_pref_value_map,
+ scoped_ptr<AppSorting> app_sorting,
+ bool extensions_disabled,
+ scoped_ptr<TimeProvider> time_provider) {
+ return new ExtensionPrefs(pref_service,
+ root_dir,
+ extension_pref_value_map,
+ app_sorting.Pass(),
+ time_provider.Pass(),
+ extensions_disabled);
+}
+
+ExtensionPrefs::~ExtensionPrefs() {
+}
+
+// static
+ExtensionPrefs* ExtensionPrefs::Get(content::BrowserContext* context) {
+ return ExtensionPrefsFactory::GetInstance()->GetForBrowserContext(context);
+}
+
+static base::FilePath::StringType MakePathRelative(const base::FilePath& parent,
+ const base::FilePath& child) {
+ if (!parent.IsParent(child))
+ return child.value();
+
+ base::FilePath::StringType retval = child.value().substr(
+ parent.value().length());
+ if (base::FilePath::IsSeparator(retval[0]))
+ return retval.substr(1);
+ else
+ return retval;
+}
+
+void ExtensionPrefs::MakePathsRelative() {
+ const base::DictionaryValue* dict =
+ prefs_->GetDictionary(pref_names::kExtensions);
+ if (!dict || dict->empty())
+ return;
+
+ // Collect all extensions ids with absolute paths in |absolute_keys|.
+ std::set<std::string> absolute_keys;
+ for (base::DictionaryValue::Iterator i(*dict); !i.IsAtEnd(); i.Advance()) {
+ const base::DictionaryValue* extension_dict = NULL;
+ if (!i.value().GetAsDictionary(&extension_dict))
+ continue;
+ int location_value;
+ if (extension_dict->GetInteger(kPrefLocation, &location_value) &&
+ Manifest::IsUnpackedLocation(
+ static_cast<Manifest::Location>(location_value))) {
+ // Unpacked extensions can have absolute paths.
+ continue;
+ }
+ base::FilePath::StringType path_string;
+ if (!extension_dict->GetString(kPrefPath, &path_string))
+ continue;
+ base::FilePath path(path_string);
+ if (path.IsAbsolute())
+ absolute_keys.insert(i.key());
+ }
+ if (absolute_keys.empty())
+ return;
+
+ // Fix these paths.
+ DictionaryPrefUpdate update(prefs_, pref_names::kExtensions);
+ base::DictionaryValue* update_dict = update.Get();
+ for (std::set<std::string>::iterator i = absolute_keys.begin();
+ i != absolute_keys.end(); ++i) {
+ base::DictionaryValue* extension_dict = NULL;
+ if (!update_dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict)) {
+ NOTREACHED() << "Control should never reach here for extension " << *i;
+ continue;
+ }
+ base::FilePath::StringType path_string;
+ extension_dict->GetString(kPrefPath, &path_string);
+ base::FilePath path(path_string);
+ extension_dict->SetString(kPrefPath,
+ MakePathRelative(install_directory_, path));
+ }
+}
+
+const base::DictionaryValue* ExtensionPrefs::GetExtensionPref(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* extensions =
+ prefs_->GetDictionary(pref_names::kExtensions);
+ const base::DictionaryValue* extension_dict = NULL;
+ if (!extensions ||
+ !extensions->GetDictionary(extension_id, &extension_dict)) {
+ return NULL;
+ }
+ return extension_dict;
+}
+
+void ExtensionPrefs::UpdateExtensionPref(const std::string& extension_id,
+ const std::string& key,
+ base::Value* data_value) {
+ if (!Extension::IdIsValid(extension_id)) {
+ NOTREACHED() << "Invalid extension_id " << extension_id;
+ return;
+ }
+ ScopedExtensionPrefUpdate update(prefs_, extension_id);
+ if (data_value)
+ update->Set(key, data_value);
+ else
+ update->Remove(key, NULL);
+}
+
+void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) {
+ extension_pref_value_map_->UnregisterExtension(extension_id);
+ content_settings_store_->UnregisterExtension(extension_id);
+ DictionaryPrefUpdate update(prefs_, pref_names::kExtensions);
+ base::DictionaryValue* dict = update.Get();
+ dict->Remove(extension_id, NULL);
+}
+
+bool ExtensionPrefs::ReadPrefAsBoolean(const std::string& extension_id,
+ const std::string& pref_key,
+ bool* out_value) const {
+ const base::DictionaryValue* ext = GetExtensionPref(extension_id);
+ if (!ext || !ext->GetBoolean(pref_key, out_value))
+ return false;
+
+ return true;
+}
+
+bool ExtensionPrefs::ReadPrefAsInteger(const std::string& extension_id,
+ const std::string& pref_key,
+ int* out_value) const {
+ const base::DictionaryValue* ext = GetExtensionPref(extension_id);
+ if (!ext || !ext->GetInteger(pref_key, out_value))
+ return false;
+
+ return true;
+}
+
+bool ExtensionPrefs::ReadPrefAsString(const std::string& extension_id,
+ const std::string& pref_key,
+ std::string* out_value) const {
+ const base::DictionaryValue* ext = GetExtensionPref(extension_id);
+ if (!ext || !ext->GetString(pref_key, out_value))
+ return false;
+
+ return true;
+}
+
+bool ExtensionPrefs::ReadPrefAsList(const std::string& extension_id,
+ const std::string& pref_key,
+ const base::ListValue** out_value) const {
+ const base::DictionaryValue* ext = GetExtensionPref(extension_id);
+ const base::ListValue* out = NULL;
+ if (!ext || !ext->GetList(pref_key, &out))
+ return false;
+ if (out_value)
+ *out_value = out;
+
+ return true;
+}
+
+bool ExtensionPrefs::ReadPrefAsDictionary(
+ const std::string& extension_id,
+ const std::string& pref_key,
+ const base::DictionaryValue** out_value) const {
+ const base::DictionaryValue* ext = GetExtensionPref(extension_id);
+ const base::DictionaryValue* out = NULL;
+ if (!ext || !ext->GetDictionary(pref_key, &out))
+ return false;
+ if (out_value)
+ *out_value = out;
+
+ return true;
+}
+
+bool ExtensionPrefs::HasPrefForExtension(
+ const std::string& extension_id) const {
+ return GetExtensionPref(extension_id) != NULL;
+}
+
+bool ExtensionPrefs::ReadPrefAsURLPatternSet(const std::string& extension_id,
+ const std::string& pref_key,
+ URLPatternSet* result,
+ int valid_schemes) {
+ const base::ListValue* value = NULL;
+ if (!ReadPrefAsList(extension_id, pref_key, &value))
+ return false;
+
+ bool allow_file_access = AllowFileAccess(extension_id);
+ return result->Populate(*value, valid_schemes, allow_file_access, NULL);
+}
+
+void ExtensionPrefs::SetExtensionPrefURLPatternSet(
+ const std::string& extension_id,
+ const std::string& pref_key,
+ const URLPatternSet& new_value) {
+ UpdateExtensionPref(extension_id, pref_key, new_value.ToValue().release());
+}
+
+bool ExtensionPrefs::ReadPrefAsBooleanAndReturn(
+ const std::string& extension_id,
+ const std::string& pref_key) const {
+ bool out_value = false;
+ return ReadPrefAsBoolean(extension_id, pref_key, &out_value) && out_value;
+}
+
+PermissionSet* ExtensionPrefs::ReadPrefAsPermissionSet(
+ const std::string& extension_id,
+ const std::string& pref_key) {
+ if (!GetExtensionPref(extension_id))
+ return NULL;
+
+ // Retrieve the API permissions. Please refer SetExtensionPrefPermissionSet()
+ // for api_values format.
+ APIPermissionSet apis;
+ const base::ListValue* api_values = NULL;
+ std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
+ if (ReadPrefAsList(extension_id, api_pref, &api_values)) {
+ APIPermissionSet::ParseFromJSON(api_values,
+ APIPermissionSet::kAllowInternalPermissions,
+ &apis, NULL, NULL);
+ }
+
+ // Retrieve the Manifest Keys permissions. Please refer to
+ // |SetExtensionPrefPermissionSet| for manifest_permissions_values format.
+ ManifestPermissionSet manifest_permissions;
+ const base::ListValue* manifest_permissions_values = NULL;
+ std::string manifest_permission_pref =
+ JoinPrefs(pref_key, kPrefManifestPermissions);
+ if (ReadPrefAsList(extension_id, manifest_permission_pref,
+ &manifest_permissions_values)) {
+ ManifestPermissionSet::ParseFromJSON(
+ manifest_permissions_values, &manifest_permissions, NULL, NULL);
+ }
+
+ // Retrieve the explicit host permissions.
+ URLPatternSet explicit_hosts;
+ ReadPrefAsURLPatternSet(
+ extension_id, JoinPrefs(pref_key, kPrefExplicitHosts),
+ &explicit_hosts, Extension::kValidHostPermissionSchemes);
+
+ // Retrieve the scriptable host permissions.
+ URLPatternSet scriptable_hosts;
+ ReadPrefAsURLPatternSet(
+ extension_id, JoinPrefs(pref_key, kPrefScriptableHosts),
+ &scriptable_hosts, UserScript::ValidUserScriptSchemes());
+
+ return new PermissionSet(
+ apis, manifest_permissions, explicit_hosts, scriptable_hosts);
+}
+
+// Set the API or Manifest permissions.
+// The format of api_values is:
+// [ "permission_name1", // permissions do not support detail.
+// "permission_name2",
+// {"permission_name3": value },
+// // permission supports detail, permission detail will be stored in value.
+// ...
+// ]
+template<typename T>
+static base::ListValue* CreatePermissionList(const T& permissions) {
+ base::ListValue* values = new base::ListValue();
+ for (typename T::const_iterator i = permissions.begin();
+ i != permissions.end(); ++i) {
+ scoped_ptr<base::Value> detail(i->ToValue());
+ if (detail) {
+ base::DictionaryValue* tmp = new base::DictionaryValue();
+ tmp->Set(i->name(), detail.release());
+ values->Append(tmp);
+ } else {
+ values->Append(new base::StringValue(i->name()));
+ }
+ }
+ return values;
+}
+
+void ExtensionPrefs::SetExtensionPrefPermissionSet(
+ const std::string& extension_id,
+ const std::string& pref_key,
+ const PermissionSet* new_value) {
+ std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
+ base::ListValue* api_values = CreatePermissionList(new_value->apis());
+ UpdateExtensionPref(extension_id, api_pref, api_values);
+
+ std::string manifest_permissions_pref =
+ JoinPrefs(pref_key, kPrefManifestPermissions);
+ base::ListValue* manifest_permissions_values = CreatePermissionList(
+ new_value->manifest_permissions());
+ UpdateExtensionPref(extension_id,
+ manifest_permissions_pref,
+ manifest_permissions_values);
+
+ // Set the explicit host permissions.
+ if (!new_value->explicit_hosts().is_empty()) {
+ SetExtensionPrefURLPatternSet(extension_id,
+ JoinPrefs(pref_key, kPrefExplicitHosts),
+ new_value->explicit_hosts());
+ }
+
+ // Set the scriptable host permissions.
+ if (!new_value->scriptable_hosts().is_empty()) {
+ SetExtensionPrefURLPatternSet(extension_id,
+ JoinPrefs(pref_key, kPrefScriptableHosts),
+ new_value->scriptable_hosts());
+ }
+}
+
+int ExtensionPrefs::IncrementAcknowledgePromptCount(
+ const std::string& extension_id) {
+ int count = 0;
+ ReadPrefAsInteger(extension_id, kPrefAcknowledgePromptCount, &count);
+ ++count;
+ UpdateExtensionPref(extension_id, kPrefAcknowledgePromptCount,
+ new base::FundamentalValue(count));
+ return count;
+}
+
+bool ExtensionPrefs::IsExternalExtensionAcknowledged(
+ const std::string& extension_id) {
+ return ReadPrefAsBooleanAndReturn(extension_id, kPrefExternalAcknowledged);
+}
+
+void ExtensionPrefs::AcknowledgeExternalExtension(
+ const std::string& extension_id) {
+ DCHECK(Extension::IdIsValid(extension_id));
+ UpdateExtensionPref(extension_id, kPrefExternalAcknowledged,
+ new base::FundamentalValue(true));
+ UpdateExtensionPref(extension_id, kPrefAcknowledgePromptCount, NULL);
+}
+
+bool ExtensionPrefs::IsBlacklistedExtensionAcknowledged(
+ const std::string& extension_id) {
+ return ReadPrefAsBooleanAndReturn(extension_id, kPrefBlacklistAcknowledged);
+}
+
+void ExtensionPrefs::AcknowledgeBlacklistedExtension(
+ const std::string& extension_id) {
+ DCHECK(Extension::IdIsValid(extension_id));
+ UpdateExtensionPref(extension_id, kPrefBlacklistAcknowledged,
+ new base::FundamentalValue(true));
+ UpdateExtensionPref(extension_id, kPrefAcknowledgePromptCount, NULL);
+}
+
+bool ExtensionPrefs::IsExternalInstallFirstRun(
+ const std::string& extension_id) {
+ return ReadPrefAsBooleanAndReturn(extension_id, kPrefExternalInstallFirstRun);
+}
+
+void ExtensionPrefs::SetExternalInstallFirstRun(
+ const std::string& extension_id) {
+ DCHECK(Extension::IdIsValid(extension_id));
+ UpdateExtensionPref(extension_id, kPrefExternalInstallFirstRun,
+ new base::FundamentalValue(true));
+}
+
+bool ExtensionPrefs::HasWipeoutBeenAcknowledged(
+ const std::string& extension_id) {
+ return ReadPrefAsBooleanAndReturn(extension_id, kPrefWipeoutAcknowledged);
+}
+
+void ExtensionPrefs::SetWipeoutAcknowledged(
+ const std::string& extension_id,
+ bool value) {
+ UpdateExtensionPref(extension_id, kPrefWipeoutAcknowledged,
+ value ? base::Value::CreateBooleanValue(value) : NULL);
+}
+
+bool ExtensionPrefs::SetAlertSystemFirstRun() {
+ if (prefs_->GetBoolean(pref_names::kAlertsInitialized)) {
+ return true;
+ }
+ prefs_->SetBoolean(pref_names::kAlertsInitialized, true);
+ return false;
+}
+
+bool ExtensionPrefs::ExtensionsBlacklistedByDefault() const {
+ return admin_policy::BlacklistedByDefault(
+ prefs_->GetList(pref_names::kInstallDenyList));
+}
+
+bool ExtensionPrefs::DidExtensionEscalatePermissions(
+ const std::string& extension_id) {
+ return ReadPrefAsBooleanAndReturn(extension_id,
+ kExtensionDidEscalatePermissions);
+}
+
+void ExtensionPrefs::SetDidExtensionEscalatePermissions(
+ const Extension* extension, bool did_escalate) {
+ UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions,
+ new base::FundamentalValue(did_escalate));
+}
+
+int ExtensionPrefs::GetDisableReasons(const std::string& extension_id) const {
+ int value = -1;
+ if (ReadPrefAsInteger(extension_id, kPrefDisableReasons, &value) &&
+ value >= 0) {
+ return value;
+ }
+ return Extension::DISABLE_NONE;
+}
+
+void ExtensionPrefs::AddDisableReason(const std::string& extension_id,
+ Extension::DisableReason disable_reason) {
+ int new_value = GetDisableReasons(extension_id) |
+ static_cast<int>(disable_reason);
+ UpdateExtensionPref(extension_id, kPrefDisableReasons,
+ new base::FundamentalValue(new_value));
+}
+
+void ExtensionPrefs::RemoveDisableReason(
+ const std::string& extension_id,
+ Extension::DisableReason disable_reason) {
+ int new_value = GetDisableReasons(extension_id) &
+ ~static_cast<int>(disable_reason);
+ if (new_value == Extension::DISABLE_NONE) {
+ UpdateExtensionPref(extension_id, kPrefDisableReasons, NULL);
+ } else {
+ UpdateExtensionPref(extension_id, kPrefDisableReasons,
+ new base::FundamentalValue(new_value));
+ }
+}
+
+void ExtensionPrefs::ClearDisableReasons(const std::string& extension_id) {
+ UpdateExtensionPref(extension_id, kPrefDisableReasons, NULL);
+}
+
+std::set<std::string> ExtensionPrefs::GetBlacklistedExtensions() {
+ std::set<std::string> ids;
+
+ const base::DictionaryValue* extensions =
+ prefs_->GetDictionary(pref_names::kExtensions);
+ if (!extensions)
+ return ids;
+
+ for (base::DictionaryValue::Iterator it(*extensions);
+ !it.IsAtEnd(); it.Advance()) {
+ if (!it.value().IsType(base::Value::TYPE_DICTIONARY)) {
+ NOTREACHED() << "Invalid pref for extension " << it.key();
+ continue;
+ }
+ if (IsBlacklistBitSet(
+ static_cast<const base::DictionaryValue*>(&it.value()))) {
+ ids.insert(it.key());
+ }
+ }
+
+ return ids;
+}
+
+void ExtensionPrefs::SetExtensionBlacklisted(const std::string& extension_id,
+ bool is_blacklisted) {
+ bool currently_blacklisted = IsExtensionBlacklisted(extension_id);
+ if (is_blacklisted == currently_blacklisted) {
+ NOTREACHED() << extension_id << " is " <<
+ (currently_blacklisted ? "already" : "not") <<
+ " blacklisted";
+ return;
+ }
+
+ // Always make sure the "acknowledged" bit is cleared since the blacklist bit
+ // is changing.
+ UpdateExtensionPref(extension_id, kPrefBlacklistAcknowledged, NULL);
+
+ if (is_blacklisted) {
+ UpdateExtensionPref(extension_id,
+ kPrefBlacklist,
+ new base::FundamentalValue(true));
+ } else {
+ UpdateExtensionPref(extension_id, kPrefBlacklist, NULL);
+ const base::DictionaryValue* dict = GetExtensionPref(extension_id);
+ if (dict && dict->empty())
+ DeleteExtensionPrefs(extension_id);
+ }
+}
+
+bool ExtensionPrefs::IsExtensionBlacklisted(const std::string& id) const {
+ const base::DictionaryValue* ext_prefs = GetExtensionPref(id);
+ return ext_prefs && IsBlacklistBitSet(ext_prefs);
+}
+
+namespace {
+
+// Serializes |time| as a string value mapped to |key| in |dictionary|.
+void SaveTime(base::DictionaryValue* dictionary,
+ const char* key,
+ const base::Time& time) {
+ if (!dictionary)
+ return;
+ std::string string_value = base::Int64ToString(time.ToInternalValue());
+ dictionary->SetString(key, string_value);
+}
+
+// The opposite of SaveTime. If |key| is not found, this returns an empty Time
+// (is_null() will return true).
+base::Time ReadTime(const base::DictionaryValue* dictionary, const char* key) {
+ if (!dictionary)
+ return base::Time();
+ std::string string_value;
+ int64 value;
+ if (dictionary->GetString(key, &string_value)) {
+ if (base::StringToInt64(string_value, &value)) {
+ return base::Time::FromInternalValue(value);
+ }
+ }
+ return base::Time();
+}
+
+} // namespace
+
+base::Time ExtensionPrefs::LastPingDay(const std::string& extension_id) const {
+ DCHECK(Extension::IdIsValid(extension_id));
+ return ReadTime(GetExtensionPref(extension_id), kLastPingDay);
+}
+
+void ExtensionPrefs::SetLastPingDay(const std::string& extension_id,
+ const base::Time& time) {
+ DCHECK(Extension::IdIsValid(extension_id));
+ ScopedExtensionPrefUpdate update(prefs_, extension_id);
+ SaveTime(update.Get(), kLastPingDay, time);
+}
+
+base::Time ExtensionPrefs::BlacklistLastPingDay() const {
+ return ReadTime(prefs_->GetDictionary(kExtensionsBlacklistUpdate),
+ kLastPingDay);
+}
+
+void ExtensionPrefs::SetBlacklistLastPingDay(const base::Time& time) {
+ DictionaryPrefUpdate update(prefs_, kExtensionsBlacklistUpdate);
+ SaveTime(update.Get(), kLastPingDay, time);
+}
+
+base::Time ExtensionPrefs::LastActivePingDay(const std::string& extension_id) {
+ DCHECK(Extension::IdIsValid(extension_id));
+ return ReadTime(GetExtensionPref(extension_id), kLastActivePingDay);
+}
+
+void ExtensionPrefs::SetLastActivePingDay(const std::string& extension_id,
+ const base::Time& time) {
+ DCHECK(Extension::IdIsValid(extension_id));
+ ScopedExtensionPrefUpdate update(prefs_, extension_id);
+ SaveTime(update.Get(), kLastActivePingDay, time);
+}
+
+bool ExtensionPrefs::GetActiveBit(const std::string& extension_id) {
+ const base::DictionaryValue* dictionary = GetExtensionPref(extension_id);
+ bool result = false;
+ if (dictionary && dictionary->GetBoolean(kActiveBit, &result))
+ return result;
+ return false;
+}
+
+void ExtensionPrefs::SetActiveBit(const std::string& extension_id,
+ bool active) {
+ UpdateExtensionPref(extension_id, kActiveBit,
+ new base::FundamentalValue(active));
+}
+
+void ExtensionPrefs::MigratePermissions(const ExtensionIdList& extension_ids) {
+ PermissionsInfo* info = PermissionsInfo::GetInstance();
+ for (ExtensionIdList::const_iterator ext_id =
+ extension_ids.begin(); ext_id != extension_ids.end(); ++ext_id) {
+
+ // An extension's granted permissions need to be migrated if the
+ // full_access bit is present. This bit was always present in the previous
+ // scheme and is never present now.
+ bool full_access;
+ const base::DictionaryValue* ext = GetExtensionPref(*ext_id);
+ if (!ext || !ext->GetBoolean(kPrefOldGrantedFullAccess, &full_access))
+ continue;
+
+ // Remove the full access bit (empty list will get trimmed).
+ UpdateExtensionPref(
+ *ext_id, kPrefOldGrantedFullAccess, new base::ListValue());
+
+ // Add the plugin permission if the full access bit was set.
+ if (full_access) {
+ const base::ListValue* apis = NULL;
+ base::ListValue* new_apis = NULL;
+
+ std::string granted_apis =
+ JoinPrefs(kPrefGrantedPermissions, kPrefAPIs);
+ if (ext->GetList(kPrefOldGrantedAPIs, &apis))
+ new_apis = apis->DeepCopy();
+ else
+ new_apis = new base::ListValue();
+
+ std::string plugin_name = info->GetByID(
+ APIPermission::kPlugin)->name();
+ new_apis->Append(new base::StringValue(plugin_name));
+ UpdateExtensionPref(*ext_id, granted_apis, new_apis);
+ }
+
+ // The granted permissions originally only held the effective hosts,
+ // which are a combination of host and user script host permissions.
+ // We now maintain these lists separately. For migration purposes, it
+ // does not matter how we treat the old effective hosts as long as the
+ // new effective hosts will be the same, so we move them to explicit
+ // host permissions.
+ const base::ListValue* hosts = NULL;
+ std::string explicit_hosts =
+ JoinPrefs(kPrefGrantedPermissions, kPrefExplicitHosts);
+ if (ext->GetList(kPrefOldGrantedHosts, &hosts)) {
+ UpdateExtensionPref(
+ *ext_id, explicit_hosts, hosts->DeepCopy());
+
+ // We can get rid of the old one by setting it to an empty list.
+ UpdateExtensionPref(*ext_id, kPrefOldGrantedHosts, new base::ListValue());
+ }
+ }
+}
+
+void ExtensionPrefs::MigrateDisableReasons(
+ const ExtensionIdList& extension_ids) {
+ for (ExtensionIdList::const_iterator ext_id =
+ extension_ids.begin(); ext_id != extension_ids.end(); ++ext_id) {
+ int value = -1;
+ if (ReadPrefAsInteger(*ext_id, kDeprecatedPrefDisableReason, &value)) {
+ int new_value = Extension::DISABLE_NONE;
+ switch (value) {
+ case Extension::DEPRECATED_DISABLE_USER_ACTION:
+ new_value = Extension::DISABLE_USER_ACTION;
+ break;
+ case Extension::DEPRECATED_DISABLE_PERMISSIONS_INCREASE:
+ new_value = Extension::DISABLE_PERMISSIONS_INCREASE;
+ break;
+ case Extension::DEPRECATED_DISABLE_RELOAD:
+ new_value = Extension::DISABLE_RELOAD;
+ break;
+ }
+
+ UpdateExtensionPref(*ext_id, kPrefDisableReasons,
+ new base::FundamentalValue(new_value));
+ // Remove the old disable reason.
+ UpdateExtensionPref(*ext_id, kDeprecatedPrefDisableReason, NULL);
+ }
+ }
+}
+
+PermissionSet* ExtensionPrefs::GetGrantedPermissions(
+ const std::string& extension_id) {
+ CHECK(Extension::IdIsValid(extension_id));
+ return ReadPrefAsPermissionSet(extension_id, kPrefGrantedPermissions);
+}
+
+void ExtensionPrefs::AddGrantedPermissions(
+ const std::string& extension_id,
+ const PermissionSet* permissions) {
+ CHECK(Extension::IdIsValid(extension_id));
+
+ scoped_refptr<PermissionSet> granted_permissions(
+ GetGrantedPermissions(extension_id));
+
+ // The new granted permissions are the union of the already granted
+ // permissions and the newly granted permissions.
+ scoped_refptr<PermissionSet> new_perms(
+ PermissionSet::CreateUnion(
+ permissions, granted_permissions.get()));
+
+ SetExtensionPrefPermissionSet(
+ extension_id, kPrefGrantedPermissions, new_perms.get());
+}
+
+void ExtensionPrefs::RemoveGrantedPermissions(
+ const std::string& extension_id,
+ const PermissionSet* permissions) {
+ CHECK(Extension::IdIsValid(extension_id));
+
+ scoped_refptr<PermissionSet> granted_permissions(
+ GetGrantedPermissions(extension_id));
+
+ // The new granted permissions are the difference of the already granted
+ // permissions and the newly ungranted permissions.
+ scoped_refptr<PermissionSet> new_perms(
+ PermissionSet::CreateDifference(
+ granted_permissions.get(), permissions));
+
+ SetExtensionPrefPermissionSet(
+ extension_id, kPrefGrantedPermissions, new_perms.get());
+}
+
+PermissionSet* ExtensionPrefs::GetActivePermissions(
+ const std::string& extension_id) {
+ CHECK(Extension::IdIsValid(extension_id));
+ return ReadPrefAsPermissionSet(extension_id, kPrefActivePermissions);
+}
+
+void ExtensionPrefs::SetActivePermissions(
+ const std::string& extension_id,
+ const PermissionSet* permissions) {
+ SetExtensionPrefPermissionSet(
+ extension_id, kPrefActivePermissions, permissions);
+}
+
+void ExtensionPrefs::SetExtensionRunning(const std::string& extension_id,
+ bool is_running) {
+ base::Value* value = new base::FundamentalValue(is_running);
+ UpdateExtensionPref(extension_id, kPrefRunning, value);
+}
+
+bool ExtensionPrefs::IsExtensionRunning(const std::string& extension_id) {
+ const base::DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension)
+ return false;
+ bool running = false;
+ extension->GetBoolean(kPrefRunning, &running);
+ return running;
+}
+
+void ExtensionPrefs::SetIsActive(const std::string& extension_id,
+ bool is_active) {
+ base::Value* value = new base::FundamentalValue(is_active);
+ UpdateExtensionPref(extension_id, kIsActive, value);
+}
+
+bool ExtensionPrefs::IsActive(const std::string& extension_id) {
+ const base::DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension)
+ return false;
+ bool is_active = false;
+ extension->GetBoolean(kIsActive, &is_active);
+ return is_active;
+}
+
+bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) const {
+ return ReadPrefAsBooleanAndReturn(extension_id, kPrefIncognitoEnabled);
+}
+
+void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id,
+ bool enabled) {
+ UpdateExtensionPref(extension_id, kPrefIncognitoEnabled,
+ new base::FundamentalValue(enabled));
+}
+
+bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) const {
+ return ReadPrefAsBooleanAndReturn(extension_id, kPrefAllowFileAccess);
+}
+
+void ExtensionPrefs::SetAllowFileAccess(const std::string& extension_id,
+ bool allow) {
+ UpdateExtensionPref(extension_id, kPrefAllowFileAccess,
+ new base::FundamentalValue(allow));
+}
+
+bool ExtensionPrefs::HasAllowFileAccessSetting(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* ext = GetExtensionPref(extension_id);
+ return ext && ext->HasKey(kPrefAllowFileAccess);
+}
+
+bool ExtensionPrefs::DoesExtensionHaveState(
+ const std::string& id, Extension::State check_state) const {
+ const base::DictionaryValue* extension = GetExtensionPref(id);
+ int state = -1;
+ if (!extension || !extension->GetInteger(kPrefState, &state))
+ return false;
+
+ if (state < 0 || state >= Extension::NUM_STATES) {
+ LOG(ERROR) << "Bad pref 'state' for extension '" << id << "'";
+ return false;
+ }
+
+ return state == check_state;
+}
+
+bool ExtensionPrefs::IsExternalExtensionUninstalled(
+ const std::string& id) const {
+ return DoesExtensionHaveState(id, Extension::EXTERNAL_EXTENSION_UNINSTALLED);
+}
+
+bool ExtensionPrefs::IsExtensionDisabled(
+ const std::string& id) const {
+ return DoesExtensionHaveState(id, Extension::DISABLED);
+}
+
+ExtensionIdList ExtensionPrefs::GetToolbarOrder() {
+ ExtensionIdList id_list_out;
+ GetUserExtensionPrefIntoContainer(pref_names::kToolbar, &id_list_out);
+ return id_list_out;
+}
+
+void ExtensionPrefs::SetToolbarOrder(const ExtensionIdList& extension_ids) {
+ SetExtensionPrefFromContainer(pref_names::kToolbar, extension_ids);
+}
+
+bool ExtensionPrefs::GetKnownDisabled(ExtensionIdSet* id_set_out) {
+ return GetUserExtensionPrefIntoContainer(pref_names::kKnownDisabled,
+ id_set_out);
+}
+
+void ExtensionPrefs::SetKnownDisabled(const ExtensionIdSet& extension_ids) {
+ SetExtensionPrefFromContainer(pref_names::kKnownDisabled, extension_ids);
+}
+
+void ExtensionPrefs::OnExtensionInstalled(
+ const Extension* extension,
+ Extension::State initial_state,
+ bool blacklisted_for_malware,
+ const syncer::StringOrdinal& page_ordinal) {
+ ScopedExtensionPrefUpdate update(prefs_, extension->id());
+ base::DictionaryValue* extension_dict = update.Get();
+ const base::Time install_time = time_provider_->GetCurrentTime();
+ PopulateExtensionInfoPrefs(extension, install_time, initial_state,
+ blacklisted_for_malware, extension_dict);
+ FinishExtensionInfoPrefs(extension->id(), install_time,
+ extension->RequiresSortOrdinal(),
+ page_ordinal, extension_dict);
+}
+
+void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
+ const Manifest::Location& location,
+ bool external_uninstall) {
+ app_sorting_->ClearOrdinals(extension_id);
+
+ // For external extensions, we save a preference reminding ourself not to try
+ // and install the extension anymore (except when |external_uninstall| is
+ // true, which signifies that the registry key was deleted or the pref file
+ // no longer lists the extension).
+ if (!external_uninstall && Manifest::IsExternalLocation(location)) {
+ UpdateExtensionPref(extension_id, kPrefState,
+ new base::FundamentalValue(
+ Extension::EXTERNAL_EXTENSION_UNINSTALLED));
+ extension_pref_value_map_->SetExtensionState(extension_id, false);
+ content_settings_store_->SetExtensionState(extension_id, false);
+ } else {
+ DeleteExtensionPrefs(extension_id);
+ }
+}
+
+void ExtensionPrefs::SetExtensionState(const std::string& extension_id,
+ Extension::State state) {
+ UpdateExtensionPref(extension_id, kPrefState,
+ new base::FundamentalValue(state));
+ bool enabled = (state == Extension::ENABLED);
+ extension_pref_value_map_->SetExtensionState(extension_id, enabled);
+ content_settings_store_->SetExtensionState(extension_id, enabled);
+}
+
+std::string ExtensionPrefs::GetVersionString(const std::string& extension_id) {
+ const base::DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension)
+ return std::string();
+
+ std::string version;
+ extension->GetString(kPrefVersion, &version);
+
+ return version;
+}
+
+void ExtensionPrefs::UpdateManifest(const Extension* extension) {
+ if (!Manifest::IsUnpackedLocation(extension->location())) {
+ const base::DictionaryValue* extension_dict =
+ GetExtensionPref(extension->id());
+ if (!extension_dict)
+ return;
+ const base::DictionaryValue* old_manifest = NULL;
+ bool update_required =
+ !extension_dict->GetDictionary(kPrefManifest, &old_manifest) ||
+ !extension->manifest()->value()->Equals(old_manifest);
+ if (update_required) {
+ UpdateExtensionPref(extension->id(), kPrefManifest,
+ extension->manifest()->value()->DeepCopy());
+ }
+ }
+}
+
+base::FilePath ExtensionPrefs::GetExtensionPath(
+ const std::string& extension_id) {
+ const base::DictionaryValue* dict = GetExtensionPref(extension_id);
+ if (!dict)
+ return base::FilePath();
+
+ std::string path;
+ if (!dict->GetString(kPrefPath, &path))
+ return base::FilePath();
+
+ return install_directory_.Append(base::FilePath::FromUTF8Unsafe(path));
+}
+
+scoped_ptr<ExtensionInfo> ExtensionPrefs::GetInstalledInfoHelper(
+ const std::string& extension_id,
+ const base::DictionaryValue* extension) const {
+ int location_value;
+ if (!extension->GetInteger(kPrefLocation, &location_value))
+ return scoped_ptr<ExtensionInfo>();
+
+ base::FilePath::StringType path;
+ if (!extension->GetString(kPrefPath, &path))
+ return scoped_ptr<ExtensionInfo>();
+
+ // Make path absolute. Unpacked extensions will already have absolute paths,
+ // otherwise make it so.
+ Manifest::Location location = static_cast<Manifest::Location>(location_value);
+ if (!Manifest::IsUnpackedLocation(location)) {
+ DCHECK(location == Manifest::COMPONENT ||
+ !base::FilePath(path).IsAbsolute());
+ path = install_directory_.Append(path).value();
+ }
+
+ // Only the following extension types have data saved in the preferences.
+ if (location != Manifest::INTERNAL &&
+ !Manifest::IsUnpackedLocation(location) &&
+ !Manifest::IsExternalLocation(location)) {
+ NOTREACHED();
+ return scoped_ptr<ExtensionInfo>();
+ }
+
+ const base::DictionaryValue* manifest = NULL;
+ if (!Manifest::IsUnpackedLocation(location) &&
+ !extension->GetDictionary(kPrefManifest, &manifest)) {
+ LOG(WARNING) << "Missing manifest for extension " << extension_id;
+ // Just a warning for now.
+ }
+
+ return scoped_ptr<ExtensionInfo>(new ExtensionInfo(
+ manifest, extension_id, base::FilePath(path), location));
+}
+
+scoped_ptr<ExtensionInfo> ExtensionPrefs::GetInstalledExtensionInfo(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* ext = NULL;
+ const base::DictionaryValue* extensions =
+ prefs_->GetDictionary(pref_names::kExtensions);
+ if (!extensions ||
+ !extensions->GetDictionaryWithoutPathExpansion(extension_id, &ext))
+ return scoped_ptr<ExtensionInfo>();
+ int state_value;
+ if (!ext->GetInteger(kPrefState, &state_value) ||
+ state_value == Extension::ENABLED_COMPONENT) {
+ // Old preferences files may not have kPrefState for component extensions.
+ return scoped_ptr<ExtensionInfo>();
+ }
+
+ if (state_value == Extension::EXTERNAL_EXTENSION_UNINSTALLED) {
+ LOG(WARNING) << "External extension with id " << extension_id
+ << " has been uninstalled by the user";
+ return scoped_ptr<ExtensionInfo>();
+ }
+
+ return GetInstalledInfoHelper(extension_id, ext);
+}
+
+scoped_ptr<ExtensionPrefs::ExtensionsInfo>
+ExtensionPrefs::GetInstalledExtensionsInfo() const {
+ scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo);
+
+ const base::DictionaryValue* extensions =
+ prefs_->GetDictionary(pref_names::kExtensions);
+ for (base::DictionaryValue::Iterator extension_id(*extensions);
+ !extension_id.IsAtEnd(); extension_id.Advance()) {
+ if (!Extension::IdIsValid(extension_id.key()))
+ continue;
+
+ scoped_ptr<ExtensionInfo> info =
+ GetInstalledExtensionInfo(extension_id.key());
+ if (info)
+ extensions_info->push_back(linked_ptr<ExtensionInfo>(info.release()));
+ }
+
+ return extensions_info.Pass();
+}
+
+scoped_ptr<ExtensionPrefs::ExtensionsInfo>
+ExtensionPrefs::GetUninstalledExtensionsInfo() const {
+ scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo);
+
+ const base::DictionaryValue* extensions =
+ prefs_->GetDictionary(pref_names::kExtensions);
+ for (base::DictionaryValue::Iterator extension_id(*extensions);
+ !extension_id.IsAtEnd(); extension_id.Advance()) {
+ const base::DictionaryValue* ext = NULL;
+ if (!Extension::IdIsValid(extension_id.key()) ||
+ !IsExternalExtensionUninstalled(extension_id.key()) ||
+ !extension_id.value().GetAsDictionary(&ext))
+ continue;
+
+ scoped_ptr<ExtensionInfo> info =
+ GetInstalledInfoHelper(extension_id.key(), ext);
+ if (info)
+ extensions_info->push_back(linked_ptr<ExtensionInfo>(info.release()));
+ }
+
+ return extensions_info.Pass();
+}
+
+void ExtensionPrefs::SetDelayedInstallInfo(
+ const Extension* extension,
+ Extension::State initial_state,
+ bool blacklisted_for_malware,
+ DelayReason delay_reason,
+ const syncer::StringOrdinal& page_ordinal) {
+ base::DictionaryValue* extension_dict = new base::DictionaryValue();
+ PopulateExtensionInfoPrefs(extension, time_provider_->GetCurrentTime(),
+ initial_state, blacklisted_for_malware,
+ extension_dict);
+
+ // Add transient data that is needed by FinishDelayedInstallInfo(), but
+ // should not be in the final extension prefs. All entries here should have
+ // a corresponding Remove() call in FinishDelayedInstallInfo().
+ if (extension->RequiresSortOrdinal()) {
+ extension_dict->SetString(
+ kPrefSuggestedPageOrdinal,
+ page_ordinal.IsValid() ? page_ordinal.ToInternalValue()
+ : std::string());
+ }
+ extension_dict->SetInteger(kDelayedInstallReason,
+ static_cast<int>(delay_reason));
+
+ UpdateExtensionPref(extension->id(), kDelayedInstallInfo, extension_dict);
+}
+
+bool ExtensionPrefs::RemoveDelayedInstallInfo(
+ const std::string& extension_id) {
+ if (!GetExtensionPref(extension_id))
+ return false;
+ ScopedExtensionPrefUpdate update(prefs_, extension_id);
+ bool result = update->Remove(kDelayedInstallInfo, NULL);
+ return result;
+}
+
+bool ExtensionPrefs::FinishDelayedInstallInfo(
+ const std::string& extension_id) {
+ CHECK(Extension::IdIsValid(extension_id));
+ ScopedExtensionPrefUpdate update(prefs_, extension_id);
+ base::DictionaryValue* extension_dict = update.Get();
+ base::DictionaryValue* pending_install_dict = NULL;
+ if (!extension_dict->GetDictionary(kDelayedInstallInfo,
+ &pending_install_dict)) {
+ return false;
+ }
+
+ // Retrieve and clear transient values populated by SetDelayedInstallInfo().
+ // Also do any other data cleanup that makes sense.
+ std::string serialized_ordinal;
+ syncer::StringOrdinal suggested_page_ordinal;
+ bool needs_sort_ordinal = false;
+ if (pending_install_dict->GetString(kPrefSuggestedPageOrdinal,
+ &serialized_ordinal)) {
+ suggested_page_ordinal = syncer::StringOrdinal(serialized_ordinal);
+ needs_sort_ordinal = true;
+ pending_install_dict->Remove(kPrefSuggestedPageOrdinal, NULL);
+ }
+ pending_install_dict->Remove(kDelayedInstallReason, NULL);
+
+ const base::Time install_time = time_provider_->GetCurrentTime();
+ pending_install_dict->Set(
+ kPrefInstallTime,
+ new base::StringValue(
+ base::Int64ToString(install_time.ToInternalValue())));
+
+ // Commit the delayed install data.
+ for (base::DictionaryValue::Iterator it(*pending_install_dict); !it.IsAtEnd();
+ it.Advance()) {
+ extension_dict->Set(it.key(), it.value().DeepCopy());
+ }
+ FinishExtensionInfoPrefs(extension_id, install_time, needs_sort_ordinal,
+ suggested_page_ordinal, extension_dict);
+ return true;
+}
+
+scoped_ptr<ExtensionInfo> ExtensionPrefs::GetDelayedInstallInfo(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* extension_prefs =
+ GetExtensionPref(extension_id);
+ if (!extension_prefs)
+ return scoped_ptr<ExtensionInfo>();
+
+ const base::DictionaryValue* ext = NULL;
+ if (!extension_prefs->GetDictionary(kDelayedInstallInfo, &ext))
+ return scoped_ptr<ExtensionInfo>();
+
+ return GetInstalledInfoHelper(extension_id, ext);
+}
+
+ExtensionPrefs::DelayReason ExtensionPrefs::GetDelayedInstallReason(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* extension_prefs =
+ GetExtensionPref(extension_id);
+ if (!extension_prefs)
+ return DELAY_REASON_NONE;
+
+ const base::DictionaryValue* ext = NULL;
+ if (!extension_prefs->GetDictionary(kDelayedInstallInfo, &ext))
+ return DELAY_REASON_NONE;
+
+ int delay_reason;
+ if (!ext->GetInteger(kDelayedInstallReason, &delay_reason))
+ return DELAY_REASON_NONE;
+
+ return static_cast<DelayReason>(delay_reason);
+}
+
+scoped_ptr<ExtensionPrefs::ExtensionsInfo> ExtensionPrefs::
+ GetAllDelayedInstallInfo() const {
+ scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo);
+
+ const base::DictionaryValue* extensions =
+ prefs_->GetDictionary(pref_names::kExtensions);
+ for (base::DictionaryValue::Iterator extension_id(*extensions);
+ !extension_id.IsAtEnd(); extension_id.Advance()) {
+ if (!Extension::IdIsValid(extension_id.key()))
+ continue;
+
+ scoped_ptr<ExtensionInfo> info = GetDelayedInstallInfo(extension_id.key());
+ if (info)
+ extensions_info->push_back(linked_ptr<ExtensionInfo>(info.release()));
+ }
+
+ return extensions_info.Pass();
+}
+
+bool ExtensionPrefs::WasAppDraggedByUser(const std::string& extension_id) {
+ return ReadPrefAsBooleanAndReturn(extension_id, kPrefUserDraggedApp);
+}
+
+void ExtensionPrefs::SetAppDraggedByUser(const std::string& extension_id) {
+ UpdateExtensionPref(extension_id, kPrefUserDraggedApp,
+ new base::FundamentalValue(true));
+}
+
+bool ExtensionPrefs::IsFromWebStore(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* dictionary = GetExtensionPref(extension_id);
+ bool result = false;
+ if (dictionary && dictionary->GetBoolean(kPrefFromWebStore, &result))
+ return result;
+ return false;
+}
+
+bool ExtensionPrefs::IsFromBookmark(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* dictionary = GetExtensionPref(extension_id);
+ bool result = false;
+ if (dictionary && dictionary->GetBoolean(kPrefFromBookmark, &result))
+ return result;
+ return false;
+}
+
+int ExtensionPrefs::GetCreationFlags(const std::string& extension_id) const {
+ int creation_flags = Extension::NO_FLAGS;
+ if (!ReadPrefAsInteger(extension_id, kPrefCreationFlags, &creation_flags)) {
+ // Since kPrefCreationFlags was added later, it will be missing for
+ // previously installed extensions.
+ if (IsFromBookmark(extension_id))
+ creation_flags |= Extension::FROM_BOOKMARK;
+ if (IsFromWebStore(extension_id))
+ creation_flags |= Extension::FROM_WEBSTORE;
+ if (WasInstalledByDefault(extension_id))
+ creation_flags |= Extension::WAS_INSTALLED_BY_DEFAULT;
+ }
+ return creation_flags;
+}
+
+int ExtensionPrefs::GetDelayedInstallCreationFlags(
+ const std::string& extension_id) const {
+ int creation_flags = Extension::NO_FLAGS;
+ const base::DictionaryValue* delayed_info = NULL;
+ if (ReadPrefAsDictionary(extension_id, kDelayedInstallInfo, &delayed_info)) {
+ delayed_info->GetInteger(kPrefCreationFlags, &creation_flags);
+ }
+ return creation_flags;
+}
+
+bool ExtensionPrefs::WasInstalledByDefault(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* dictionary = GetExtensionPref(extension_id);
+ bool result = false;
+ if (dictionary &&
+ dictionary->GetBoolean(kPrefWasInstalledByDefault, &result))
+ return result;
+ return false;
+}
+
+base::Time ExtensionPrefs::GetInstallTime(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension) {
+ NOTREACHED();
+ return base::Time();
+ }
+ std::string install_time_str;
+ if (!extension->GetString(kPrefInstallTime, &install_time_str))
+ return base::Time();
+ int64 install_time_i64 = 0;
+ if (!base::StringToInt64(install_time_str, &install_time_i64))
+ return base::Time();
+ return base::Time::FromInternalValue(install_time_i64);
+}
+
+base::Time ExtensionPrefs::GetLastLaunchTime(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension)
+ return base::Time();
+
+ std::string launch_time_str;
+ if (!extension->GetString(kPrefLastLaunchTime, &launch_time_str))
+ return base::Time();
+ int64 launch_time_i64 = 0;
+ if (!base::StringToInt64(launch_time_str, &launch_time_i64))
+ return base::Time();
+ return base::Time::FromInternalValue(launch_time_i64);
+}
+
+void ExtensionPrefs::SetLastLaunchTime(const std::string& extension_id,
+ const base::Time& time) {
+ DCHECK(Extension::IdIsValid(extension_id));
+ ScopedExtensionPrefUpdate update(prefs_, extension_id);
+ SaveTime(update.Get(), kPrefLastLaunchTime, time);
+}
+
+void ExtensionPrefs::GetExtensions(ExtensionIdList* out) {
+ CHECK(out);
+
+ scoped_ptr<ExtensionsInfo> extensions_info(GetInstalledExtensionsInfo());
+
+ for (size_t i = 0; i < extensions_info->size(); ++i) {
+ ExtensionInfo* info = extensions_info->at(i).get();
+ out->push_back(info->extension_id);
+ }
+}
+
+// static
+ExtensionIdList ExtensionPrefs::GetExtensionsFrom(
+ const PrefService* pref_service) {
+ ExtensionIdList result;
+
+ const base::DictionaryValue* extension_prefs = NULL;
+ const base::Value* extension_prefs_value =
+ pref_service->GetUserPrefValue(pref_names::kExtensions);
+ if (!extension_prefs_value ||
+ !extension_prefs_value->GetAsDictionary(&extension_prefs)) {
+ return result; // Empty set
+ }
+
+ for (base::DictionaryValue::Iterator it(*extension_prefs); !it.IsAtEnd();
+ it.Advance()) {
+ const base::DictionaryValue* ext = NULL;
+ if (!it.value().GetAsDictionary(&ext)) {
+ NOTREACHED() << "Invalid pref for extension " << it.key();
+ continue;
+ }
+ if (!IsBlacklistBitSet(ext))
+ result.push_back(it.key());
+ }
+ return result;
+}
+
+void ExtensionPrefs::FixMissingPrefs(const ExtensionIdList& extension_ids) {
+ // Fix old entries that did not get an installation time entry when they
+ // were installed or don't have a preferences field.
+ for (ExtensionIdList::const_iterator ext_id = extension_ids.begin();
+ ext_id != extension_ids.end(); ++ext_id) {
+ if (GetInstallTime(*ext_id) == base::Time()) {
+ VLOG(1) << "Could not parse installation time of extension "
+ << *ext_id << ". It was probably installed before setting "
+ << kPrefInstallTime << " was introduced. Updating "
+ << kPrefInstallTime << " to the current time.";
+ const base::Time install_time = time_provider_->GetCurrentTime();
+ UpdateExtensionPref(*ext_id,
+ kPrefInstallTime,
+ new base::StringValue(base::Int64ToString(
+ install_time.ToInternalValue())));
+ }
+ }
+}
+
+void ExtensionPrefs::InitPrefStore() {
+ if (extensions_disabled_) {
+ extension_pref_value_map_->NotifyInitializationCompleted();
+ return;
+ }
+
+ // When this is called, the PrefService is initialized and provides access
+ // to the user preferences stored in a JSON file.
+ ExtensionIdList extension_ids;
+ GetExtensions(&extension_ids);
+ // Create empty preferences dictionary for each extension (these dictionaries
+ // are pruned when persisting the preferences to disk).
+ for (ExtensionIdList::iterator ext_id = extension_ids.begin();
+ ext_id != extension_ids.end(); ++ext_id) {
+ ScopedExtensionPrefUpdate update(prefs_, *ext_id);
+ // This creates an empty dictionary if none is stored.
+ update.Get();
+ }
+
+ FixMissingPrefs(extension_ids);
+ MigratePermissions(extension_ids);
+ MigrateDisableReasons(extension_ids);
+ app_sorting_->Initialize(extension_ids);
+
+ PreferenceAPI::InitExtensionControlledPrefs(this, extension_pref_value_map_);
+
+ extension_pref_value_map_->NotifyInitializationCompleted();
+}
+
+bool ExtensionPrefs::HasIncognitoPrefValue(const std::string& pref_key) {
+ bool has_incognito_pref_value = false;
+ extension_pref_value_map_->GetEffectivePrefValue(pref_key,
+ true,
+ &has_incognito_pref_value);
+ return has_incognito_pref_value;
+}
+
+URLPatternSet ExtensionPrefs::GetAllowedInstallSites() {
+ URLPatternSet result;
+ const base::ListValue* list =
+ prefs_->GetList(pref_names::kAllowedInstallSites);
+ CHECK(list);
+
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ std::string entry_string;
+ URLPattern entry(URLPattern::SCHEME_ALL);
+ if (!list->GetString(i, &entry_string) ||
+ entry.Parse(entry_string) != URLPattern::PARSE_SUCCESS) {
+ LOG(ERROR) << "Invalid value for preference: "
+ << pref_names::kAllowedInstallSites << "." << i;
+ continue;
+ }
+ result.AddPattern(entry);
+ }
+
+ return result;
+}
+
+const base::DictionaryValue* ExtensionPrefs::GetGeometryCache(
+ const std::string& extension_id) const {
+ const base::DictionaryValue* extension_prefs = GetExtensionPref(extension_id);
+ if (!extension_prefs)
+ return NULL;
+
+ const base::DictionaryValue* ext = NULL;
+ if (!extension_prefs->GetDictionary(kPrefGeometryCache, &ext))
+ return NULL;
+
+ return ext;
+}
+
+void ExtensionPrefs::SetGeometryCache(
+ const std::string& extension_id,
+ scoped_ptr<base::DictionaryValue> cache) {
+ UpdateExtensionPref(extension_id, kPrefGeometryCache, cache.release());
+}
+
+const base::DictionaryValue* ExtensionPrefs::GetInstallSignature() {
+ return prefs_->GetDictionary(kInstallSignature);
+}
+
+void ExtensionPrefs::SetInstallSignature(
+ const base::DictionaryValue* signature) {
+ if (signature) {
+ prefs_->Set(kInstallSignature, *signature);
+ DVLOG(1) << "SetInstallSignature - saving";
+ } else {
+ DVLOG(1) << "SetInstallSignature - clearing";
+ prefs_->ClearPref(kInstallSignature);
+ }
+}
+
+
+ExtensionPrefs::ExtensionPrefs(
+ PrefService* prefs,
+ const base::FilePath& root_dir,
+ ExtensionPrefValueMap* extension_pref_value_map,
+ scoped_ptr<AppSorting> app_sorting,
+ scoped_ptr<TimeProvider> time_provider,
+ bool extensions_disabled)
+ : prefs_(prefs),
+ install_directory_(root_dir),
+ extension_pref_value_map_(extension_pref_value_map),
+ app_sorting_(app_sorting.Pass()),
+ content_settings_store_(new ContentSettingsStore()),
+ time_provider_(time_provider.Pass()),
+ extensions_disabled_(extensions_disabled) {
+ app_sorting_->SetExtensionScopedPrefs(this);
+ MakePathsRelative();
+ InitPrefStore();
+}
+
+void ExtensionPrefs::SetNeedsStorageGarbageCollection(bool value) {
+ prefs_->SetBoolean(pref_names::kStorageGarbageCollect, value);
+}
+
+bool ExtensionPrefs::NeedsStorageGarbageCollection() {
+ return prefs_->GetBoolean(pref_names::kStorageGarbageCollect);
+}
+
+// static
+void ExtensionPrefs::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterDictionaryPref(
+ pref_names::kExtensions,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterListPref(pref_names::kToolbar,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterIntegerPref(
+ pref_names::kToolbarSize,
+ -1, // default value
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterDictionaryPref(
+ kExtensionsBlacklistUpdate,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterListPref(pref_names::kInstallAllowList,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterListPref(pref_names::kInstallDenyList,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterDictionaryPref(
+ pref_names::kInstallForceList,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterListPref(pref_names::kAllowedTypes,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ pref_names::kStorageGarbageCollect,
+ false, // default value
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterInt64Pref(
+ pref_names::kLastUpdateCheck,
+ 0, // default value
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterInt64Pref(
+ pref_names::kNextUpdateCheck,
+ 0, // default value
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterListPref(pref_names::kAllowedInstallSites,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterStringPref(
+ pref_names::kLastChromeVersion,
+ std::string(), // default value
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterListPref(pref_names::kKnownDisabled,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+#if defined(TOOLKIT_VIEWS)
+ registry->RegisterIntegerPref(
+ pref_names::kBrowserActionContainerWidth,
+ 0,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+#endif
+ registry->RegisterDictionaryPref(
+ kInstallSignature,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+
+ registry->RegisterListPref(pref_names::kNativeMessagingBlacklist,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterListPref(pref_names::kNativeMessagingWhitelist,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+}
+
+template <class ExtensionIdContainer>
+bool ExtensionPrefs::GetUserExtensionPrefIntoContainer(
+ const char* pref,
+ ExtensionIdContainer* id_container_out) {
+ DCHECK(id_container_out->empty());
+
+ const base::Value* user_pref_value = prefs_->GetUserPrefValue(pref);
+ const base::ListValue* user_pref_as_list;
+ if (!user_pref_value || !user_pref_value->GetAsList(&user_pref_as_list))
+ return false;
+
+ std::insert_iterator<ExtensionIdContainer> insert_iterator(
+ *id_container_out, id_container_out->end());
+ std::string extension_id;
+ for (base::ListValue::const_iterator value_it = user_pref_as_list->begin();
+ value_it != user_pref_as_list->end(); ++value_it) {
+ if (!(*value_it)->GetAsString(&extension_id)) {
+ NOTREACHED();
+ continue;
+ }
+ insert_iterator = extension_id;
+ }
+ return true;
+}
+
+template <class ExtensionIdContainer>
+void ExtensionPrefs::SetExtensionPrefFromContainer(
+ const char* pref,
+ const ExtensionIdContainer& strings) {
+ ListPrefUpdate update(prefs_, pref);
+ base::ListValue* list_of_values = update.Get();
+ list_of_values->Clear();
+ for (typename ExtensionIdContainer::const_iterator iter = strings.begin();
+ iter != strings.end(); ++iter) {
+ list_of_values->Append(new base::StringValue(*iter));
+ }
+}
+
+void ExtensionPrefs::PopulateExtensionInfoPrefs(
+ const Extension* extension,
+ const base::Time install_time,
+ Extension::State initial_state,
+ bool blacklisted_for_malware,
+ base::DictionaryValue* extension_dict) {
+ // Leave the state blank for component extensions so that old chrome versions
+ // loading new profiles do not fail in GetInstalledExtensionInfo. Older
+ // Chrome versions would only check for an omitted state.
+ if (initial_state != Extension::ENABLED_COMPONENT)
+ extension_dict->Set(kPrefState, new base::FundamentalValue(initial_state));
+
+ extension_dict->Set(kPrefLocation,
+ new base::FundamentalValue(extension->location()));
+ extension_dict->Set(kPrefCreationFlags,
+ new base::FundamentalValue(extension->creation_flags()));
+ extension_dict->Set(kPrefFromWebStore,
+ new base::FundamentalValue(extension->from_webstore()));
+ extension_dict->Set(kPrefFromBookmark,
+ new base::FundamentalValue(extension->from_bookmark()));
+ extension_dict->Set(
+ kPrefWasInstalledByDefault,
+ new base::FundamentalValue(extension->was_installed_by_default()));
+ extension_dict->Set(kPrefInstallTime,
+ new base::StringValue(
+ base::Int64ToString(install_time.ToInternalValue())));
+ if (blacklisted_for_malware)
+ extension_dict->Set(kPrefBlacklist, new base::FundamentalValue(true));
+
+ base::FilePath::StringType path = MakePathRelative(install_directory_,
+ extension->path());
+ extension_dict->Set(kPrefPath, new base::StringValue(path));
+ // We store prefs about LOAD extensions, but don't cache their manifest
+ // since it may change on disk.
+ if (!Manifest::IsUnpackedLocation(extension->location())) {
+ extension_dict->Set(kPrefManifest,
+ extension->manifest()->value()->DeepCopy());
+ }
+}
+
+void ExtensionPrefs::FinishExtensionInfoPrefs(
+ const std::string& extension_id,
+ const base::Time install_time,
+ bool needs_sort_ordinal,
+ const syncer::StringOrdinal& suggested_page_ordinal,
+ base::DictionaryValue* extension_dict) {
+ // Reinitializes various preferences with empty dictionaries.
+ if (!extension_dict->HasKey(pref_names::kPrefPreferences)) {
+ extension_dict->Set(pref_names::kPrefPreferences,
+ new base::DictionaryValue);
+ }
+
+ if (!extension_dict->HasKey(pref_names::kPrefIncognitoPreferences)) {
+ extension_dict->Set(pref_names::kPrefIncognitoPreferences,
+ new base::DictionaryValue);
+ }
+
+ if (!extension_dict->HasKey(pref_names::kPrefRegularOnlyPreferences)) {
+ extension_dict->Set(pref_names::kPrefRegularOnlyPreferences,
+ new base::DictionaryValue);
+ }
+
+ if (!extension_dict->HasKey(pref_names::kPrefContentSettings))
+ extension_dict->Set(pref_names::kPrefContentSettings, new base::ListValue);
+
+ if (!extension_dict->HasKey(pref_names::kPrefIncognitoContentSettings)) {
+ extension_dict->Set(pref_names::kPrefIncognitoContentSettings,
+ new base::ListValue);
+ }
+
+ // If this point has been reached, any pending installs should be considered
+ // out of date.
+ extension_dict->Remove(kDelayedInstallInfo, NULL);
+
+ // Clear state that may be registered from a previous install.
+ extension_dict->Remove(EventRouter::kRegisteredEvents, NULL);
+
+ // FYI, all code below here races on sudden shutdown because |extension_dict|,
+ // |app_sorting_|, |extension_pref_value_map_|, and |content_settings_store_|
+ // are updated non-transactionally. This is probably not fixable without
+ // nested transactional updates to pref dictionaries.
+ if (needs_sort_ordinal)
+ app_sorting_->EnsureValidOrdinals(extension_id, suggested_page_ordinal);
+
+ bool is_enabled = false;
+ int initial_state;
+ if (extension_dict->GetInteger(kPrefState, &initial_state)) {
+ is_enabled = initial_state == Extension::ENABLED;
+ }
+
+ extension_pref_value_map_->RegisterExtension(extension_id, install_time,
+ is_enabled);
+ content_settings_store_->RegisterExtension(extension_id, install_time,
+ is_enabled);
+}
+
+} // namespace extensions
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
new file mode 100644
index 0000000..2525b36
--- /dev/null
+++ b/extensions/browser/extension_prefs.h
@@ -0,0 +1,638 @@
+// 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.
+
+#ifndef EXTENSIONS_BROWSER_EXTENSION_PREFS_H_
+#define EXTENSIONS_BROWSER_EXTENSION_PREFS_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/scoped_user_pref_update.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "extensions/browser/app_sorting.h"
+#include "extensions/browser/extension_scoped_prefs.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/url_pattern_set.h"
+#include "sync/api/string_ordinal.h"
+
+class ExtensionPrefValueMap;
+class PrefService;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+namespace extensions {
+
+class AppSorting;
+class ContentSettingsStore;
+class ExtensionPrefsUninstallExtension;
+class URLPatternSet;
+
+// Class for managing global and per-extension preferences.
+//
+// This class distinguishes the following kinds of preferences:
+// - global preferences:
+// internal state for the extension system in general, not associated
+// with an individual extension, such as lastUpdateTime.
+// - per-extension preferences:
+// meta-preferences describing properties of the extension like
+// installation time, whether the extension is enabled, etc.
+// - extension controlled preferences:
+// browser preferences that an extension controls. For example, an
+// extension could use the proxy API to specify the browser's proxy
+// preference. Extension-controlled preferences are stored in
+// PrefValueStore::extension_prefs(), which this class populates and
+// maintains as the underlying extensions change.
+class ExtensionPrefs : public ExtensionScopedPrefs,
+ public BrowserContextKeyedService {
+ public:
+ typedef std::vector<linked_ptr<ExtensionInfo> > ExtensionsInfo;
+
+ // Vector containing identifiers for preferences.
+ typedef std::set<std::string> PrefKeySet;
+
+ // This enum is used to store the reason an extension's install has been
+ // delayed. Do not remove items or re-order this enum as it is used in
+ // preferences.
+ enum DelayReason {
+ DELAY_REASON_NONE = 0,
+ DELAY_REASON_GC = 1,
+ DELAY_REASON_WAIT_FOR_IDLE = 2,
+ DELAY_REASON_WAIT_FOR_IMPORTS = 3,
+ };
+
+
+ // Creates base::Time classes. The default implementation is just to return
+ // the current time, but tests can inject alternative implementations.
+ class TimeProvider {
+ public:
+ TimeProvider();
+
+ virtual ~TimeProvider();
+
+ // By default, returns the current time (base::Time::Now()).
+ virtual base::Time GetCurrentTime() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TimeProvider);
+ };
+
+ // A wrapper around a ScopedUserPrefUpdate, which allows us to access the
+ // entry of a particular key for an extension. Use this if you need a mutable
+ // record of a dictionary or list in the current settings. Otherwise, prefer
+ // ReadPrefAsT() and UpdateExtensionPref() methods.
+ template <typename T, base::Value::Type type_enum_value>
+ class ScopedUpdate {
+ public:
+ ScopedUpdate(ExtensionPrefs* prefs,
+ const std::string& extension_id,
+ const std::string& key);
+ virtual ~ScopedUpdate();
+
+ // Returns a mutable value for the key (ownership remains with the prefs),
+ // if one exists. Otherwise, returns NULL.
+ virtual T* Get();
+
+ // Creates and returns a mutable value for the key (the prefs own the new
+ // value), if one does not already exist. Otherwise, returns the current
+ // value.
+ virtual T* Create();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedUpdate);
+
+ DictionaryPrefUpdate update_;
+ const std::string extension_id_;
+ const std::string key_;
+ };
+ typedef ScopedUpdate<base::DictionaryValue, base::Value::TYPE_DICTIONARY>
+ ScopedDictionaryUpdate;
+ typedef ScopedUpdate<base::ListValue, base::Value::TYPE_LIST>
+ ScopedListUpdate;
+
+ // Creates and initializes an ExtensionPrefs object.
+ // Does not take ownership of |prefs| and |extension_pref_value_map|.
+ // If |extensions_disabled| is true, extension controlled preferences and
+ // content settings do not become effective.
+ static ExtensionPrefs* Create(
+ PrefService* prefs,
+ const base::FilePath& root_dir,
+ ExtensionPrefValueMap* extension_pref_value_map,
+ scoped_ptr<AppSorting> app_sorting,
+ bool extensions_disabled);
+
+ // A version of Create which allows injection of a custom base::Time provider.
+ // Use this as needed for testing.
+ static ExtensionPrefs* Create(
+ PrefService* prefs,
+ const base::FilePath& root_dir,
+ ExtensionPrefValueMap* extension_pref_value_map,
+ scoped_ptr<AppSorting> app_sorting,
+ bool extensions_disabled,
+ scoped_ptr<TimeProvider> time_provider);
+
+ virtual ~ExtensionPrefs();
+
+ // Convenience function to get the ExtensionPrefs for a BrowserContext.
+ static ExtensionPrefs* Get(content::BrowserContext* context);
+
+ // Returns all installed extensions from extension preferences provided by
+ // |pref_service|. This is exposed for ProtectedPrefsWatcher because it needs
+ // access to the extension ID list before the ExtensionService is initialized.
+ static ExtensionIdList GetExtensionsFrom(const PrefService* pref_service);
+
+ // Returns true if the specified external extension was uninstalled by the
+ // user.
+ bool IsExternalExtensionUninstalled(const std::string& id) const;
+
+ // Checks whether |extension_id| is disabled. If there's no state pref for
+ // the extension, this will return false. Generally you should use
+ // ExtensionService::IsExtensionEnabled instead.
+ bool IsExtensionDisabled(const std::string& id) const;
+
+ // Get/Set the order that the browser actions appear in the toolbar.
+ ExtensionIdList GetToolbarOrder();
+ void SetToolbarOrder(const ExtensionIdList& extension_ids);
+
+ // Gets the set of known disabled extension IDs into |id_set_out|. Returns
+ // false iff the set of known disabled extension IDs hasn't been set yet.
+ bool GetKnownDisabled(ExtensionIdSet* id_set_out);
+
+ // Sets the set of known disabled extension IDs.
+ void SetKnownDisabled(const ExtensionIdSet& extension_ids);
+
+ // Called when an extension is installed, so that prefs get created.
+ // |blacklisted_for_malware| should be set if the extension was included in a
+ // blacklist due to being malware. If |page_ordinal| is an invalid ordinal,
+ // then a page will be found for the App.
+ void OnExtensionInstalled(const Extension* extension,
+ Extension::State initial_state,
+ bool blacklisted_for_malware,
+ const syncer::StringOrdinal& page_ordinal);
+
+ // Called when an extension is uninstalled, so that prefs get cleaned up.
+ void OnExtensionUninstalled(const std::string& extension_id,
+ const Manifest::Location& location,
+ bool external_uninstall);
+
+ // Called to change the extension's state when it is enabled/disabled.
+ void SetExtensionState(const std::string& extension_id, Extension::State);
+
+ // Populates |out| with the ids of all installed extensions.
+ void GetExtensions(ExtensionIdList* out);
+
+ // ExtensionScopedPrefs methods:
+ virtual void UpdateExtensionPref(const std::string& id,
+ const std::string& key,
+ base::Value* value) OVERRIDE;
+
+ virtual void DeleteExtensionPrefs(const std::string& id) OVERRIDE;
+
+ virtual bool ReadPrefAsBoolean(const std::string& extension_id,
+ const std::string& pref_key,
+ bool* out_value) const OVERRIDE;
+
+ virtual bool ReadPrefAsInteger(const std::string& extension_id,
+ const std::string& pref_key,
+ int* out_value) const OVERRIDE;
+
+ virtual bool ReadPrefAsString(const std::string& extension_id,
+ const std::string& pref_key,
+ std::string* out_value) const OVERRIDE;
+
+ virtual bool ReadPrefAsList(const std::string& extension_id,
+ const std::string& pref_key,
+ const base::ListValue** out_value) const OVERRIDE;
+
+ virtual bool ReadPrefAsDictionary(
+ const std::string& extension_id,
+ const std::string& pref_key,
+ const base::DictionaryValue** out_value) const OVERRIDE;
+
+ virtual bool HasPrefForExtension(const std::string& extension_id) const
+ OVERRIDE;
+
+ // Did the extension ask to escalate its permission during an upgrade?
+ bool DidExtensionEscalatePermissions(const std::string& id);
+
+ // If |did_escalate| is true, the preferences for |extension| will be set to
+ // require the install warning when the user tries to enable.
+ void SetDidExtensionEscalatePermissions(
+ const Extension* extension,
+ bool did_escalate);
+
+ // Getter and setters for disabled reason.
+ int GetDisableReasons(const std::string& extension_id) const;
+ void AddDisableReason(const std::string& extension_id,
+ Extension::DisableReason disable_reason);
+ void RemoveDisableReason(const std::string& extension_id,
+ Extension::DisableReason disable_reason);
+ void ClearDisableReasons(const std::string& extension_id);
+
+ // Gets the set of extensions that have been blacklisted in prefs.
+ std::set<std::string> GetBlacklistedExtensions();
+
+ // Sets whether the extension with |id| is blacklisted.
+ void SetExtensionBlacklisted(const std::string& extension_id,
+ bool is_blacklisted);
+
+ // Returns the version string for the currently installed extension, or
+ // the empty string if not found.
+ std::string GetVersionString(const std::string& extension_id);
+
+ // Re-writes the extension manifest into the prefs.
+ // Called to change the extension's manifest when it's re-localized.
+ void UpdateManifest(const Extension* extension);
+
+ // Returns extension path based on extension ID, or empty FilePath on error.
+ base::FilePath GetExtensionPath(const std::string& extension_id);
+
+ // Returns base extensions install directory.
+ const base::FilePath& install_directory() const { return install_directory_; }
+
+ // Returns whether the extension with |id| has its blacklist bit set.
+ //
+ // WARNING: this only checks the extension's entry in prefs, so by definition
+ // can only check extensions that prefs knows about. There may be other
+ // sources of blacklist information, such as safebrowsing. You probably want
+ // to use Blacklist::GetBlacklistedIDs rather than this method.
+ bool IsExtensionBlacklisted(const std::string& id) const;
+
+ // Increment the count of how many times we prompted the user to acknowledge
+ // the given extension, and return the new count.
+ int IncrementAcknowledgePromptCount(const std::string& extension_id);
+
+ // Whether the user has acknowledged an external extension.
+ bool IsExternalExtensionAcknowledged(const std::string& extension_id);
+ void AcknowledgeExternalExtension(const std::string& extension_id);
+
+ // Whether the user has acknowledged a blacklisted extension.
+ bool IsBlacklistedExtensionAcknowledged(const std::string& extension_id);
+ void AcknowledgeBlacklistedExtension(const std::string& extension_id);
+
+ // Whether the external extension was installed during the first run
+ // of this profile.
+ bool IsExternalInstallFirstRun(const std::string& extension_id);
+ void SetExternalInstallFirstRun(const std::string& extension_id);
+
+ // Whether the user has been notified about extension with |extension_id|
+ // being wiped out.
+ bool HasWipeoutBeenAcknowledged(const std::string& extension_id);
+ void SetWipeoutAcknowledged(const std::string& extension_id, bool value);
+
+ // Returns true if the extension notification code has already run for the
+ // first time for this profile. Currently we use this flag to mean that any
+ // extensions that would trigger notifications should get silently
+ // acknowledged. This is a fuse. Calling it the first time returns false.
+ // Subsequent calls return true. It's not possible through an API to ever
+ // reset it. Don't call it unless you mean it!
+ bool SetAlertSystemFirstRun();
+
+ // Checks if extensions are blacklisted by default, by policy.
+ // The ManagementPolicy::Provider methods also take this into account, and
+ // should be used instead when the extension ID is known.
+ bool ExtensionsBlacklistedByDefault() const;
+
+ // Returns the last value set via SetLastPingDay. If there isn't such a
+ // pref, the returned Time will return true for is_null().
+ base::Time LastPingDay(const std::string& extension_id) const;
+
+ // The time stored is based on the server's perspective of day start time, not
+ // the client's.
+ void SetLastPingDay(const std::string& extension_id, const base::Time& time);
+
+ // Similar to the 2 above, but for the extensions blacklist.
+ base::Time BlacklistLastPingDay() const;
+ void SetBlacklistLastPingDay(const base::Time& time);
+
+ // Similar to LastPingDay/SetLastPingDay, but for sending "days since active"
+ // ping.
+ base::Time LastActivePingDay(const std::string& extension_id);
+ void SetLastActivePingDay(const std::string& extension_id,
+ const base::Time& time);
+
+ // A bit we use for determining if we should send the "days since active"
+ // ping. A value of true means the item has been active (launched) since the
+ // last update check.
+ bool GetActiveBit(const std::string& extension_id);
+ void SetActiveBit(const std::string& extension_id, bool active);
+
+ // Returns the granted permission set for the extension with |extension_id|,
+ // and NULL if no preferences were found for |extension_id|.
+ // This passes ownership of the returned set to the caller.
+ PermissionSet* GetGrantedPermissions(const std::string& extension_id);
+
+ // Adds |permissions| to the granted permissions set for the extension with
+ // |extension_id|. The new granted permissions set will be the union of
+ // |permissions| and the already granted permissions.
+ void AddGrantedPermissions(const std::string& extension_id,
+ const PermissionSet* permissions);
+
+ // As above, but subtracts the given |permissions| from the granted set.
+ void RemoveGrantedPermissions(const std::string& extension_id,
+ const PermissionSet* permissions);
+
+ // Gets the active permission set for the specified extension. This may
+ // differ from the permissions in the manifest due to the optional
+ // permissions API. This passes ownership of the set to the caller.
+ PermissionSet* GetActivePermissions(const std::string& extension_id);
+
+ // Sets the active |permissions| for the extension with |extension_id|.
+ void SetActivePermissions(const std::string& extension_id,
+ const PermissionSet* permissions);
+
+ // Records whether or not this extension is currently running.
+ void SetExtensionRunning(const std::string& extension_id, bool is_running);
+
+ // Returns whether or not this extension is marked as running. This is used to
+ // restart apps across browser restarts.
+ bool IsExtensionRunning(const std::string& extension_id);
+
+ // Set/Get whether or not the app is active. Used to force a launch of apps
+ // that don't handle onRestarted() on a restart. We can only safely do that if
+ // the app was active when it was last running.
+ void SetIsActive(const std::string& extension_id, bool is_active);
+ bool IsActive(const std::string& extension_id);
+
+ // Returns true if the user enabled this extension to be loaded in incognito
+ // mode.
+ //
+ // IMPORTANT: you probably want to use extension_utils::IsIncognitoEnabled
+ // instead of this method.
+ bool IsIncognitoEnabled(const std::string& extension_id) const;
+ void SetIsIncognitoEnabled(const std::string& extension_id, bool enabled);
+
+ // Returns true if the user has chosen to allow this extension to inject
+ // scripts into pages with file URLs.
+ //
+ // IMPORTANT: you probably want to use extension_utils::AllowFileAccess
+ // instead of this method.
+ bool AllowFileAccess(const std::string& extension_id) const;
+ void SetAllowFileAccess(const std::string& extension_id, bool allow);
+ bool HasAllowFileAccessSetting(const std::string& extension_id) const;
+
+ // Saves ExtensionInfo for each installed extension with the path to the
+ // version directory and the location. Blacklisted extensions won't be saved
+ // and neither will external extensions the user has explicitly uninstalled.
+ // Caller takes ownership of returned structure.
+ scoped_ptr<ExtensionsInfo> GetInstalledExtensionsInfo() const;
+
+ // Same as above, but only includes external extensions the user has
+ // explicitly uninstalled.
+ scoped_ptr<ExtensionsInfo> GetUninstalledExtensionsInfo() const;
+
+ // Returns the ExtensionInfo from the prefs for the given extension. If the
+ // extension is not present, NULL is returned.
+ scoped_ptr<ExtensionInfo> GetInstalledExtensionInfo(
+ const std::string& extension_id) const;
+
+ // We've downloaded an updated .crx file for the extension, but are waiting
+ // to install it.
+ void SetDelayedInstallInfo(const Extension* extension,
+ Extension::State initial_state,
+ bool blacklisted_for_malware,
+ DelayReason delay_reason,
+ const syncer::StringOrdinal& page_ordinal);
+
+ // Removes any delayed install information we have for the given
+ // |extension_id|. Returns true if there was info to remove; false otherwise.
+ bool RemoveDelayedInstallInfo(const std::string& extension_id);
+
+ // Update the prefs to finish the update for an extension.
+ bool FinishDelayedInstallInfo(const std::string& extension_id);
+
+ // Returns the ExtensionInfo from the prefs for delayed install information
+ // for |extension_id|, if we have any. Otherwise returns NULL.
+ scoped_ptr<ExtensionInfo> GetDelayedInstallInfo(
+ const std::string& extension_id) const;
+
+ DelayReason GetDelayedInstallReason(const std::string& extension_id) const;
+
+ // Returns information about all the extensions that have delayed install
+ // information.
+ scoped_ptr<ExtensionsInfo> GetAllDelayedInstallInfo() const;
+
+ // Returns true if the user repositioned the app on the app launcher via drag
+ // and drop.
+ bool WasAppDraggedByUser(const std::string& extension_id);
+
+ // Sets a flag indicating that the user repositioned the app on the app
+ // launcher by drag and dropping it.
+ void SetAppDraggedByUser(const std::string& extension_id);
+
+ // Returns true if there is an extension which controls the preference value
+ // for |pref_key| *and* it is specific to incognito mode.
+ bool HasIncognitoPrefValue(const std::string& pref_key);
+
+ // Returns the creation flags mask for the extension.
+ int GetCreationFlags(const std::string& extension_id) const;
+
+ // Returns the creation flags mask for a delayed install extension.
+ int GetDelayedInstallCreationFlags(const std::string& extension_id) const;
+
+ // Returns true if the extension was installed from the Chrome Web Store.
+ bool IsFromWebStore(const std::string& extension_id) const;
+
+ // Returns true if the extension was installed from an App generated from a
+ // bookmark.
+ bool IsFromBookmark(const std::string& extension_id) const;
+
+ // Returns true if the extension was installed as a default app.
+ bool WasInstalledByDefault(const std::string& extension_id) const;
+
+ // Helper method to acquire the installation time of an extension.
+ // Returns base::Time() if the installation time could not be parsed or
+ // found.
+ base::Time GetInstallTime(const std::string& extension_id) const;
+
+ // Gets/sets the last launch time of an extension.
+ base::Time GetLastLaunchTime(const std::string& extension_id) const;
+ void SetLastLaunchTime(const std::string& extension_id,
+ const base::Time& time);
+
+ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+ bool extensions_disabled() { return extensions_disabled_; }
+
+ ContentSettingsStore* content_settings_store() {
+ return content_settings_store_.get();
+ }
+
+ // The underlying PrefService.
+ PrefService* pref_service() const { return prefs_; }
+
+ // The underlying AppSorting.
+ AppSorting* app_sorting() const { return app_sorting_.get(); }
+
+ // Describes the URLs that are able to install extensions. See
+ // pref_names::kAllowedInstallSites for more information.
+ URLPatternSet GetAllowedInstallSites();
+
+ // Schedules garbage collection of an extension's on-disk data on the next
+ // start of this ExtensionService. Applies only to extensions with isolated
+ // storage.
+ void SetNeedsStorageGarbageCollection(bool value);
+ bool NeedsStorageGarbageCollection();
+
+ // Used by ShellWindowGeometryCache to persist its cache. These methods
+ // should not be called directly.
+ const base::DictionaryValue* GetGeometryCache(
+ const std::string& extension_id) const;
+ void SetGeometryCache(const std::string& extension_id,
+ scoped_ptr<base::DictionaryValue> cache);
+
+ // Used for verification of installed extension ids. For the Set method, pass
+ // null to remove the preference.
+ const base::DictionaryValue* GetInstallSignature();
+ void SetInstallSignature(const base::DictionaryValue* signature);
+
+ private:
+ friend class ExtensionPrefsBlacklistedExtensions; // Unit test.
+ friend class ExtensionPrefsUninstallExtension; // Unit test.
+
+ // See the Create methods.
+ ExtensionPrefs(PrefService* prefs,
+ const base::FilePath& root_dir,
+ ExtensionPrefValueMap* extension_pref_value_map,
+ scoped_ptr<AppSorting> app_sorting,
+ scoped_ptr<TimeProvider> time_provider,
+ bool extensions_disabled);
+
+ // Converts absolute paths in the pref to paths relative to the
+ // install_directory_.
+ void MakePathsRelative();
+
+ // Converts internal relative paths to be absolute. Used for export to
+ // consumers who expect full paths.
+ void MakePathsAbsolute(base::DictionaryValue* dict);
+
+ // Helper function used by GetInstalledExtensionInfo() and
+ // GetDelayedInstallInfo() to construct an ExtensionInfo from the provided
+ // |extension| dictionary.
+ scoped_ptr<ExtensionInfo> GetInstalledInfoHelper(
+ const std::string& extension_id,
+ const base::DictionaryValue* extension) const;
+
+ // Interprets the list pref, |pref_key| in |extension_id|'s preferences, as a
+ // URLPatternSet. The |valid_schemes| specify how to parse the URLPatterns.
+ bool ReadPrefAsURLPatternSet(const std::string& extension_id,
+ const std::string& pref_key,
+ URLPatternSet* result,
+ int valid_schemes);
+
+ // Converts |new_value| to a list of strings and sets the |pref_key| pref
+ // belonging to |extension_id|.
+ void SetExtensionPrefURLPatternSet(const std::string& extension_id,
+ const std::string& pref_key,
+ const URLPatternSet& new_value);
+
+ // Read the boolean preference entry and return true if the preference exists
+ // and the preference's value is true; false otherwise.
+ bool ReadPrefAsBooleanAndReturn(const std::string& extension_id,
+ const std::string& key) const;
+
+ // Interprets |pref_key| in |extension_id|'s preferences as an
+ // PermissionSet, and passes ownership of the set to the caller.
+ PermissionSet* ReadPrefAsPermissionSet(const std::string& extension_id,
+ const std::string& pref_key);
+
+ // Converts the |new_value| to its value and sets the |pref_key| pref
+ // belonging to |extension_id|.
+ void SetExtensionPrefPermissionSet(const std::string& extension_id,
+ const std::string& pref_key,
+ const PermissionSet* new_value);
+
+ // Returns an immutable dictionary for extension |id|'s prefs, or NULL if it
+ // doesn't exist.
+ const base::DictionaryValue* GetExtensionPref(const std::string& id) const;
+
+ // Fix missing preference entries in the extensions that are were introduced
+ // in a later Chrome version.
+ void FixMissingPrefs(const ExtensionIdList& extension_ids);
+
+ // Installs the persistent extension preferences into |prefs_|'s extension
+ // pref store. Does nothing if extensions_disabled_ is true.
+ void InitPrefStore();
+
+ // Migrates the permissions data in the pref store.
+ void MigratePermissions(const ExtensionIdList& extension_ids);
+
+ // Migrates the disable reasons from a single enum to a bit mask.
+ void MigrateDisableReasons(const ExtensionIdList& extension_ids);
+
+ // Checks whether there is a state pref for the extension and if so, whether
+ // it matches |check_state|.
+ bool DoesExtensionHaveState(const std::string& id,
+ Extension::State check_state) const;
+
+ // Reads the list of strings for |pref| from user prefs into
+ // |id_container_out|. Returns false if the pref wasn't found in the user
+ // pref store.
+ template <class ExtensionIdContainer>
+ bool GetUserExtensionPrefIntoContainer(
+ const char* pref,
+ ExtensionIdContainer* id_container_out);
+
+ // Writes the list of strings contained in |strings| to |pref| in prefs.
+ template <class ExtensionIdContainer>
+ void SetExtensionPrefFromContainer(const char* pref,
+ const ExtensionIdContainer& strings);
+
+ // Helper function to populate |extension_dict| with the values needed
+ // by a newly installed extension. Work is broken up between this
+ // function and FinishExtensionInfoPrefs() to accomodate delayed
+ // installations.
+ void PopulateExtensionInfoPrefs(const Extension* extension,
+ const base::Time install_time,
+ Extension::State initial_state,
+ bool blacklisted_for_malware,
+ base::DictionaryValue* extension_dict);
+
+ // Helper function to complete initialization of the values in
+ // |extension_dict| for an extension install. Also see
+ // PopulateExtensionInfoPrefs().
+ void FinishExtensionInfoPrefs(
+ const std::string& extension_id,
+ const base::Time install_time,
+ bool needs_sort_ordinal,
+ const syncer::StringOrdinal& suggested_page_ordinal,
+ base::DictionaryValue* extension_dict);
+
+ // The pref service specific to this set of extension prefs. Owned by the
+ // BrowserContext.
+ PrefService* prefs_;
+
+ // Base extensions install directory.
+ base::FilePath install_directory_;
+
+ // Weak pointer, owned by BrowserContext.
+ ExtensionPrefValueMap* extension_pref_value_map_;
+
+ // Contains all the logic for handling the order for various extension
+ // properties.
+ scoped_ptr<AppSorting> app_sorting_;
+
+ scoped_refptr<ContentSettingsStore> content_settings_store_;
+
+ scoped_ptr<TimeProvider> time_provider_;
+
+ bool extensions_disabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionPrefs);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_EXTENSION_PREFS_H_
diff --git a/extensions/browser/extension_prefs_factory.cc b/extensions/browser/extension_prefs_factory.cc
new file mode 100644
index 0000000..e83e33b
--- /dev/null
+++ b/extensions/browser/extension_prefs_factory.cc
@@ -0,0 +1,61 @@
+// 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 "base/command_line.h"
+#include "base/prefs/pref_service.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+#include "extensions/browser/extension_pref_value_map.h"
+#include "extensions/browser/extension_pref_value_map_factory.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_prefs_factory.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/common/constants.h"
+
+namespace extensions {
+
+// static
+ExtensionPrefs* ExtensionPrefsFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<ExtensionPrefs*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+ExtensionPrefsFactory* ExtensionPrefsFactory::GetInstance() {
+ return Singleton<ExtensionPrefsFactory>::get();
+}
+
+void ExtensionPrefsFactory::SetInstanceForTesting(
+ content::BrowserContext* context, ExtensionPrefs* prefs) {
+ Associate(context, prefs);
+}
+
+ExtensionPrefsFactory::ExtensionPrefsFactory()
+ : BrowserContextKeyedServiceFactory(
+ "ExtensionPrefs",
+ BrowserContextDependencyManager::GetInstance()) {
+}
+
+ExtensionPrefsFactory::~ExtensionPrefsFactory() {
+}
+
+BrowserContextKeyedService* ExtensionPrefsFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get();
+ return ExtensionPrefs::Create(
+ client->GetPrefServiceForContext(context),
+ context->GetPath().AppendASCII(extensions::kInstallDirectoryName),
+ ExtensionPrefValueMapFactory::GetForBrowserContext(context),
+ client->CreateAppSorting().Pass(),
+ client->AreExtensionsDisabled(
+ *CommandLine::ForCurrentProcess(), context));
+}
+
+content::BrowserContext* ExtensionPrefsFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
+}
+
+} // namespace extensions
diff --git a/extensions/browser/extension_prefs_factory.h b/extensions/browser/extension_prefs_factory.h
new file mode 100644
index 0000000..3aee29a
--- /dev/null
+++ b/extensions/browser/extension_prefs_factory.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef EXTENSIONS_BROWSER_EXTENSION_PREFS_FACTORY_H_
+#define EXTENSIONS_BROWSER_EXTENSION_PREFS_FACTORY_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+namespace extensions {
+
+class ExtensionPrefs;
+
+class ExtensionPrefsFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ static ExtensionPrefs* GetForBrowserContext(content::BrowserContext* context);
+
+ static ExtensionPrefsFactory* GetInstance();
+
+ void SetInstanceForTesting(
+ content::BrowserContext* context, ExtensionPrefs* prefs);
+
+ private:
+ friend struct DefaultSingletonTraits<ExtensionPrefsFactory>;
+
+ ExtensionPrefsFactory();
+ virtual ~ExtensionPrefsFactory();
+
+ virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const OVERRIDE;
+ virtual content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const OVERRIDE;
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_EXTENSION_PREFS_FACTORY_H_
diff --git a/extensions/browser/extension_scoped_prefs.h b/extensions/browser/extension_scoped_prefs.h
new file mode 100644
index 0000000..15fc577
--- /dev/null
+++ b/extensions/browser/extension_scoped_prefs.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef EXTENSIONS_BROWSER_EXTENSION_SCOPED_PREFS_H_
+#define EXTENSIONS_BROWSER_EXTENSION_SCOPED_PREFS_H_
+
+namespace extensions {
+
+class ExtensionScopedPrefs {
+ public:
+ ExtensionScopedPrefs() {}
+ ~ExtensionScopedPrefs() {}
+
+ // Sets the pref |key| for extension |id| to |value|.
+ virtual void UpdateExtensionPref(const std::string& id,
+ const std::string& key,
+ base::Value* value) = 0;
+
+ // Deletes the pref dictionary for extension |id|.
+ virtual void DeleteExtensionPrefs(const std::string& id) = 0;
+
+ // Reads a boolean pref |pref_key| from extension with id |extension_id|.
+ virtual bool ReadPrefAsBoolean(const std::string& extension_id,
+ const std::string& pref_key,
+ bool* out_value) const = 0;
+
+ // Reads an integer pref |pref_key| from extension with id |extension_id|.
+ virtual bool ReadPrefAsInteger(const std::string& extension_id,
+ const std::string& pref_key,
+ int* out_value) const = 0;
+
+ // Reads a string pref |pref_key| from extension with id |extension_id|.
+ virtual bool ReadPrefAsString(const std::string& extension_id,
+ const std::string& pref_key,
+ std::string* out_value) const = 0;
+
+ // Reads a list pref |pref_key| from extension with id |extension_id|.
+ virtual bool ReadPrefAsList(const std::string& extension_id,
+ const std::string& pref_key,
+ const base::ListValue** out_value) const = 0;
+
+ // Reads a dictionary pref |pref_key| from extension with id |extension_id|.
+ virtual bool ReadPrefAsDictionary(
+ const std::string& extension_id,
+ const std::string& pref_key,
+ const base::DictionaryValue** out_value) const = 0;
+
+ // Returns true if the prefs contain an entry for an extension with id
+ // |extension_id|.
+ virtual bool HasPrefForExtension(const std::string& extension_id) const = 0;
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_EXTENSION_SCOPED_PREFS_H_
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
index 46405a0..ee7fde3 100644
--- a/extensions/browser/extensions_browser_client.h
+++ b/extensions/browser/extensions_browser_client.h
@@ -60,7 +60,7 @@ class ExtensionsBrowserClient {
virtual content::BrowserContext* GetOffTheRecordContext(
content::BrowserContext* context) = 0;
- // Return the original "recording" context. This method returns |context| if
+ // Returns the original "recording" context. This method returns |context| if
// |context| is not incognito.
virtual content::BrowserContext* GetOriginalContext(
content::BrowserContext* context) = 0;
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index 725c675..7ad28d0f5 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -172,15 +172,26 @@
'browser/event_listener_map.h',
'browser/event_router.cc',
'browser/event_router.h',
- 'browser/extension_prefs_scope.h',
'browser/extension_error.cc',
'browser/extension_error.h',
'browser/extension_function.cc',
'browser/extension_function.h',
+ 'browser/extension_pref_store.cc',
+ 'browser/extension_pref_store.h',
+ 'browser/extension_pref_value_map.cc',
+ 'browser/extension_pref_value_map_factory.cc',
+ 'browser/extension_pref_value_map_factory.h',
+ 'browser/extension_pref_value_map.h',
+ 'browser/extension_prefs.cc',
+ 'browser/extension_prefs.h',
+ 'browser/extension_prefs_factory.cc',
+ 'browser/extension_prefs_factory.h',
+ 'browser/extension_prefs_scope.h',
'browser/extension_registry.cc',
'browser/extension_registry.h',
'browser/extension_registry_factory.cc',
'browser/extension_registry_factory.h',
+ 'browser/extension_scoped_prefs.h',
'browser/extensions_browser_client.cc',
'browser/extensions_browser_client.h',
'browser/external_provider_interface.h',