Chromium Code Reviews| OLD | NEW |
|---|---|
| (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/json/json_reader.h" | |
| 9 #include "base/metrics/field_trial.h" | |
| 10 #include "base/metrics/histogram.h" | |
| 11 #include "base/prefs/pref_service.h" | |
| 12 #include "base/task_runner.h" | |
| 13 #include "base/threading/sequenced_worker_pool.h" | |
| 14 #include "chrome/browser/profile_resetter/automatic_profile_resetter_mementos.h" | |
| 15 #include "chrome/browser/profiles/profile.h" | |
| 16 #include "content/public/browser/browser_thread.h" | |
| 17 #include "grit/browser_resources.h" | |
| 18 #include "ui/base/resource/resource_bundle.h" | |
| 19 | |
| 20 namespace profile_resetter { | |
| 21 namespace { | |
| 22 | |
| 23 // Number of bits, and maximum value (exclusive) for the mask consisting of | |
| 24 // flags that tell which of reset criteria were satisfied. | |
| 25 const size_t kSatisfiedCriteriaMaskBits = 2; | |
| 26 const uint32 kSatisfiedCriteriaMaskMaximumValue = | |
| 27 (1 << kSatisfiedCriteriaMaskBits); | |
| 28 | |
| 29 // Number of bits, and maximum value (exclusive) for the mask consisting of | |
| 30 // flags that tell if any of reset criteria were satisfied and whether we had | |
| 31 // already shown the prompt. | |
| 32 const size_t kCombinedStatusMaskBits = 4; | |
| 33 const uint32 kCombinedStatusMaskMaximumValue = (1 << kCombinedStatusMaskBits); | |
| 34 | |
| 35 // Name constants for the field trial behind which we enable this feature. | |
| 36 const char kAutomaticProfileResetStudyName[] = "AutomaticProfileReset"; | |
| 37 const char kAutomaticProfileResetStudyDryRunGroupName[] = "DryRun"; | |
| 38 const char kAutomaticProfileResetStudyEnabledroupName[] = "Enabled"; | |
| 39 | |
| 40 // Keys used in the input dictionary of the program. | |
| 41 // TODO(engedy): Add these on an as-needed basis. | |
| 42 | |
| 43 // Keys used in the output dictionary of the program. | |
| 44 const char kHadPromptedAlreadyKey[] = "had_prompted_already"; | |
| 45 const char kSatisfiedCriteriaMaskKeys[][29] = {"satisfied_criteria_mask_bit1", | |
| 46 "satisfied_criteria_mask_bit2"}; | |
| 47 const char kCombinedStatusMaskKeys[][26] = { | |
| 48 "combined_status_mask_bit1", "combined_status_mask_bit2", | |
| 49 "combined_status_mask_bit3", "combined_status_mask_bit4"}; | |
| 50 | |
| 51 // Keys used in the input *and* output dictionary of the program. | |
| 52 const char kMementoValueInPrefsKey[] = "memento_value_in_prefs"; | |
| 53 const char kMementoValueInLocalStateKey[] = "memento_value_in_local_state"; | |
| 54 const char kMementoValueInFileKey[] = "memento_value_in_file"; | |
| 55 | |
| 56 COMPILE_ASSERT( | |
| 57 arraysize(kSatisfiedCriteriaMaskKeys) == kSatisfiedCriteriaMaskBits, | |
| 58 satisfied_criteria_mask_bits_mismatch); | |
| 59 COMPILE_ASSERT(arraysize(kCombinedStatusMaskKeys) == kCombinedStatusMaskBits, | |
| 60 combined_status_mask_bits_mismatch); | |
| 61 | |
| 62 // Implementation detail classes --------------------------------------------- | |
| 63 | |
| 64 // Mostly trivial AutomaticProfileResetterDelegate implementation. | |
|
robertshield
2013/09/25 20:18:12
Nit: delete the above line, or explain how the imp
engedy
2013/09/27 23:27:34
Done.
| |
| 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 // A fake interpreter that enables writing EvaluateConditionsOnWorkerPoolThread. | |
|
robertshield
2013/09/25 20:18:12
s/enables writing/used by/
Also mention that this
engedy
2013/09/27 23:27:34
I have wired in the real thing. PTAL below.
| |
| 92 class FakeInterpreter { | |
| 93 public: | |
| 94 FakeInterpreter() {} | |
| 95 ~FakeInterpreter() {} | |
| 96 | |
| 97 bool GetOutputBoolean(const std::string& key, bool* target) { return false; } | |
| 98 | |
| 99 bool GetOutputString(const std::string& key, std::string* target) { | |
| 100 return false; | |
| 101 } | |
| 102 | |
| 103 private: | |
| 104 DISALLOW_COPY_AND_ASSIGN(FakeInterpreter); | |
| 105 }; | |
| 106 | |
| 107 // Enumeration of the possible outcomes of showing the profile reset prompt. | |
| 108 enum PromptResult { | |
| 109 // Prompt was not shown because only a dry-run was performed. | |
| 110 PROMPT_NOT_SHOWN, | |
| 111 PROMPT_ACTION_RESET, | |
| 112 PROMPT_ACTION_NO_RESET, | |
| 113 PROMPT_DISMISSED, | |
| 114 // Prompt was still shown (not dismissed by the user) when Chrome was closed. | |
| 115 PROMPT_IGNORED, | |
| 116 PROMPT_RESULT_MAX | |
| 117 }; | |
| 118 | |
| 119 } // namespace | |
| 120 | |
| 121 // AutomaticProfileResetter::EvaluationResults ------------------------------- | |
| 122 | |
| 123 // Encapsulates the output values extracted from the evaluator program. | |
| 124 struct AutomaticProfileResetter::EvaluationResults { | |
| 125 EvaluationResults() | |
| 126 : had_prompted_already(false), | |
| 127 satisfied_criteria_mask(0), | |
| 128 combined_status_mask(0) {} | |
| 129 | |
| 130 std::string memento_value_in_prefs; | |
| 131 std::string memento_value_in_local_state; | |
| 132 std::string memento_value_in_file; | |
| 133 | |
| 134 bool had_prompted_already; | |
| 135 uint32 satisfied_criteria_mask; | |
| 136 uint32 combined_status_mask; | |
| 137 }; | |
| 138 | |
| 139 // AutomaticProfileResetter -------------------------------------------------- | |
| 140 | |
| 141 AutomaticProfileResetter::AutomaticProfileResetter(Profile* profile) | |
| 142 : profile_(profile), | |
| 143 state_(STATE_UNINITIALIZED), | |
| 144 memento_in_prefs_(profile_), | |
| 145 memento_in_local_state_(profile_), | |
| 146 memento_in_file_(profile_), | |
| 147 weak_ptr_factory_(this) { | |
| 148 DCHECK(profile_); | |
| 149 } | |
| 150 | |
| 151 AutomaticProfileResetter::~AutomaticProfileResetter() {} | |
| 152 | |
| 153 void AutomaticProfileResetter::Initialize() { | |
| 154 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 155 DCHECK_EQ(state_, STATE_UNINITIALIZED); | |
| 156 | |
| 157 if (IsDryRun() || IsLiveRun()) { | |
| 158 ui::ResourceBundle& resources(ui::ResourceBundle::GetSharedInstance()); | |
| 159 if (IsLiveRun()) { | |
| 160 program_ = | |
| 161 resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_RULES); | |
| 162 hash_seed_ = | |
| 163 resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED); | |
| 164 } else { | |
| 165 program_ = | |
| 166 resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_RULES_DRY); | |
| 167 hash_seed_ = resources.GetRawDataResource( | |
| 168 IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED_DRY); | |
| 169 } | |
| 170 delegate_.reset(new AutomaticProfileResetterDelegateImpl()); | |
| 171 state_ = STATE_READY; | |
| 172 | |
| 173 content::BrowserThread::PostTask( | |
| 174 content::BrowserThread::UI, | |
| 175 FROM_HERE, | |
| 176 base::Bind(&AutomaticProfileResetter::BeginEvaluationFlow, | |
| 177 weak_ptr_factory_.GetWeakPtr())); | |
| 178 } else { | |
| 179 state_ = STATE_DISABLED; | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 bool AutomaticProfileResetter::IsDryRun() const { | |
| 184 return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) == | |
| 185 kAutomaticProfileResetStudyDryRunGroupName; | |
| 186 } | |
| 187 | |
| 188 bool AutomaticProfileResetter::IsLiveRun() const { | |
| 189 return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) == | |
| 190 kAutomaticProfileResetStudyEnabledroupName; | |
|
robertshield
2013/09/25 20:18:12
Looks like there is a G missing before the "roup"
engedy
2013/09/27 23:27:34
Done.
| |
| 191 } | |
| 192 | |
| 193 void AutomaticProfileResetter::BeginEvaluationFlow() { | |
| 194 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 195 DCHECK_EQ(state_, STATE_READY); | |
| 196 | |
| 197 state_ = STATE_WORKING; | |
| 198 | |
| 199 memento_in_file_.ReadValue( | |
| 200 base::Bind(&AutomaticProfileResetter::ContinueWithEvaluationFlow, | |
| 201 weak_ptr_factory_.GetWeakPtr())); | |
| 202 } | |
| 203 | |
| 204 scoped_ptr<base::DictionaryValue> | |
| 205 AutomaticProfileResetter::BuildEvaluatorProgramInput( | |
| 206 const std::string& memento_value_in_file) { | |
| 207 // TODO(engedy): Add any additional state that is needed here. | |
| 208 scoped_ptr<base::DictionaryValue> input(new base::DictionaryValue); | |
| 209 input->SetString(kMementoValueInPrefsKey, memento_in_prefs_.ReadValue()); | |
| 210 input->SetString(kMementoValueInLocalStateKey, | |
| 211 memento_in_local_state_.ReadValue()); | |
| 212 input->SetString(kMementoValueInFileKey, memento_value_in_file); | |
| 213 return input.Pass(); | |
| 214 } | |
| 215 | |
| 216 void AutomaticProfileResetter::ContinueWithEvaluationFlow( | |
| 217 const std::string& memento_value_in_file) { | |
| 218 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 219 DCHECK_EQ(state_, STATE_WORKING); | |
| 220 PrefService* prefs = profile_->GetPrefs(); | |
| 221 DCHECK(prefs); | |
| 222 | |
| 223 scoped_ptr<base::DictionaryValue> input( | |
| 224 BuildEvaluatorProgramInput(memento_value_in_file)); | |
| 225 | |
| 226 base::SequencedWorkerPool* blocking_pool = | |
| 227 content::BrowserThread::GetBlockingPool(); | |
| 228 scoped_refptr<base::TaskRunner> task_runner = | |
| 229 blocking_pool->GetTaskRunnerWithShutdownBehavior( | |
| 230 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
| 231 | |
| 232 base::PostTaskAndReplyWithResult( | |
| 233 task_runner.get(), | |
| 234 FROM_HERE, | |
| 235 base::Bind(&EvaluateConditionsOnWorkerPoolThread, | |
| 236 hash_seed_.as_string(), | |
| 237 program_.as_string(), | |
| 238 base::Passed(&input)), | |
| 239 base::Bind(&AutomaticProfileResetter::FinishEvaluationFlow, | |
| 240 weak_ptr_factory_.GetWeakPtr())); | |
| 241 } | |
| 242 | |
| 243 scoped_ptr<AutomaticProfileResetter::EvaluationResults> | |
|
battre
2013/09/25 09:43:26
add "// static" before this line
or in my opinion
engedy
2013/09/27 23:27:34
I am not sure I understand: how would this be any
| |
| 244 AutomaticProfileResetter::EvaluateConditionsOnWorkerPoolThread( | |
| 245 const std::string& hash_key, | |
| 246 const std::string& program, | |
| 247 scoped_ptr<base::DictionaryValue> program_input) { | |
| 248 // TODO(engedy): Once implemented, call real interpreter from here. | |
| 249 scoped_ptr<EvaluationResults> results(new EvaluationResults()); | |
| 250 FakeInterpreter interpreter; | |
| 251 interpreter.GetOutputBoolean(kHadPromptedAlreadyKey, | |
| 252 &results->had_prompted_already); | |
| 253 interpreter.GetOutputString(kMementoValueInPrefsKey, | |
| 254 &results->memento_value_in_prefs); | |
| 255 interpreter.GetOutputString(kMementoValueInLocalStateKey, | |
| 256 &results->memento_value_in_local_state); | |
| 257 interpreter.GetOutputString(kMementoValueInFileKey, | |
| 258 &results->memento_value_in_file); | |
| 259 for (size_t i = 0; i < arraysize(kCombinedStatusMaskKeys); ++i) { | |
| 260 bool flag = false; // Default value. | |
| 261 interpreter.GetOutputBoolean(kCombinedStatusMaskKeys[i], &flag); | |
| 262 if (flag) | |
| 263 results->combined_status_mask |= (1 << i); | |
| 264 } | |
| 265 for (size_t i = 0; i < arraysize(kSatisfiedCriteriaMaskKeys); ++i) { | |
| 266 bool flag = false; // Default value. | |
| 267 interpreter.GetOutputBoolean(kSatisfiedCriteriaMaskKeys[i], &flag); | |
| 268 if (flag) | |
| 269 results->satisfied_criteria_mask |= (1 << i); | |
| 270 } | |
| 271 | |
| 272 return results.Pass(); | |
| 273 } | |
| 274 | |
| 275 void AutomaticProfileResetter::FinishEvaluationFlow( | |
| 276 scoped_ptr<EvaluationResults> results) { | |
| 277 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 278 DCHECK_EQ(state_, STATE_WORKING); | |
| 279 | |
| 280 delegate_->ReportStatistics(results->satisfied_criteria_mask, | |
| 281 results->combined_status_mask); | |
| 282 | |
| 283 if (results->satisfied_criteria_mask != 0 && !results->had_prompted_already) { | |
| 284 memento_in_prefs_.StoreValue(results->memento_value_in_prefs); | |
| 285 memento_in_local_state_.StoreValue(results->memento_value_in_local_state); | |
| 286 memento_in_file_.StoreValue(results->memento_value_in_file); | |
| 287 | |
| 288 if (IsLiveRun()) | |
| 289 delegate_->ShowPrompt(); | |
| 290 else | |
|
robertshield
2013/09/25 20:18:12
style nit: multi line statements should be wrapped
engedy
2013/09/27 23:27:34
Done.
| |
| 291 UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.PromptResult", | |
| 292 PROMPT_NOT_SHOWN, | |
| 293 PROMPT_RESULT_MAX); | |
| 294 } | |
| 295 | |
| 296 state_ = STATE_DONE; | |
| 297 } | |
| 298 | |
| 299 void AutomaticProfileResetter::SetHashSeedForTesting( | |
| 300 const std::string& hash_key) { | |
| 301 hash_seed_ = hash_key; | |
|
battre
2013/09/25 09:43:26
This looks incorrect. If he passed hash_key parame
engedy
2013/09/25 16:56:59
Good point. I played around too much with StringPi
engedy
2013/09/27 23:27:34
Done.
| |
| 302 } | |
| 303 | |
| 304 void AutomaticProfileResetter::SetProgramForTesting( | |
| 305 const std::string& program) { | |
| 306 program_ = program; | |
| 307 } | |
| 308 | |
| 309 void AutomaticProfileResetter::SetDelegateForTesting( | |
| 310 AutomaticProfileResetterDelegate* delegate) { | |
| 311 delegate_.reset(delegate); | |
| 312 } | |
| 313 | |
| 314 void AutomaticProfileResetter::Shutdown() { | |
| 315 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 316 | |
| 317 state_ = STATE_DISABLED; | |
| 318 delegate_.reset(); | |
| 319 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 320 } | |
| 321 | |
| 322 } // namespace profile_resetter | |
| OLD | NEW |