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

Side by Side 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, 2 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/profile_resetter/automatic_profile_resetter.h"
6
7 #include "base/bind_helpers.h"
8 #include "base/logging.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/task_runner.h"
14 #include "base/task_runner_util.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "chrome/browser/profile_resetter/jtl_interpreter.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "grit/browser_resources.h"
20 #include "ui/base/resource/resource_bundle.h"
21
22 namespace {
23
24 // Number of bits, and maximum value (exclusive) for the mask whose bits
25 // indicate which of reset criteria were satisfied.
26 const size_t kSatisfiedCriteriaMaskBits = 2;
27 const uint32 kSatisfiedCriteriaMaskMaximumValue =
28 (1 << kSatisfiedCriteriaMaskBits);
29
30 // Number of bits, and maximum value (exclusive) for the mask whose bits
31 // indicate if any of reset criteria were satisfied, and which of the mementos
32 // were already present.
33 const size_t kCombinedStatusMaskBits = 4;
34 const uint32 kCombinedStatusMaskMaximumValue = (1 << kCombinedStatusMaskBits);
35
36 // Name constants for the field trial behind which we enable this feature.
37 const char kAutomaticProfileResetStudyName[] = "AutomaticProfileReset";
38 const char kAutomaticProfileResetStudyDryRunGroupName[] = "DryRun";
39 const char kAutomaticProfileResetStudyEnabledGroupName[] = "Enabled";
40
41 // Keys used in the input dictionary of the program.
42 // TODO(engedy): Add these here on an as-needed basis.
43
44 // Keys used in the output dictionary of the program.
45 const char kHadPromptedAlreadyKey[] = "had_prompted_already";
46 const char kSatisfiedCriteriaMaskKeys[][29] = {"satisfied_criteria_mask_bit1",
47 "satisfied_criteria_mask_bit2"};
48 const char kCombinedStatusMaskKeys[][26] = {
49 "combined_status_mask_bit1", "combined_status_mask_bit2",
50 "combined_status_mask_bit3", "combined_status_mask_bit4"};
51
52 // Keys used in both the input and output dictionary of the program.
53 const char kMementoValueInPrefsKey[] = "memento_value_in_prefs";
54 const char kMementoValueInLocalStateKey[] = "memento_value_in_local_state";
55 const char kMementoValueInFileKey[] = "memento_value_in_file";
56
57 COMPILE_ASSERT(
58 arraysize(kSatisfiedCriteriaMaskKeys) == kSatisfiedCriteriaMaskBits,
59 satisfied_criteria_mask_bits_mismatch);
60 COMPILE_ASSERT(arraysize(kCombinedStatusMaskKeys) == kCombinedStatusMaskBits,
61 combined_status_mask_bits_mismatch);
62
63 // Implementation detail classes ---------------------------------------------
64
65 class AutomaticProfileResetterDelegateImpl
66 : public AutomaticProfileResetterDelegate {
67 public:
68 AutomaticProfileResetterDelegateImpl() {}
69 virtual ~AutomaticProfileResetterDelegateImpl() {}
70
71 // AutomaticProfileResetterDelegate overrides:
72
73 virtual void ShowPrompt() OVERRIDE {
74 // TODO(engedy): Call the UI from here once we have it.
75 }
76
77 virtual void ReportStatistics(uint32 satisfied_criteria_mask,
78 uint32 combined_status_mask) OVERRIDE {
79 UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.SatisfiedCriteriaMask",
80 satisfied_criteria_mask,
81 kSatisfiedCriteriaMaskMaximumValue);
82 UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.CombinedStatusMask",
83 combined_status_mask,
84 kCombinedStatusMaskMaximumValue);
85 }
86
87 private:
88 DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetterDelegateImpl);
89 };
90
91 // Enumeration of the possible outcomes of showing the profile reset prompt.
92 enum PromptResult {
93 // Prompt was not shown because only a dry-run was performed.
94 PROMPT_NOT_SHOWN,
95 PROMPT_ACTION_RESET,
96 PROMPT_ACTION_NO_RESET,
97 PROMPT_DISMISSED,
98 // Prompt was still shown (not dismissed by the user) when Chrome was closed.
99 PROMPT_IGNORED,
100 PROMPT_RESULT_MAX
101 };
102
103 } // namespace
104
105 // AutomaticProfileResetter::EvaluationResults -------------------------------
106
107 // Encapsulates the output values extracted from the evaluator program.
108 struct AutomaticProfileResetter::EvaluationResults {
109 EvaluationResults()
110 : had_prompted_already(false),
111 satisfied_criteria_mask(0),
112 combined_status_mask(0) {}
113
114 std::string memento_value_in_prefs;
115 std::string memento_value_in_local_state;
116 std::string memento_value_in_file;
117
118 bool had_prompted_already;
119 uint32 satisfied_criteria_mask;
120 uint32 combined_status_mask;
121 };
122
123 // AutomaticProfileResetter --------------------------------------------------
124
125 AutomaticProfileResetter::AutomaticProfileResetter(Profile* profile)
126 : profile_(profile),
127 state_(STATE_UNINITIALIZED),
128 memento_in_prefs_(profile_),
129 memento_in_local_state_(profile_),
130 memento_in_file_(profile_),
131 weak_ptr_factory_(this) {
132 DCHECK(profile_);
133 }
134
135 AutomaticProfileResetter::~AutomaticProfileResetter() {}
136
137 void AutomaticProfileResetter::Initialize() {
138 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
139 DCHECK_EQ(state_, STATE_UNINITIALIZED);
140
141 if (ShouldPerformDryRun() || ShouldPerformLiveRun()) {
142 ui::ResourceBundle& resources(ui::ResourceBundle::GetSharedInstance());
143 if (ShouldPerformLiveRun()) {
144 program_ =
145 resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_RULES);
146 hash_seed_ =
147 resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED);
148 } else { // ShouldPerformDryRun()
149 program_ =
150 resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_RULES_DRY);
151 hash_seed_ = resources.GetRawDataResource(
152 IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED_DRY);
153 }
154 delegate_.reset(new AutomaticProfileResetterDelegateImpl());
155
156 state_ = STATE_READY;
157
158 content::BrowserThread::PostTask(
159 content::BrowserThread::UI,
160 FROM_HERE,
161 base::Bind(&AutomaticProfileResetter::BeginEvaluationFlow,
162 weak_ptr_factory_.GetWeakPtr()));
163 } else {
164 state_ = STATE_DISABLED;
165 }
166 }
167
168 bool AutomaticProfileResetter::ShouldPerformDryRun() const {
169 return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
170 kAutomaticProfileResetStudyDryRunGroupName;
171 }
172
173 bool AutomaticProfileResetter::ShouldPerformLiveRun() const {
174 return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
175 kAutomaticProfileResetStudyEnabledGroupName;
176 }
177
178 void AutomaticProfileResetter::BeginEvaluationFlow() {
179 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
180 DCHECK_EQ(state_, STATE_READY);
181
182 if (!program_.empty()) {
183 state_ = STATE_WORKING;
184 memento_in_file_.ReadValue(
185 base::Bind(&AutomaticProfileResetter::ContinueWithEvaluationFlow,
186 weak_ptr_factory_.GetWeakPtr()));
187 } else {
188 // Terminate early if there is no program included (nor set by tests).
189 state_ = STATE_DISABLED;
190 }
191 }
192
193 scoped_ptr<base::DictionaryValue>
194 AutomaticProfileResetter::BuildEvaluatorProgramInput(
195 const std::string& memento_value_in_file) {
196 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
197 // TODO(engedy): Add any additional state here that is needed by the program.
198 scoped_ptr<base::DictionaryValue> input(new base::DictionaryValue);
199 input->SetString(kMementoValueInPrefsKey, memento_in_prefs_.ReadValue());
200 input->SetString(kMementoValueInLocalStateKey,
201 memento_in_local_state_.ReadValue());
202 input->SetString(kMementoValueInFileKey, memento_value_in_file);
203 return input.Pass();
204 }
205
206 void AutomaticProfileResetter::ContinueWithEvaluationFlow(
207 const std::string& memento_value_in_file) {
208 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
209 DCHECK_EQ(state_, STATE_WORKING);
210 PrefService* prefs = profile_->GetPrefs();
211 DCHECK(prefs);
212
213 scoped_ptr<base::DictionaryValue> input(
214 BuildEvaluatorProgramInput(memento_value_in_file));
215
216 base::SequencedWorkerPool* blocking_pool =
217 content::BrowserThread::GetBlockingPool();
218 scoped_refptr<base::TaskRunner> task_runner =
219 blocking_pool->GetTaskRunnerWithShutdownBehavior(
220 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
221
222 base::PostTaskAndReplyWithResult(
223 task_runner.get(),
224 FROM_HERE,
225 base::Bind(&EvaluateConditionsOnWorkerPoolThread,
226 hash_seed_,
227 program_,
228 base::Passed(&input)),
229 base::Bind(&AutomaticProfileResetter::FinishEvaluationFlow,
230 weak_ptr_factory_.GetWeakPtr()));
231 }
232
233 // static
234 scoped_ptr<AutomaticProfileResetter::EvaluationResults>
235 AutomaticProfileResetter::EvaluateConditionsOnWorkerPoolThread(
236 const base::StringPiece& hash_seed,
237 const base::StringPiece& program,
238 scoped_ptr<base::DictionaryValue> program_input) {
239 std::string hash_seed_str(hash_seed.as_string());
240 std::string program_str(program.as_string());
241 JtlInterpreter interpreter(hash_seed_str, program_str, program_input.get());
242 interpreter.Execute();
243 UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.InterpreterResult",
244 interpreter.result(),
245 JtlInterpreter::RESULT_MAX);
246
247 // In each case below, the respective field in result originally contains the
248 // default, so if the getter fails, we still have the correct value there.
249 scoped_ptr<EvaluationResults> results(new EvaluationResults());
250 interpreter.GetOutputBoolean(kHadPromptedAlreadyKey,
251 &results->had_prompted_already);
252 interpreter.GetOutputString(kMementoValueInPrefsKey,
253 &results->memento_value_in_prefs);
254 interpreter.GetOutputString(kMementoValueInLocalStateKey,
255 &results->memento_value_in_local_state);
256 interpreter.GetOutputString(kMementoValueInFileKey,
257 &results->memento_value_in_file);
258 for (size_t i = 0; i < arraysize(kCombinedStatusMaskKeys); ++i) {
259 bool flag = false;
260 if (interpreter.GetOutputBoolean(kCombinedStatusMaskKeys[i], &flag) && flag)
261 results->combined_status_mask |= (1 << i);
262 }
263 for (size_t i = 0; i < arraysize(kSatisfiedCriteriaMaskKeys); ++i) {
264 bool flag = false;
265 if (interpreter.GetOutputBoolean(kSatisfiedCriteriaMaskKeys[i], &flag) &&
266 flag)
267 results->satisfied_criteria_mask |= (1 << i);
268 }
269 return results.Pass();
270 }
271
272 void AutomaticProfileResetter::FinishEvaluationFlow(
273 scoped_ptr<EvaluationResults> results) {
274 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
275 DCHECK_EQ(state_, STATE_WORKING);
276
277 delegate_->ReportStatistics(results->satisfied_criteria_mask,
278 results->combined_status_mask);
279
280 if (results->satisfied_criteria_mask != 0 && !results->had_prompted_already) {
281 memento_in_prefs_.StoreValue(results->memento_value_in_prefs);
282 memento_in_local_state_.StoreValue(results->memento_value_in_local_state);
283 memento_in_file_.StoreValue(results->memento_value_in_file);
284
285 if (ShouldPerformLiveRun()) {
286 delegate_->ShowPrompt();
287 } else {
288 UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.PromptResult",
289 PROMPT_NOT_SHOWN,
290 PROMPT_RESULT_MAX);
291 }
292 }
293
294 state_ = STATE_DONE;
295 }
296
297 void AutomaticProfileResetter::SetHashSeedForTesting(
298 const base::StringPiece& hash_key) {
299 hash_seed_ = hash_key;
300 }
301
302 void AutomaticProfileResetter::SetProgramForTesting(
303 const base::StringPiece& program) {
304 program_ = program;
305 }
306
307 void AutomaticProfileResetter::SetDelegateForTesting(
308 AutomaticProfileResetterDelegate* delegate) {
309 delegate_.reset(delegate);
310 }
311
312 void AutomaticProfileResetter::Shutdown() {
313 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
314
315 state_ = STATE_DISABLED;
316 delegate_.reset();
317 weak_ptr_factory_.InvalidateWeakPtrs();
318 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698