Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1569)

Unified Diff: chrome/browser/profile_resetter/automatic_profile_resetter.cc

Issue 24533002: Added the AutomaticProfileResetter service. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Final touches on unittests. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
new file mode 100644
index 0000000000000000000000000000000000000000..c0f7d252608a04107ed2dd37500e80b534f7384b
--- /dev/null
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter.cc
@@ -0,0 +1,318 @@
+// Copyright 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.
+
+#include "chrome/browser/profile_resetter/automatic_profile_resetter.h"
+
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_service.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/profile_resetter/jtl_interpreter.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_thread.h"
+#include "grit/browser_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+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";
+
+// Keys used in the input dictionary of the program.
+// TODO(engedy): Add these here on an as-needed basis.
+
+// Keys used in the output dictionary of the program.
+const char kHadPromptedAlreadyKey[] = "had_prompted_already";
+const char kSatisfiedCriteriaMaskKeys[][29] = {"satisfied_criteria_mask_bit1",
+ "satisfied_criteria_mask_bit2"};
+const char kCombinedStatusMaskKeys[][26] = {
+ "combined_status_mask_bit1", "combined_status_mask_bit2",
+ "combined_status_mask_bit3", "combined_status_mask_bit4"};
+
+// Keys used in both the input and output dictionary of the program.
+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);
+};
+
+// Enumeration of the possible outcomes of showing the profile reset prompt.
+enum PromptResult {
+ // Prompt was not shown because only a dry-run was performed.
+ PROMPT_NOT_SHOWN,
+ PROMPT_ACTION_RESET,
+ PROMPT_ACTION_NO_RESET,
+ PROMPT_DISMISSED,
+ // Prompt was still shown (not dismissed by the user) when Chrome was closed.
+ PROMPT_IGNORED,
+ PROMPT_RESULT_MAX
+};
+
+} // namespace
+
+// AutomaticProfileResetter::EvaluationResults -------------------------------
+
+// Encapsulates the output values extracted from the evaluator program.
+struct AutomaticProfileResetter::EvaluationResults {
+ EvaluationResults()
+ : had_prompted_already(false),
+ satisfied_criteria_mask(0),
+ combined_status_mask(0) {}
+
+ std::string memento_value_in_prefs;
+ std::string memento_value_in_local_state;
+ std::string memento_value_in_file;
+
+ bool had_prompted_already;
+ uint32 satisfied_criteria_mask;
+ uint32 combined_status_mask;
+};
+
+// AutomaticProfileResetter --------------------------------------------------
+
+AutomaticProfileResetter::AutomaticProfileResetter(Profile* profile)
+ : profile_(profile),
+ state_(STATE_UNINITIALIZED),
+ memento_in_prefs_(profile_),
+ memento_in_local_state_(profile_),
+ memento_in_file_(profile_),
+ weak_ptr_factory_(this) {
+ DCHECK(profile_);
+}
+
+AutomaticProfileResetter::~AutomaticProfileResetter() {}
+
+void AutomaticProfileResetter::Initialize() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK_EQ(state_, STATE_UNINITIALIZED);
+
+ if (ShouldPerformDryRun() || ShouldPerformLiveRun()) {
+ ui::ResourceBundle& resources(ui::ResourceBundle::GetSharedInstance());
+ if (ShouldPerformLiveRun()) {
+ program_ =
+ resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_RULES);
+ hash_seed_ =
+ resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED);
+ } else { // ShouldPerformDryRun()
+ program_ =
+ resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_RULES_DRY);
+ hash_seed_ = resources.GetRawDataResource(
+ IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED_DRY);
+ }
+ delegate_.reset(new AutomaticProfileResetterDelegateImpl());
+
+ 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);
+
+ 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;
+ }
+}
+
+scoped_ptr<base::DictionaryValue>
+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);
+ input->SetString(kMementoValueInPrefsKey, memento_in_prefs_.ReadValue());
+ input->SetString(kMementoValueInLocalStateKey,
+ memento_in_local_state_.ReadValue());
+ input->SetString(kMementoValueInFileKey, memento_value_in_file);
+ return input.Pass();
+}
+
+void AutomaticProfileResetter::ContinueWithEvaluationFlow(
+ const std::string& memento_value_in_file) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK_EQ(state_, STATE_WORKING);
+ PrefService* prefs = profile_->GetPrefs();
+ DCHECK(prefs);
+
+ scoped_ptr<base::DictionaryValue> input(
+ BuildEvaluatorProgramInput(memento_value_in_file));
+
+ base::SequencedWorkerPool* blocking_pool =
+ content::BrowserThread::GetBlockingPool();
+ scoped_refptr<base::TaskRunner> task_runner =
+ blocking_pool->GetTaskRunnerWithShutdownBehavior(
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+
+ base::PostTaskAndReplyWithResult(
+ task_runner.get(),
+ FROM_HERE,
+ base::Bind(&EvaluateConditionsOnWorkerPoolThread,
+ hash_seed_,
+ program_,
+ base::Passed(&input)),
+ base::Bind(&AutomaticProfileResetter::FinishEvaluationFlow,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+// static
+scoped_ptr<AutomaticProfileResetter::EvaluationResults>
+AutomaticProfileResetter::EvaluateConditionsOnWorkerPoolThread(
+ const base::StringPiece& hash_seed,
+ const base::StringPiece& program,
+ scoped_ptr<base::DictionaryValue> program_input) {
+ std::string hash_seed_str(hash_seed.as_string());
+ std::string program_str(program.as_string());
+ JtlInterpreter interpreter(hash_seed_str, program_str, program_input.get());
+ interpreter.Execute();
+ UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.InterpreterResult",
+ interpreter.result(),
+ JtlInterpreter::RESULT_MAX);
+
+ // 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());
+ interpreter.GetOutputBoolean(kHadPromptedAlreadyKey,
+ &results->had_prompted_already);
+ interpreter.GetOutputString(kMementoValueInPrefsKey,
+ &results->memento_value_in_prefs);
+ interpreter.GetOutputString(kMementoValueInLocalStateKey,
+ &results->memento_value_in_local_state);
+ interpreter.GetOutputString(kMementoValueInFileKey,
+ &results->memento_value_in_file);
+ for (size_t i = 0; i < arraysize(kCombinedStatusMaskKeys); ++i) {
+ bool flag = false;
+ if (interpreter.GetOutputBoolean(kCombinedStatusMaskKeys[i], &flag) && flag)
+ results->combined_status_mask |= (1 << i);
+ }
+ for (size_t i = 0; i < arraysize(kSatisfiedCriteriaMaskKeys); ++i) {
+ bool flag = false;
+ if (interpreter.GetOutputBoolean(kSatisfiedCriteriaMaskKeys[i], &flag) &&
+ flag)
+ results->satisfied_criteria_mask |= (1 << i);
+ }
+ return results.Pass();
+}
+
+void AutomaticProfileResetter::FinishEvaluationFlow(
+ scoped_ptr<EvaluationResults> results) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK_EQ(state_, STATE_WORKING);
+
+ delegate_->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);
+ memento_in_local_state_.StoreValue(results->memento_value_in_local_state);
+ memento_in_file_.StoreValue(results->memento_value_in_file);
+
+ if (ShouldPerformLiveRun()) {
+ delegate_->ShowPrompt();
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.PromptResult",
+ PROMPT_NOT_SHOWN,
+ PROMPT_RESULT_MAX);
+ }
+ }
+
+ state_ = STATE_DONE;
+}
+
+void AutomaticProfileResetter::SetHashSeedForTesting(
+ const base::StringPiece& hash_key) {
+ hash_seed_ = hash_key;
+}
+
+void AutomaticProfileResetter::SetProgramForTesting(
+ const base::StringPiece& program) {
+ program_ = program;
+}
+
+void AutomaticProfileResetter::SetDelegateForTesting(
+ AutomaticProfileResetterDelegate* delegate) {
+ delegate_.reset(delegate);
+}
+
+void AutomaticProfileResetter::Shutdown() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ state_ = STATE_DISABLED;
+ delegate_.reset();
+ weak_ptr_factory_.InvalidateWeakPtrs();
+}

Powered by Google App Engine
This is Rietveld 408576698