| Index: chrome/browser/profile_resetter/automatic_profile_resetter.cc
|
| diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter.cc b/chrome/browser/profile_resetter/automatic_profile_resetter.cc
|
| index c0f7d252608a04107ed2dd37500e80b534f7384b..8e5e0cbfb2e71230cf7f11d8541335bcfe53e947 100644
|
| --- a/chrome/browser/profile_resetter/automatic_profile_resetter.cc
|
| +++ b/chrome/browser/profile_resetter/automatic_profile_resetter.cc
|
| @@ -10,9 +10,14 @@
|
| #include "base/metrics/field_trial.h"
|
| #include "base/metrics/histogram.h"
|
| #include "base/prefs/pref_service.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| #include "base/task_runner.h"
|
| #include "base/task_runner_util.h"
|
| #include "base/threading/sequenced_worker_pool.h"
|
| +#include "base/time/time.h"
|
| +#include "base/values.h"
|
| +#include "chrome/browser/browser_process.h"
|
| +#include "chrome/browser/profile_resetter/automatic_profile_resetter_delegate.h"
|
| #include "chrome/browser/profile_resetter/jtl_interpreter.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| #include "content/public/browser/browser_thread.h"
|
| @@ -21,25 +26,24 @@
|
|
|
| namespace {
|
|
|
| -// Number of bits, and maximum value (exclusive) for the mask whose bits
|
| -// indicate which of reset criteria were satisfied.
|
| -const size_t kSatisfiedCriteriaMaskBits = 2;
|
| -const uint32 kSatisfiedCriteriaMaskMaximumValue =
|
| - (1 << kSatisfiedCriteriaMaskBits);
|
| -
|
| -// Number of bits, and maximum value (exclusive) for the mask whose bits
|
| -// indicate if any of reset criteria were satisfied, and which of the mementos
|
| -// were already present.
|
| -const size_t kCombinedStatusMaskBits = 4;
|
| -const uint32 kCombinedStatusMaskMaximumValue = (1 << kCombinedStatusMaskBits);
|
| -
|
| // Name constants for the field trial behind which we enable this feature.
|
| const char kAutomaticProfileResetStudyName[] = "AutomaticProfileReset";
|
| const char kAutomaticProfileResetStudyDryRunGroupName[] = "DryRun";
|
| const char kAutomaticProfileResetStudyEnabledGroupName[] = "Enabled";
|
|
|
| +// How long to wait after start-up before unleashing the evaluation flow.
|
| +const int64 kEvaluationFlowDelayInSeconds = 55;
|
| +
|
| // Keys used in the input dictionary of the program.
|
| -// TODO(engedy): Add these here on an as-needed basis.
|
| +const char kUserPreferencesKey[] = "preferences";
|
| +const char kUserPreferencesIsUserControlledKey[] = "preferences_iuc";
|
| +const char kLocalStateKey[] = "local_state";
|
| +const char kLocalStateIsUserControlledKey[] = "local_state_iuc";
|
| +const char kSearchProvidersKey[] = "search_providers";
|
| +const char kDefaultSearchProviderKey[] = "default_search_provider";
|
| +const char kDefaultSearchProviderIsUserControlledKey[] =
|
| + "default_search_provider_iuc";
|
| +const char kLoadedModuleDigestsKey[] = "loaded_modules";
|
|
|
| // Keys used in the output dictionary of the program.
|
| const char kHadPromptedAlreadyKey[] = "had_prompted_already";
|
| @@ -54,39 +58,7 @@ const char kMementoValueInPrefsKey[] = "memento_value_in_prefs";
|
| const char kMementoValueInLocalStateKey[] = "memento_value_in_local_state";
|
| const char kMementoValueInFileKey[] = "memento_value_in_file";
|
|
|
| -COMPILE_ASSERT(
|
| - arraysize(kSatisfiedCriteriaMaskKeys) == kSatisfiedCriteriaMaskBits,
|
| - satisfied_criteria_mask_bits_mismatch);
|
| -COMPILE_ASSERT(arraysize(kCombinedStatusMaskKeys) == kCombinedStatusMaskBits,
|
| - combined_status_mask_bits_mismatch);
|
| -
|
| -// Implementation detail classes ---------------------------------------------
|
| -
|
| -class AutomaticProfileResetterDelegateImpl
|
| - : public AutomaticProfileResetterDelegate {
|
| - public:
|
| - AutomaticProfileResetterDelegateImpl() {}
|
| - virtual ~AutomaticProfileResetterDelegateImpl() {}
|
| -
|
| - // AutomaticProfileResetterDelegate overrides:
|
| -
|
| - virtual void ShowPrompt() OVERRIDE {
|
| - // TODO(engedy): Call the UI from here once we have it.
|
| - }
|
| -
|
| - virtual void ReportStatistics(uint32 satisfied_criteria_mask,
|
| - uint32 combined_status_mask) OVERRIDE {
|
| - UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.SatisfiedCriteriaMask",
|
| - satisfied_criteria_mask,
|
| - kSatisfiedCriteriaMaskMaximumValue);
|
| - UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.CombinedStatusMask",
|
| - combined_status_mask,
|
| - kCombinedStatusMaskMaximumValue);
|
| - }
|
| -
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetterDelegateImpl);
|
| -};
|
| +// Implementation details ------------------------------------------------------
|
|
|
| // Enumeration of the possible outcomes of showing the profile reset prompt.
|
| enum PromptResult {
|
| @@ -100,6 +72,52 @@ enum PromptResult {
|
| PROMPT_RESULT_MAX
|
| };
|
|
|
| +// Returns whether or not a dry-run shall be performed.
|
| +bool ShouldPerformDryRun() {
|
| + return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
|
| + kAutomaticProfileResetStudyDryRunGroupName;
|
| +}
|
| +
|
| +// Returns whether or not a live-run shall be performed.
|
| +bool ShouldPerformLiveRun() {
|
| + return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
|
| + kAutomaticProfileResetStudyEnabledGroupName;
|
| +}
|
| +
|
| +// Deep-copies all preferences in |source| to a sub-tree named |value_tree_key|
|
| +// in |target_dictionary|, with path expansion, and also creates an isomorphic
|
| +// sub-tree under the key |is_user_controlled_tree_key| that contains only
|
| +// Boolean values, indicating whether or not the corresponding preferences are
|
| +// coming from the 'user' PrefStore.
|
| +void BuildSubTreesFromPreferences(const PrefService* source,
|
| + const char* value_tree_key,
|
| + const char* is_user_controlled_tree_key,
|
| + base::DictionaryValue* target_dictionary) {
|
| + scoped_ptr<base::DictionaryValue> pref_name_to_value_map(
|
| + source->GetPreferenceValuesWithoutPathExpansion());
|
| + std::vector<std::string> pref_names;
|
| + pref_names.reserve(pref_name_to_value_map->size());
|
| + for (base::DictionaryValue::Iterator it(*pref_name_to_value_map);
|
| + !it.IsAtEnd(); it.Advance())
|
| + pref_names.push_back(it.key());
|
| +
|
| + base::DictionaryValue* value_tree = new base::DictionaryValue;
|
| + base::DictionaryValue* is_user_controlled_tree = new base::DictionaryValue;
|
| + for (std::vector<std::string>::const_iterator it = pref_names.begin();
|
| + it != pref_names.end(); ++it) {
|
| + scoped_ptr<Value> pref_value_owned;
|
| + if (pref_name_to_value_map->RemoveWithoutPathExpansion(*it,
|
| + &pref_value_owned)) {
|
| + value_tree->Set(*it, pref_value_owned.release());
|
| + const PrefService::Preference* pref = source->FindPreference(it->c_str());
|
| + is_user_controlled_tree->Set(
|
| + *it, new base::FundamentalValue(pref->IsUserControlled()));
|
| + }
|
| + }
|
| + target_dictionary->Set(value_tree_key, value_tree);
|
| + target_dictionary->Set(is_user_controlled_tree_key, is_user_controlled_tree);
|
| +}
|
| +
|
| } // namespace
|
|
|
| // AutomaticProfileResetter::EvaluationResults -------------------------------
|
| @@ -122,14 +140,32 @@ struct AutomaticProfileResetter::EvaluationResults {
|
|
|
| // AutomaticProfileResetter --------------------------------------------------
|
|
|
| +const size_t AutomaticProfileResetter::kSatisfiedCriteriaMaskNumberOfBits = 2u;
|
| +const uint32 AutomaticProfileResetter::kSatisfiedCriteriaMaskMaximumValue =
|
| + (1u << AutomaticProfileResetter::kSatisfiedCriteriaMaskNumberOfBits);
|
| +
|
| +const size_t AutomaticProfileResetter::kCombinedStatusMaskNumberOfBits = 4u;
|
| +const uint32 AutomaticProfileResetter::kCombinedStatusMaskMaximumValue =
|
| + (1u << AutomaticProfileResetter::kCombinedStatusMaskNumberOfBits);
|
| +
|
| +COMPILE_ASSERT(arraysize(kSatisfiedCriteriaMaskKeys) ==
|
| + AutomaticProfileResetter::kSatisfiedCriteriaMaskNumberOfBits,
|
| + satisfied_criteria_mask_bits_mismatch);
|
| +COMPILE_ASSERT(arraysize(kCombinedStatusMaskKeys) ==
|
| + AutomaticProfileResetter::kCombinedStatusMaskNumberOfBits,
|
| + combined_status_mask_bits_mismatch);
|
| +
|
| AutomaticProfileResetter::AutomaticProfileResetter(Profile* profile)
|
| : profile_(profile),
|
| state_(STATE_UNINITIALIZED),
|
| + enumeration_of_loaded_modules_ready_(false),
|
| + template_url_service_ready_(false),
|
| memento_in_prefs_(profile_),
|
| memento_in_local_state_(profile_),
|
| memento_in_file_(profile_),
|
| weak_ptr_factory_(this) {
|
| DCHECK(profile_);
|
| + Initialize();
|
| }
|
|
|
| AutomaticProfileResetter::~AutomaticProfileResetter() {}
|
| @@ -151,55 +187,137 @@ void AutomaticProfileResetter::Initialize() {
|
| hash_seed_ = resources.GetRawDataResource(
|
| IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED_DRY);
|
| }
|
| - delegate_.reset(new AutomaticProfileResetterDelegateImpl());
|
| + delegate_.reset(new AutomaticProfileResetterDelegateImpl(profile_));
|
| + task_runner_for_waiting_ =
|
| + content::BrowserThread::GetMessageLoopProxyForThread(
|
| + content::BrowserThread::UI);
|
| + state_ = STATE_INITIALIZED;
|
| + } else {
|
| + state_ = STATE_DISABLED;
|
| + }
|
| +}
|
|
|
| - state_ = STATE_READY;
|
| +void AutomaticProfileResetter::Activate() {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| + DCHECK(state_ == STATE_INITIALIZED || state_ == STATE_DISABLED);
|
| +
|
| + if (state_ == STATE_INITIALIZED) {
|
| + if (!program_.empty()) {
|
| + // Some steps in the flow (e.g. loaded modules, file-based memento) are
|
| + // IO-intensive, so defer execution until some time later.
|
| + task_runner_for_waiting_->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&AutomaticProfileResetter::PrepareEvaluationFlow,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + base::TimeDelta::FromSeconds(kEvaluationFlowDelayInSeconds));
|
| + } else {
|
| + // Terminate early if there is no program included (nor set by tests).
|
| + state_ = STATE_DISABLED;
|
| + }
|
| + }
|
| +}
|
|
|
| +void AutomaticProfileResetter::PrepareEvaluationFlow() {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| + DCHECK_EQ(state_, STATE_INITIALIZED);
|
| +
|
| + state_ = STATE_WAITING_ON_DEPENDENCIES;
|
| +
|
| + delegate_->RequestCallbackWhenTemplateURLServiceIsLoaded(
|
| + base::Bind(&AutomaticProfileResetter::OnTemplateURLServiceIsLoaded,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + delegate_->RequestCallbackWhenLoadedModulesAreEnumerated(
|
| + base::Bind(&AutomaticProfileResetter::OnLoadedModulesAreEnumerated,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + delegate_->LoadTemplateURLServiceIfNeeded();
|
| + delegate_->EnumerateLoadedModulesIfNeeded();
|
| +}
|
| +
|
| +void AutomaticProfileResetter::OnTemplateURLServiceIsLoaded() {
|
| + template_url_service_ready_ = true;
|
| + OnDependencyIsReady();
|
| +}
|
| +
|
| +void AutomaticProfileResetter::OnLoadedModulesAreEnumerated() {
|
| + enumeration_of_loaded_modules_ready_ = true;
|
| + OnDependencyIsReady();
|
| +}
|
| +
|
| +void AutomaticProfileResetter::OnDependencyIsReady() {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| + DCHECK_EQ(state_, STATE_WAITING_ON_DEPENDENCIES);
|
| +
|
| + if (template_url_service_ready_ && enumeration_of_loaded_modules_ready_) {
|
| + state_ = STATE_READY;
|
| content::BrowserThread::PostTask(
|
| content::BrowserThread::UI,
|
| FROM_HERE,
|
| base::Bind(&AutomaticProfileResetter::BeginEvaluationFlow,
|
| weak_ptr_factory_.GetWeakPtr()));
|
| - } else {
|
| - state_ = STATE_DISABLED;
|
| }
|
| }
|
|
|
| -bool AutomaticProfileResetter::ShouldPerformDryRun() const {
|
| - return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
|
| - kAutomaticProfileResetStudyDryRunGroupName;
|
| -}
|
| -
|
| -bool AutomaticProfileResetter::ShouldPerformLiveRun() const {
|
| - return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
|
| - kAutomaticProfileResetStudyEnabledGroupName;
|
| -}
|
| -
|
| void AutomaticProfileResetter::BeginEvaluationFlow() {
|
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| DCHECK_EQ(state_, STATE_READY);
|
| + DCHECK(!program_.empty());
|
|
|
| - if (!program_.empty()) {
|
| - state_ = STATE_WORKING;
|
| - memento_in_file_.ReadValue(
|
| - base::Bind(&AutomaticProfileResetter::ContinueWithEvaluationFlow,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| - } else {
|
| - // Terminate early if there is no program included (nor set by tests).
|
| - state_ = STATE_DISABLED;
|
| - }
|
| + state_ = STATE_WORKING;
|
| + memento_in_file_.ReadValue(
|
| + base::Bind(&AutomaticProfileResetter::ContinueWithEvaluationFlow,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| }
|
|
|
| scoped_ptr<base::DictionaryValue>
|
| -AutomaticProfileResetter::BuildEvaluatorProgramInput(
|
| + AutomaticProfileResetter::BuildEvaluatorProgramInput(
|
| const std::string& memento_value_in_file) {
|
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - // TODO(engedy): Add any additional state here that is needed by the program.
|
| +
|
| scoped_ptr<base::DictionaryValue> input(new base::DictionaryValue);
|
| +
|
| + // Include memento values (or empty strings in case mementos are not there).
|
| input->SetString(kMementoValueInPrefsKey, memento_in_prefs_.ReadValue());
|
| input->SetString(kMementoValueInLocalStateKey,
|
| memento_in_local_state_.ReadValue());
|
| input->SetString(kMementoValueInFileKey, memento_value_in_file);
|
| +
|
| + // Include all user (i.e. profile-specific) preferences, along with
|
| + // information about whether the value is coming from the 'user' PrefStore.
|
| + PrefService* prefs = profile_->GetPrefs();
|
| + DCHECK(prefs);
|
| + BuildSubTreesFromPreferences(prefs,
|
| + kUserPreferencesKey,
|
| + kUserPreferencesIsUserControlledKey,
|
| + input.get());
|
| +
|
| + // Include all local state (i.e. shared) preferences, along with information
|
| + // about whether the value is coming from the 'user' PrefStore.
|
| + PrefService* local_state = g_browser_process->local_state();
|
| + DCHECK(local_state);
|
| + BuildSubTreesFromPreferences(
|
| + local_state, kLocalStateKey, kLocalStateIsUserControlledKey, input.get());
|
| +
|
| + // Include all information related to search engines.
|
| + scoped_ptr<base::DictionaryValue> default_search_provider_details(
|
| + delegate_->GetDefaultSearchProviderDetails());
|
| + if (default_search_provider_details)
|
| + input->Set(kDefaultSearchProviderKey,
|
| + default_search_provider_details.release());
|
| +
|
| + scoped_ptr<base::ListValue> search_providers_details(
|
| + delegate_->GetPrepopulatedSearchProvidersDetails());
|
| + if (search_providers_details)
|
| + input->Set(kSearchProvidersKey, search_providers_details.release());
|
| +
|
| + input->SetBoolean(kDefaultSearchProviderIsUserControlledKey,
|
| + !delegate_->IsDefaultSearchProviderManaged());
|
| +
|
| + // Include information about loaded modules.
|
| + scoped_ptr<base::ListValue> loaded_module_digests(
|
| + delegate_->GetLoadedModuleNameDigests());
|
| + if (loaded_module_digests)
|
| + input->Set(kLoadedModuleDigestsKey, loaded_module_digests.release());
|
| +
|
| return input.Pass();
|
| }
|
|
|
| @@ -232,7 +350,7 @@ void AutomaticProfileResetter::ContinueWithEvaluationFlow(
|
|
|
| // static
|
| scoped_ptr<AutomaticProfileResetter::EvaluationResults>
|
| -AutomaticProfileResetter::EvaluateConditionsOnWorkerPoolThread(
|
| + AutomaticProfileResetter::EvaluateConditionsOnWorkerPoolThread(
|
| const base::StringPiece& hash_seed,
|
| const base::StringPiece& program,
|
| scoped_ptr<base::DictionaryValue> program_input) {
|
| @@ -246,7 +364,7 @@ AutomaticProfileResetter::EvaluateConditionsOnWorkerPoolThread(
|
|
|
| // In each case below, the respective field in result originally contains the
|
| // default, so if the getter fails, we still have the correct value there.
|
| - scoped_ptr<EvaluationResults> results(new EvaluationResults());
|
| + scoped_ptr<EvaluationResults> results(new EvaluationResults);
|
| interpreter.GetOutputBoolean(kHadPromptedAlreadyKey,
|
| &results->had_prompted_already);
|
| interpreter.GetOutputString(kMementoValueInPrefsKey,
|
| @@ -274,8 +392,8 @@ void AutomaticProfileResetter::FinishEvaluationFlow(
|
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| DCHECK_EQ(state_, STATE_WORKING);
|
|
|
| - delegate_->ReportStatistics(results->satisfied_criteria_mask,
|
| - results->combined_status_mask);
|
| + ReportStatistics(results->satisfied_criteria_mask,
|
| + results->combined_status_mask);
|
|
|
| if (results->satisfied_criteria_mask != 0 && !results->had_prompted_already) {
|
| memento_in_prefs_.StoreValue(results->memento_value_in_prefs);
|
| @@ -294,6 +412,18 @@ void AutomaticProfileResetter::FinishEvaluationFlow(
|
| state_ = STATE_DONE;
|
| }
|
|
|
| +void AutomaticProfileResetter::ReportStatistics(uint32 satisfied_criteria_mask,
|
| + uint32 combined_status_mask) {
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + "AutomaticProfileReset.SatisfiedCriteriaMask",
|
| + satisfied_criteria_mask,
|
| + AutomaticProfileResetter::kSatisfiedCriteriaMaskMaximumValue);
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + "AutomaticProfileReset.CombinedStatusMask",
|
| + combined_status_mask,
|
| + AutomaticProfileResetter::kCombinedStatusMaskMaximumValue);
|
| +}
|
| +
|
| void AutomaticProfileResetter::SetHashSeedForTesting(
|
| const base::StringPiece& hash_key) {
|
| hash_seed_ = hash_key;
|
| @@ -305,8 +435,13 @@ void AutomaticProfileResetter::SetProgramForTesting(
|
| }
|
|
|
| void AutomaticProfileResetter::SetDelegateForTesting(
|
| - AutomaticProfileResetterDelegate* delegate) {
|
| - delegate_.reset(delegate);
|
| + scoped_ptr<AutomaticProfileResetterDelegate> delegate) {
|
| + delegate_ = delegate.Pass();
|
| +}
|
| +
|
| +void AutomaticProfileResetter::SetTaskRunnerForWaitingForTesting(
|
| + const scoped_refptr<base::TaskRunner>& task_runner) {
|
| + task_runner_for_waiting_ = task_runner;
|
| }
|
|
|
| void AutomaticProfileResetter::Shutdown() {
|
|
|