diff options
author | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-09 22:30:47 +0000 |
---|---|---|
committer | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-09 22:30:47 +0000 |
commit | 69f65a24803adfc456ef9382c31ee37d6cdac5b1 (patch) | |
tree | b0014db2eaa00366654af88f23b7a9142c9addc6 /base/prefs | |
parent | 9e108b3bcbdd0f7a46b6f6c1887996015bbb32c3 (diff) | |
download | chromium_src-69f65a24803adfc456ef9382c31ee37d6cdac5b1.zip chromium_src-69f65a24803adfc456ef9382c31ee37d6cdac5b1.tar.gz chromium_src-69f65a24803adfc456ef9382c31ee37d6cdac5b1.tar.bz2 |
Revert 269415 "Introduce a new framework for back-and-forth trac..."
Reverting because this appears to have caused Linux TSAN redness.
> Introduce a new framework for back-and-forth tracked preference migration
> between Protected Preferences and unprotected Preferences.
>
> Migration from unprotected Preferences to Protected Preferences was previously
> done after both stores had been initialized. This was inherently incorrect as
> some operations (PrefHashFilter::FilterOnLoad) would occur before the values
> had been moved to the proper store. It also introduced a weird method in
> PrefHashFilter::MigrateValues which required an independent PrefHashFilter
> (backed by a copy of the real PrefHashStore). This after-the-fact migration
> caused Settings.TrackedPreferenceCleared spikes when changing a value from
> being enforced to not being enforced (as we'd have a MAC, but no value yet in
> this store when running FilterOnLoad()) and more importantly it also caused
> issue 365769 -- both of these issues highlight the incorrectness of the
> current approach.
>
> The migration back from Protected Preferences to unprotected Preferences when
> enforcement was disabled was using yet another mechanism which would only kick
> in when a given pref was written to (ref. old non-const
> SegregatedPrefStore::StoreForKey()).
>
> The new framework intercepts PrefFilter::FilterOnLoad() events for both stores
> and does the back-and-forth migration in place before it even hands them back
> to the PrefFilter::FinalizeFilterOnLoad() which then hands it back to the
> JsonPrefStores (so that they are agnostic to the migration; from their point
> of view their values were always in their store as they received it).
> Furthermore, this new framework will easily allow us to later move MACs out of
> Local State into their respective stores (which is a task on our radar which
> we currently have no easy way to accomplish).
>
> The new framework also handles read errors better. For example, it was
> previously possible for the unprotected->protected migration to result in data
> loss if the protected store was somehow read-only from a read error while the
> unprotected store wasn't -- resulting in an in-memory migration only flushed
> to disk in the store from which the value was deleted... The new framework
> handles those cases, preferring temporary data duplication over potential data
> loss (duplicated data is cleaned up once confirmation is obtained that the new
> authority for this data has been successfully written to disk -- it will even
> try again in following Chrome runs if it doesn't succeed in this one).
>
> Note: This CL helped LSAN discover an existing leak in post_task_and_reply_impl.cc, see issue 371974 for details.
>
> BUG=365769, 371974
> TEST=
> A) Make sure all kTrackedPrefs consistently report
> Settings.TrackedPreferenceUnchanged across changes from various enforcement
> levels (using --force-fieldtrials).
> B) Make sure the prefs are properly migrated to their new store (and
> subsequently cleaned up from their old store) when changing the
> enforcement_level across multiple runs.
> C) Make sure prefs are properly migrated in a quick startup/shutdown with a
> new enforcement_level and that their old value is properly cleaned up in a
> subsequent startup at the same enforcement_level (or re-migrated at another
> enforcement_level).
>
> R=bauerb@chromium.org, robertshield@chromium.org, stuartmorgan@chromium.org, thakis@chromium.org
>
> Initially Committed in: https://src.chromium.org/viewvc/chrome?view=rev&revision=269346
> Reverted in: https://src.chromium.org/viewvc/chrome?view=rev&revision=269367
>
> Review URL: https://codereview.chromium.org/257003007
TBR=gab@chromium.org
Review URL: https://codereview.chromium.org/273243002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269438 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/prefs')
-rw-r--r-- | base/prefs/json_pref_store.cc | 150 | ||||
-rw-r--r-- | base/prefs/json_pref_store.h | 48 | ||||
-rw-r--r-- | base/prefs/json_pref_store_unittest.cc | 176 | ||||
-rw-r--r-- | base/prefs/persistent_pref_store.h | 25 | ||||
-rw-r--r-- | base/prefs/pref_filter.h | 26 |
5 files changed, 77 insertions, 348 deletions
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc index e99d64f..b0a16cc 100644 --- a/base/prefs/json_pref_store.cc +++ b/base/prefs/json_pref_store.cc @@ -39,8 +39,6 @@ class FileThreadDeserializer void Start(const base::FilePath& path) { DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); - // TODO(gab): This should use PostTaskAndReplyWithResult instead of using - // the |error_| member to pass data across tasks. sequenced_task_runner_->PostTask( FROM_HERE, base::Bind(&FileThreadDeserializer::ReadFileAndReport, @@ -61,7 +59,7 @@ class FileThreadDeserializer // Reports deserialization result on the origin thread. void ReportOnOriginThread() { DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); - delegate_->OnFileRead(value_.Pass(), error_, no_dir_); + delegate_->OnFileRead(value_.release(), error_, no_dir_); } static base::Value* DoReading(const base::FilePath& path, @@ -163,9 +161,7 @@ JsonPrefStore::JsonPrefStore(const base::FilePath& filename, writer_(filename, sequenced_task_runner), pref_filter_(pref_filter.Pass()), initialized_(false), - filtering_in_progress_(false), - read_error_(PREF_READ_ERROR_NONE) { -} + read_error_(PREF_READ_ERROR_OTHER) {} bool JsonPrefStore::GetValue(const std::string& key, const base::Value** result) const { @@ -228,12 +224,6 @@ void JsonPrefStore::RemoveValue(const std::string& key) { ReportValueChanged(key); } -void JsonPrefStore::RemoveValueSilently(const std::string& key) { - prefs_->RemovePath(key, NULL); - if (!read_only_) - writer_.ScheduleWrite(this); -} - bool JsonPrefStore::ReadOnly() const { return read_only_; } @@ -244,26 +234,23 @@ PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const { PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { if (path_.empty()) { - OnFileRead( - scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); + OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); return PREF_READ_ERROR_FILE_NOT_SPECIFIED; } PrefReadError error; bool no_dir; - scoped_ptr<base::Value> value( - FileThreadDeserializer::DoReading(path_, &error, &no_dir)); - OnFileRead(value.Pass(), error, no_dir); - return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE : - error; + base::Value* value = + FileThreadDeserializer::DoReading(path_, &error, &no_dir); + OnFileRead(value, error, no_dir); + return error; } -void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) { +void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) { initialized_ = false; error_delegate_.reset(error_delegate); if (path_.empty()) { - OnFileRead( - scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); + OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); return; } @@ -289,63 +276,53 @@ void JsonPrefStore::ReportValueChanged(const std::string& key) { writer_.ScheduleWrite(this); } -void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback( - const base::Closure& on_next_successful_write) { - writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write); -} - -void JsonPrefStore::OnFileRead(scoped_ptr<base::Value> value, +void JsonPrefStore::OnFileRead(base::Value* value_owned, PersistentPrefStore::PrefReadError error, bool no_dir) { - scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue); - + scoped_ptr<base::Value> value(value_owned); read_error_ = error; - bool initialization_successful = !no_dir; - - if (initialization_successful) { - switch (read_error_) { - case PREF_READ_ERROR_ACCESS_DENIED: - case PREF_READ_ERROR_FILE_OTHER: - case PREF_READ_ERROR_FILE_LOCKED: - case PREF_READ_ERROR_JSON_TYPE: - case PREF_READ_ERROR_FILE_NOT_SPECIFIED: - read_only_ = true; - break; - case PREF_READ_ERROR_NONE: - DCHECK(value.get()); - unfiltered_prefs.reset( - static_cast<base::DictionaryValue*>(value.release())); - break; - case PREF_READ_ERROR_NO_FILE: - // If the file just doesn't exist, maybe this is first run. In any case - // there's no harm in writing out default prefs in this case. - break; - case PREF_READ_ERROR_JSON_PARSE: - case PREF_READ_ERROR_JSON_REPEAT: - break; - case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE: - // This is a special error code to be returned by ReadPrefs when it - // can't complete synchronously, it should never be returned by the read - // operation itself. - NOTREACHED(); - break; - case PREF_READ_ERROR_MAX_ENUM: - NOTREACHED(); - break; - } + if (no_dir) { + FOR_EACH_OBSERVER(PrefStore::Observer, + observers_, + OnInitializationCompleted(false)); + return; } - if (pref_filter_) { - filtering_in_progress_ = true; - const PrefFilter::PostFilterOnLoadCallback post_filter_on_load_callback( - base::Bind( - &JsonPrefStore::FinalizeFileRead, this, initialization_successful)); - pref_filter_->FilterOnLoad(post_filter_on_load_callback, - unfiltered_prefs.Pass()); - } else { - FinalizeFileRead(initialization_successful, unfiltered_prefs.Pass(), false); + initialized_ = true; + + switch (error) { + case PREF_READ_ERROR_ACCESS_DENIED: + case PREF_READ_ERROR_FILE_OTHER: + case PREF_READ_ERROR_FILE_LOCKED: + case PREF_READ_ERROR_JSON_TYPE: + case PREF_READ_ERROR_FILE_NOT_SPECIFIED: + read_only_ = true; + break; + case PREF_READ_ERROR_NONE: + DCHECK(value.get()); + prefs_.reset(static_cast<base::DictionaryValue*>(value.release())); + break; + case PREF_READ_ERROR_NO_FILE: + // If the file just doesn't exist, maybe this is first run. In any case + // there's no harm in writing out default prefs in this case. + break; + case PREF_READ_ERROR_JSON_PARSE: + case PREF_READ_ERROR_JSON_REPEAT: + break; + default: + NOTREACHED() << "Unknown error: " << error; } + + if (pref_filter_ && pref_filter_->FilterOnLoad(prefs_.get())) + writer_.ScheduleWrite(this); + + if (error_delegate_.get() && error != PREF_READ_ERROR_NONE) + error_delegate_->OnError(error); + + FOR_EACH_OBSERVER(PrefStore::Observer, + observers_, + OnInitializationCompleted(true)); } JsonPrefStore::~JsonPrefStore() { @@ -360,32 +337,3 @@ bool JsonPrefStore::SerializeData(std::string* output) { serializer.set_pretty_print(true); return serializer.Serialize(*prefs_); } - -void JsonPrefStore::FinalizeFileRead(bool initialization_successful, - scoped_ptr<base::DictionaryValue> prefs, - bool schedule_write) { - filtering_in_progress_ = false; - - if (!initialization_successful) { - FOR_EACH_OBSERVER(PrefStore::Observer, - observers_, - OnInitializationCompleted(false)); - return; - } - - prefs_ = prefs.Pass(); - - initialized_ = true; - - if (schedule_write && !read_only_) - writer_.ScheduleWrite(this); - - if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE) - error_delegate_->OnError(read_error_); - - FOR_EACH_OBSERVER(PrefStore::Observer, - observers_, - OnInitializationCompleted(true)); - - return; -} diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h index 49e74ee..ad13feb 100644 --- a/base/prefs/json_pref_store.h +++ b/base/prefs/json_pref_store.h @@ -9,12 +9,10 @@ #include <string> #include "base/basictypes.h" -#include "base/callback_forward.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/files/important_file_writer.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop_proxy.h" #include "base/observer_list.h" #include "base/prefs/base_prefs_export.h" @@ -34,8 +32,7 @@ class Value; // A writable PrefStore implementation that is used for user preferences. class BASE_PREFS_EXPORT JsonPrefStore : public PersistentPrefStore, - public base::ImportantFileWriter::DataSerializer, - public base::SupportsWeakPtr<JsonPrefStore> { + public base::ImportantFileWriter::DataSerializer { public: // Returns instance of SequencedTaskRunner which guarantees that file // operations on the same file will be executed in sequenced order. @@ -66,37 +63,16 @@ class BASE_PREFS_EXPORT JsonPrefStore virtual void RemoveValue(const std::string& key) OVERRIDE; virtual bool ReadOnly() const OVERRIDE; virtual PrefReadError GetReadError() const OVERRIDE; - // Note this method may be asynchronous if this instance has a |pref_filter_| - // in which case it will return PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE. - // See details in pref_filter.h. virtual PrefReadError ReadPrefs() OVERRIDE; virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) OVERRIDE; virtual void CommitPendingWrite() OVERRIDE; virtual void ReportValueChanged(const std::string& key) OVERRIDE; - // Just like RemoveValue(), but doesn't notify observers. Used when doing some - // cleanup that shouldn't otherwise alert observers. - void RemoveValueSilently(const std::string& key); - - // Registers |on_next_successful_write| to be called once, on the next - // successful write event of |writer_|. - void RegisterOnNextSuccessfulWriteCallback( - const base::Closure& on_next_successful_write); - - // This method is called after the JSON file has been read. It then hands - // |value| (or an empty dictionary in some read error cases) to the - // |pref_filter| if one is set. It also gives a callback pointing at - // FinalizeFileRead() to that |pref_filter_| which is then responsible for - // invoking it when done. If there is no |pref_filter_|, FinalizeFileRead() - // is invoked directly. - // Note, this method is used with asynchronous file reading, so this class - // exposes it only for the internal needs (read: do not call it manually). - // TODO(gab): Move this method to the private section and hand a callback to - // it to FileThreadDeserializer rather than exposing this public method and - // giving a JsonPrefStore* to FileThreadDeserializer. - void OnFileRead(scoped_ptr<base::Value> value, - PrefReadError error, - bool no_dir); + // This method is called after JSON file has been read. Method takes + // ownership of the |value| pointer. Note, this method is used with + // asynchronous file reading, so class exposes it only for the internal needs. + // (read: do not call it manually). + void OnFileRead(base::Value* value_owned, PrefReadError error, bool no_dir); private: virtual ~JsonPrefStore(); @@ -104,17 +80,6 @@ class BASE_PREFS_EXPORT JsonPrefStore // ImportantFileWriter::DataSerializer overrides: virtual bool SerializeData(std::string* output) OVERRIDE; - // This method is called after the JSON file has been read and the result has - // potentially been intercepted and modified by |pref_filter_|. - // |initialization_successful| is pre-determined by OnFileRead() and should - // be used when reporting OnInitializationCompleted(). - // |schedule_write| indicates whether a write should be immediately scheduled - // (typically because the |pref_filter_| has already altered the |prefs|) -- - // this will be ignored if this store is read-only. - void FinalizeFileRead(bool initialization_successful, - scoped_ptr<base::DictionaryValue> prefs, - bool schedule_write); - base::FilePath path_; const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_; @@ -131,7 +96,6 @@ class BASE_PREFS_EXPORT JsonPrefStore scoped_ptr<ReadErrorDelegate> error_delegate_; bool initialized_; - bool filtering_in_progress_; PrefReadError read_error_; std::set<std::string> keys_need_empty_value_; diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc index 4c9c847..f4e1e51 100644 --- a/base/prefs/json_pref_store_unittest.cc +++ b/base/prefs/json_pref_store_unittest.cc @@ -4,12 +4,10 @@ #include "base/prefs/json_pref_store.h" -#include "base/bind.h" #include "base/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/path_service.h" #include "base/prefs/pref_filter.h" #include "base/run_loop.h" @@ -27,50 +25,6 @@ namespace { const char kHomePage[] = "homepage"; -// A PrefFilter that will intercept all calls to FilterOnLoad() and hold on -// to the |prefs| until explicitly asked to release them. -class InterceptingPrefFilter : public PrefFilter { - public: - InterceptingPrefFilter(); - virtual ~InterceptingPrefFilter(); - - // PrefFilter implementation: - virtual void FilterOnLoad( - const PostFilterOnLoadCallback& post_filter_on_load_callback, - scoped_ptr<base::DictionaryValue> pref_store_contents) OVERRIDE; - virtual void FilterUpdate(const std::string& path) OVERRIDE {} - virtual void FilterSerializeData( - const base::DictionaryValue* pref_store_contents) OVERRIDE {} - - bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; } - - // Finalize an intercepted read, handing |intercept_prefs_| back to its - // JsonPrefStore. - void ReleasePrefs(); - - private: - PostFilterOnLoadCallback post_filter_on_load_callback_; - scoped_ptr<base::DictionaryValue> intercepted_prefs_; - - DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter); -}; - -InterceptingPrefFilter::InterceptingPrefFilter() {} -InterceptingPrefFilter::~InterceptingPrefFilter() {} - -void InterceptingPrefFilter::FilterOnLoad( - const PostFilterOnLoadCallback& post_filter_on_load_callback, - scoped_ptr<base::DictionaryValue> pref_store_contents) { - post_filter_on_load_callback_ = post_filter_on_load_callback; - intercepted_prefs_ = pref_store_contents.Pass(); -} - -void InterceptingPrefFilter::ReleasePrefs() { - EXPECT_FALSE(post_filter_on_load_callback_.is_null()); - post_filter_on_load_callback_.Run(intercepted_prefs_.Pass(), false); - post_filter_on_load_callback_.Reset(); -} - class MockPrefStoreObserver : public PrefStore::Observer { public: MOCK_METHOD1(OnPrefValueChanged, void (const std::string&)); @@ -94,13 +48,6 @@ class JsonPrefStoreTest : public testing::Test { ASSERT_TRUE(PathExists(data_dir_)); } - virtual void TearDown() OVERRIDE { - // Make sure all pending tasks have been processed (e.g., deleting the - // JsonPrefStore may post write tasks). - message_loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure()); - message_loop_.Run(); - } - // The path to temporary directory used to contain the test operations. base::ScopedTempDir temp_dir_; // The path to the directory where the test data is stored. @@ -210,7 +157,7 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store, TEST_F(JsonPrefStoreTest, Basic) { ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), - temp_dir_.path().AppendASCII("write.json"))); + temp_dir_.path().AppendASCII("write.json"))); // Test that the persistent value can be loaded. base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); @@ -220,8 +167,7 @@ TEST_F(JsonPrefStoreTest, Basic) { message_loop_.message_loop_proxy().get(), scoped_ptr<PrefFilter>()); ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); - EXPECT_FALSE(pref_store->ReadOnly()); - EXPECT_TRUE(pref_store->IsInitializationComplete()); + ASSERT_FALSE(pref_store->ReadOnly()); // The JSON file looks like this: // { @@ -239,7 +185,7 @@ TEST_F(JsonPrefStoreTest, Basic) { TEST_F(JsonPrefStoreTest, BasicAsync) { ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), - temp_dir_.path().AppendASCII("write.json"))); + temp_dir_.path().AppendASCII("write.json"))); // Test that the persistent value can be loaded. base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); @@ -262,8 +208,7 @@ TEST_F(JsonPrefStoreTest, BasicAsync) { RunLoop().RunUntilIdle(); pref_store->RemoveObserver(&mock_observer); - EXPECT_FALSE(pref_store->ReadOnly()); - EXPECT_TRUE(pref_store->IsInitializationComplete()); + ASSERT_FALSE(pref_store->ReadOnly()); } // The JSON file looks like this: @@ -356,117 +301,4 @@ TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) { EXPECT_FALSE(pref_store->ReadOnly()); } -TEST_F(JsonPrefStoreTest, ReadWithInterceptor) { - ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), - temp_dir_.path().AppendASCII("write.json"))); - - // Test that the persistent value can be loaded. - base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); - ASSERT_TRUE(PathExists(input_file)); - - scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter( - new InterceptingPrefFilter()); - InterceptingPrefFilter* raw_intercepting_pref_filter_ = - intercepting_pref_filter.get(); - scoped_refptr<JsonPrefStore> pref_store = - new JsonPrefStore(input_file, - message_loop_.message_loop_proxy().get(), - intercepting_pref_filter.PassAs<PrefFilter>()); - - ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE, - pref_store->ReadPrefs()); - EXPECT_FALSE(pref_store->ReadOnly()); - - // The store shouldn't be considered initialized until the interceptor - // returns. - EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs()); - EXPECT_FALSE(pref_store->IsInitializationComplete()); - EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL)); - - raw_intercepting_pref_filter_->ReleasePrefs(); - - EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs()); - EXPECT_TRUE(pref_store->IsInitializationComplete()); - EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL)); - - // The JSON file looks like this: - // { - // "homepage": "http://www.cnn.com", - // "some_directory": "/usr/local/", - // "tabs": { - // "new_windows_in_tabs": true, - // "max_tabs": 20 - // } - // } - - RunBasicJsonPrefStoreTest( - pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); -} - -TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) { - ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), - temp_dir_.path().AppendASCII("write.json"))); - - // Test that the persistent value can be loaded. - base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); - ASSERT_TRUE(PathExists(input_file)); - - scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter( - new InterceptingPrefFilter()); - InterceptingPrefFilter* raw_intercepting_pref_filter_ = - intercepting_pref_filter.get(); - scoped_refptr<JsonPrefStore> pref_store = - new JsonPrefStore(input_file, - message_loop_.message_loop_proxy().get(), - intercepting_pref_filter.PassAs<PrefFilter>()); - - MockPrefStoreObserver mock_observer; - pref_store->AddObserver(&mock_observer); - - // Ownership of the |mock_error_delegate| is handed to the |pref_store| below. - MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate; - - { - pref_store->ReadPrefsAsync(mock_error_delegate); - - EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0); - // EXPECT_CALL(*mock_error_delegate, - // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0); - RunLoop().RunUntilIdle(); - - EXPECT_FALSE(pref_store->ReadOnly()); - EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs()); - EXPECT_FALSE(pref_store->IsInitializationComplete()); - EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL)); - } - - { - EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); - // EXPECT_CALL(*mock_error_delegate, - // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0); - - raw_intercepting_pref_filter_->ReleasePrefs(); - - EXPECT_FALSE(pref_store->ReadOnly()); - EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs()); - EXPECT_TRUE(pref_store->IsInitializationComplete()); - EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL)); - } - - pref_store->RemoveObserver(&mock_observer); - - // The JSON file looks like this: - // { - // "homepage": "http://www.cnn.com", - // "some_directory": "/usr/local/", - // "tabs": { - // "new_windows_in_tabs": true, - // "max_tabs": 20 - // } - // } - - RunBasicJsonPrefStoreTest( - pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); -} - } // namespace base diff --git a/base/prefs/persistent_pref_store.h b/base/prefs/persistent_pref_store.h index 177d860..44f3442 100644 --- a/base/prefs/persistent_pref_store.h +++ b/base/prefs/persistent_pref_store.h @@ -17,22 +17,19 @@ class BASE_PREFS_EXPORT PersistentPrefStore : public WriteablePrefStore { public: // Unique integer code for each type of error so we can report them // distinctly in a histogram. - // NOTE: Don't change the explicit values of the enums as it will change the - // server's meaning of the histogram. + // NOTE: Don't change the order here as it will change the server's meaning + // of the histogram. enum PrefReadError { PREF_READ_ERROR_NONE = 0, - PREF_READ_ERROR_JSON_PARSE = 1, - PREF_READ_ERROR_JSON_TYPE = 2, - PREF_READ_ERROR_ACCESS_DENIED = 3, - PREF_READ_ERROR_FILE_OTHER = 4, - PREF_READ_ERROR_FILE_LOCKED = 5, - PREF_READ_ERROR_NO_FILE = 6, - PREF_READ_ERROR_JSON_REPEAT = 7, - // PREF_READ_ERROR_OTHER = 8, // Deprecated. - PREF_READ_ERROR_FILE_NOT_SPECIFIED = 9, - // Indicates that ReadPrefs() couldn't complete synchronously and is waiting - // for an asynchronous task to complete first. - PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE = 10, + PREF_READ_ERROR_JSON_PARSE, + PREF_READ_ERROR_JSON_TYPE, + PREF_READ_ERROR_ACCESS_DENIED, + PREF_READ_ERROR_FILE_OTHER, + PREF_READ_ERROR_FILE_LOCKED, + PREF_READ_ERROR_NO_FILE, + PREF_READ_ERROR_JSON_REPEAT, + PREF_READ_ERROR_OTHER, + PREF_READ_ERROR_FILE_NOT_SPECIFIED, PREF_READ_ERROR_MAX_ENUM }; diff --git a/base/prefs/pref_filter.h b/base/prefs/pref_filter.h index 1020029..ce07f92 100644 --- a/base/prefs/pref_filter.h +++ b/base/prefs/pref_filter.h @@ -7,8 +7,6 @@ #include <string> -#include "base/callback_forward.h" -#include "base/memory/scoped_ptr.h" #include "base/prefs/base_prefs_export.h" namespace base { @@ -20,25 +18,15 @@ class Value; // Currently supported only by JsonPrefStore. class BASE_PREFS_EXPORT PrefFilter { public: - // A callback to be invoked when |prefs| have been read (and possibly - // pre-modified) and are now ready to be handed back to this callback's - // builder. |schedule_write| indicates whether a write should be immediately - // scheduled (typically because the |prefs| were pre-modified). - typedef base::Callback<void(scoped_ptr<base::DictionaryValue> prefs, - bool schedule_write)> PostFilterOnLoadCallback; - virtual ~PrefFilter() {} - // This method is given ownership of the |pref_store_contents| read from disk - // before the underlying PersistentPrefStore gets to use them. It must hand - // them back via |post_filter_on_load_callback|, but may modify them first. - // Note: This method is asynchronous, which may make calls like - // PersistentPrefStore::ReadPrefs() asynchronous. The owner of filtered - // PersistentPrefStores should handle this to make the reads look synchronous - // to external users (see SegregatedPrefStore::ReadPrefs() for an example). - virtual void FilterOnLoad( - const PostFilterOnLoadCallback& post_filter_on_load_callback, - scoped_ptr<base::DictionaryValue> pref_store_contents) = 0; + // Receives notification when the pref store data has been loaded but before + // Observers are notified. + // Changes made by a PrefFilter during FilterOnLoad do not result in + // notifications to |PrefStore::Observer|s. + // Implementations should return true if they modify the dictionary, to allow + // the changes to be persisted. + virtual bool FilterOnLoad(base::DictionaryValue* pref_store_contents) = 0; // Receives notification when a pref store value is changed, before Observers // are notified. |