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

Side by Side Diff: chrome/browser/chromeos/user_cros_settings_provider.cc

Issue 8727037: Signed settings refactoring: Proper caching and more tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments. Created 9 years 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 (c) 2011 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/chromeos/user_cros_settings_provider.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/hash_tables.h"
11 #include "base/logging.h"
12 #include "base/memory/singleton.h"
13 #include "base/string_util.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chromeos/cros/cros_library.h"
17 #include "chrome/browser/chromeos/cros/network_library.h"
18 #include "chrome/browser/chromeos/cros_settings.h"
19 #include "chrome/browser/chromeos/cros_settings_names.h"
20 #include "chrome/browser/chromeos/login/ownership_service.h"
21 #include "chrome/browser/chromeos/login/ownership_status_checker.h"
22 #include "chrome/browser/chromeos/login/user_manager.h"
23 #include "chrome/browser/prefs/pref_service.h"
24 #include "chrome/browser/prefs/pref_value_map.h"
25 #include "chrome/browser/prefs/scoped_user_pref_update.h"
26 #include "chrome/browser/ui/options/options_util.h"
27 #include "chrome/common/chrome_notification_types.h"
28 #include "chrome/installer/util/google_update_settings.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/notification_service.h"
31
32 using content::BrowserThread;
33
34 namespace chromeos {
35
36 namespace {
37
38 const char kTrueIncantation[] = "true";
39 const char kFalseIncantation[] = "false";
40 const char kTrustedSuffix[] = "/trusted";
41
42 // For all our boolean settings following is applicable:
43 // true is default permissive value and false is safe prohibitic value.
44 // Exception: kSignedDataRoamingEnabled which has default value of false.
45 const char* kBooleanSettings[] = {
46 kAccountsPrefAllowNewUser,
47 kAccountsPrefAllowGuest,
48 kAccountsPrefShowUserNamesOnSignIn,
49 kSignedDataRoamingEnabled,
50 kStatsReportingPref
51 };
52
53 const char* kStringSettings[] = {
54 kDeviceOwner,
55 kReleaseChannel
56 };
57
58 const char* kListSettings[] = {
59 kAccountsPrefUsers
60 };
61
62 // This class provides the means to migrate settings to the signed settings
63 // store. It does one of three things - store the settings in the policy blob
64 // immediately if the current user is the owner. Uses the
65 // SignedSettingsTempStorage if there is no owner yet, or waits for an
66 // OWNERSHIP_CHECKED notification to delay the storing until the owner has
67 // logged in.
68 class MigrationHelper : public content::NotificationObserver {
69 public:
70 explicit MigrationHelper() : callback_(NULL) {
71 registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_CHECKED,
72 content::NotificationService::AllSources());
73 }
74
75 void set_callback(SignedSettingsHelper::Callback* callback) {
76 callback_ = callback;
77 }
78
79 void AddMigrationValue(const std::string& path, base::Value* value) {
80 migration_values_.SetValue(path, value);
81 }
82
83 void MigrateValues(void) {
84 ownership_checker_.reset(new OwnershipStatusChecker(
85 base::Bind(&MigrationHelper::DoMigrateValues, base::Unretained(this))));
86 }
87
88 // NotificationObserver overrides:
89 virtual void Observe(int type,
90 const content::NotificationSource& source,
91 const content::NotificationDetails& details) OVERRIDE {
92 if (type == chrome::NOTIFICATION_OWNERSHIP_CHECKED)
93 MigrateValues();
94 }
95
96 private:
97 void DoMigrateValues(OwnershipService::Status status,
98 bool current_user_is_owner) {
99 ownership_checker_.reset(NULL);
100
101 // We can call StartStorePropertyOp in two cases - either if the owner is
102 // currently logged in and the policy can be updated immediately or if there
103 // is no owner yet in which case the value will be temporarily stored in the
104 // SignedSettingsTempStorage until the device is owned. If none of these
105 // cases is met then we will wait for user change notification and retry.
106 if (current_user_is_owner || status != OwnershipService::OWNERSHIP_TAKEN) {
107 PrefValueMap::const_iterator i;
108 for (i = migration_values_.begin(); i != migration_values_.end(); ++i) {
109 // Queue all values for storing.
110 SignedSettingsHelper::Get()->StartStorePropertyOp(i->first, *i->second,
111 callback_);
112 }
113 migration_values_.Clear();
114 }
115 }
116
117 content::NotificationRegistrar registrar_;
118 scoped_ptr<OwnershipStatusChecker> ownership_checker_;
119 SignedSettingsHelper::Callback* callback_;
120 PrefValueMap migration_values_;
121
122 DISALLOW_COPY_AND_ASSIGN(MigrationHelper);
123 };
124
125 bool IsControlledBooleanSetting(const std::string& pref_path) {
126 // TODO(nkostylev): Using std::find for 4 value array generates this warning
127 // in chroot stl_algo.h:231: error: array subscript is above array bounds.
128 // GCC 4.4.3
129 return (pref_path == kAccountsPrefAllowNewUser) ||
130 (pref_path == kAccountsPrefAllowGuest) ||
131 (pref_path == kAccountsPrefShowUserNamesOnSignIn) ||
132 (pref_path == kSignedDataRoamingEnabled) ||
133 (pref_path == kStatsReportingPref);
134 }
135
136 bool IsControlledStringSetting(const std::string& pref_path) {
137 return std::find(kStringSettings,
138 kStringSettings + arraysize(kStringSettings),
139 pref_path) !=
140 kStringSettings + arraysize(kStringSettings);
141 }
142
143 bool IsControlledListSetting(const std::string& pref_path) {
144 return std::find(kListSettings,
145 kListSettings + arraysize(kListSettings),
146 pref_path) !=
147 kListSettings + arraysize(kListSettings);
148 }
149
150 bool IsControlledSetting(const std::string& pref_path) {
151 return (IsControlledBooleanSetting(pref_path) ||
152 IsControlledStringSetting(pref_path) ||
153 IsControlledListSetting(pref_path));
154 }
155
156 void RegisterSetting(PrefService* local_state, const std::string& pref_path) {
157 local_state->RegisterBooleanPref((pref_path + kTrustedSuffix).c_str(),
158 false,
159 PrefService::UNSYNCABLE_PREF);
160 if (IsControlledBooleanSetting(pref_path)) {
161 if (pref_path == kSignedDataRoamingEnabled ||
162 pref_path == kStatsReportingPref)
163 local_state->RegisterBooleanPref(pref_path.c_str(),
164 false,
165 PrefService::UNSYNCABLE_PREF);
166 else
167 local_state->RegisterBooleanPref(pref_path.c_str(),
168 true,
169 PrefService::UNSYNCABLE_PREF);
170 } else if (IsControlledStringSetting(pref_path)) {
171 local_state->RegisterStringPref(pref_path.c_str(),
172 "",
173 PrefService::UNSYNCABLE_PREF);
174 } else {
175 DCHECK(IsControlledListSetting(pref_path));
176 local_state->RegisterListPref(pref_path.c_str(),
177 PrefService::UNSYNCABLE_PREF);
178 }
179 }
180
181 enum UseValue {
182 USE_VALUE_SUPPLIED,
183 USE_VALUE_DEFAULT
184 };
185
186 void UpdateCache(const std::string& name,
187 const base::Value* value,
188 UseValue use_value) {
189 PrefService* prefs = g_browser_process->local_state();
190 if (use_value == USE_VALUE_DEFAULT)
191 prefs->ClearPref(name.c_str());
192 else
193 prefs->Set(name.c_str(), *value);
194 prefs->ScheduleSavePersistentPrefs();
195 }
196
197 class UserCrosSettingsTrust : public SignedSettingsHelper::Callback {
198 public:
199 static UserCrosSettingsTrust* GetInstance() {
200 return Singleton<UserCrosSettingsTrust>::get();
201 }
202
203 // Working horse for UserCrosSettingsProvider::RequestTrusted* family.
204 bool RequestTrustedEntity(const std::string& name) {
205 OwnershipService::Status ownership_status =
206 ownership_service_->GetStatus(false);
207 if (ownership_status == OwnershipService::OWNERSHIP_NONE)
208 return true;
209 PrefService* prefs = g_browser_process->local_state();
210 if (prefs->IsManagedPreference(name.c_str()))
211 return true;
212 if (ownership_status == OwnershipService::OWNERSHIP_TAKEN) {
213 DCHECK(g_browser_process);
214 PrefService* prefs = g_browser_process->local_state();
215 DCHECK(prefs);
216 if (prefs->GetBoolean((name + kTrustedSuffix).c_str()))
217 return true;
218 }
219 return false;
220 }
221
222 bool RequestTrustedEntity(const std::string& name,
223 const base::Closure& callback) {
224 if (RequestTrustedEntity(name)) {
225 return true;
226 } else {
227 if (!callback.is_null())
228 callbacks_[name].push_back(callback);
229 return false;
230 }
231 }
232
233 void Reload() {
234 for (size_t i = 0; i < arraysize(kBooleanSettings); ++i)
235 StartFetchingSetting(kBooleanSettings[i]);
236 for (size_t i = 0; i < arraysize(kStringSettings); ++i)
237 StartFetchingSetting(kStringSettings[i]);
238 for (size_t i = 0; i < arraysize(kListSettings); ++i)
239 StartFetchingSetting(kListSettings[i]);
240 }
241
242 void Set(const std::string& path, const base::Value& in_value) {
243 PrefService* prefs = g_browser_process->local_state();
244 DCHECK(!prefs->IsManagedPreference(path.c_str()));
245
246 if (!UserManager::Get()->current_user_is_owner()) {
247 LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
248
249 // Revert UI change.
250 CrosSettings::Get()->FireObservers(path.c_str());
251 return;
252 }
253 if (IsControlledSetting(path)) {
254 if (IsControlledBooleanSetting(path)) {
255 bool bool_value = false;
256 if (in_value.GetAsBoolean(&bool_value)) {
257 OnBooleanPropertyChange(path, bool_value);
258 }
259 }
260 SignedSettingsHelper::Get()->StartStorePropertyOp(
261 path, in_value, this);
262 UpdateCache(path, &in_value, USE_VALUE_SUPPLIED);
263
264 LOG(ERROR) << "Set cros setting " << path;
265 } else {
266 LOG(WARNING) << "Try to set unhandled cros setting " << path;
267 }
268 }
269
270 private:
271 // upper bound for number of retries to fetch a signed setting.
272 static const int kNumRetriesLimit = 9;
273
274 UserCrosSettingsTrust()
275 : ownership_service_(OwnershipService::GetSharedInstance()),
276 retries_left_(kNumRetriesLimit) {
277 migration_helper_.set_callback(this);
278 // Start prefetching Boolean and String preferences.
279 Reload();
280 }
281
282 virtual ~UserCrosSettingsTrust() {
283 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
284 // Cancels all pending callbacks from us.
285 SignedSettingsHelper::Get()->CancelCallback(this);
286 }
287 }
288
289 // Called right before boolean property is changed.
290 void OnBooleanPropertyChange(const std::string& path, bool new_value) {
291 if (path == kSignedDataRoamingEnabled) {
292 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
293 if (cros->IsCellularAlwaysInRoaming()) {
294 // If operator requires roaming always enabled, ignore supplied value
295 // and set data roaming allowed in true always.
296 new_value = true;
297 }
298 cros->SetCellularDataRoamingAllowed(new_value);
299 } else if (path == kStatsReportingPref) {
300 // TODO(pastarmovj): Remove this once we don't need to regenerate the
301 // consent file for the GUID anymore.
302 OptionsUtil::ResolveMetricsReportingEnabled(new_value);
303 }
304 }
305
306 // Called right after signed value was checked.
307 void OnPropertyRetrieve(const std::string& path,
308 const base::Value* value,
309 UseValue use_value) {
310 if (path == kSignedDataRoamingEnabled) {
311 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
312 const NetworkDevice* cellular = cros->FindCellularDevice();
313 if (cellular) {
314 bool device_value = cellular->data_roaming_allowed();
315 if (!device_value && cros->IsCellularAlwaysInRoaming()) {
316 // If operator requires roaming always enabled, ignore supplied value
317 // and set data roaming allowed in true always.
318 cros->SetCellularDataRoamingAllowed(true);
319 } else {
320 bool new_value = false;
321 if (use_value == USE_VALUE_SUPPLIED)
322 value->GetAsBoolean(&new_value);
323 if (device_value != new_value)
324 cros->SetCellularDataRoamingAllowed(new_value);
325 }
326 }
327 } else if (path == kStatsReportingPref) {
328 bool stats_consent = false;
329 if (use_value == USE_VALUE_SUPPLIED)
330 value->GetAsBoolean(&stats_consent);
331 // TODO(pastarmovj): Remove this once migration is not needed anymore.
332 // If the value is not set we should try to migrate legacy consent file.
333 if (use_value == USE_VALUE_DEFAULT) {
334 // Loading consent file state causes us to do blocking IO on UI thread.
335 // Temporarily allow it until we fix http://crbug.com/62626
336 base::ThreadRestrictions::ScopedAllowIO allow_io;
337 stats_consent = GoogleUpdateSettings::GetCollectStatsConsent();
338 // Make sure the values will get eventually written to the policy file.
339 migration_helper_.AddMigrationValue(
340 path, base::Value::CreateBooleanValue(stats_consent));
341 migration_helper_.MigrateValues();
342 base::FundamentalValue base_value(stats_consent);
343 UpdateCache(path, &base_value, USE_VALUE_SUPPLIED);
344 LOG(WARNING) << "No metrics policy set will revert to checking "
345 << "consent file which is "
346 << (stats_consent ? "on." : "off.");
347 }
348 // TODO(pastarmovj): Remove this once we don't need to regenerate the
349 // consent file for the GUID anymore.
350 VLOG(1) << "Metrics policy is being set to : " << stats_consent
351 << "(reason : " << use_value << ")";
352 OptionsUtil::ResolveMetricsReportingEnabled(stats_consent);
353 }
354 }
355
356 void StartFetchingSetting(const std::string& name) {
357 DCHECK(g_browser_process);
358 PrefService* prefs = g_browser_process->local_state();
359 if (!prefs)
360 return;
361 // Do not trust before fetching complete.
362 prefs->ClearPref((name + kTrustedSuffix).c_str());
363 prefs->ScheduleSavePersistentPrefs();
364 SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
365 }
366
367 // Implementation of SignedSettingsHelper::Callback.
368 virtual void OnRetrievePropertyCompleted(SignedSettings::ReturnCode code,
369 const std::string& name,
370 const base::Value* value) {
371 if (!IsControlledSetting(name)) {
372 NOTREACHED();
373 return;
374 }
375
376 bool is_owned = ownership_service_->GetStatus(true) ==
377 OwnershipService::OWNERSHIP_TAKEN;
378 PrefService* prefs = g_browser_process->local_state();
379 switch (code) {
380 case SignedSettings::SUCCESS:
381 case SignedSettings::NOT_FOUND:
382 case SignedSettings::KEY_UNAVAILABLE: {
383 bool fallback_to_default = !is_owned
384 || (code == SignedSettings::NOT_FOUND);
385 DCHECK(fallback_to_default || code == SignedSettings::SUCCESS);
386 if (fallback_to_default)
387 VLOG(1) << "Going default for cros setting " << name;
388 else
389 VLOG(1) << "Retrieved cros setting " << name;
390 UpdateCache(
391 name, value,
392 fallback_to_default ? USE_VALUE_DEFAULT : USE_VALUE_SUPPLIED);
393 OnPropertyRetrieve(
394 name, value,
395 fallback_to_default ? USE_VALUE_DEFAULT : USE_VALUE_SUPPLIED);
396 break;
397 }
398 case SignedSettings::OPERATION_FAILED:
399 default: {
400 DCHECK(code == SignedSettings::OPERATION_FAILED);
401 DCHECK(is_owned);
402 LOG(ERROR) << "On owned device: failed to retrieve cros "
403 "setting, name=" << name;
404 if (retries_left_ > 0) {
405 retries_left_ -= 1;
406 StartFetchingSetting(name);
407 return;
408 }
409 LOG(ERROR) << "No retries left";
410 if (IsControlledBooleanSetting(name)) {
411 // For boolean settings we can just set safe (false) values
412 // and continue as trusted.
413 scoped_ptr<base::Value> false_value(
414 base::Value::CreateBooleanValue(false));
415 OnPropertyRetrieve(name, false_value.get(), USE_VALUE_SUPPLIED);
416 UpdateCache(name, false_value.get(), USE_VALUE_SUPPLIED);
417 } else {
418 prefs->ClearPref((name + kTrustedSuffix).c_str());
419 return;
420 }
421 break;
422 }
423 }
424 prefs->SetBoolean((name + kTrustedSuffix).c_str(), true);
425 {
426 std::vector<base::Closure>& callbacks_vector = callbacks_[name];
427 for (size_t i = 0; i < callbacks_vector.size(); ++i)
428 MessageLoop::current()->PostTask(FROM_HERE, callbacks_vector[i]);
429 callbacks_vector.clear();
430 }
431 if (code == SignedSettings::SUCCESS)
432 CrosSettings::Get()->FireObservers(name.c_str());
433 }
434
435 // Implementation of SignedSettingsHelper::Callback.
436 virtual void OnStorePropertyCompleted(SignedSettings::ReturnCode code,
437 const std::string& name,
438 const base::Value& value) {
439 VLOG(1) << "Store cros setting " << name << ", code=" << code;
440
441 // Reload the setting if store op fails.
442 if (code != SignedSettings::SUCCESS)
443 SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
444 }
445
446 // Implementation of SignedSettingsHelper::Callback.
447 virtual void OnWhitelistCompleted(SignedSettings::ReturnCode code,
448 const std::string& email) {
449 VLOG(1) << "Add " << email << " to whitelist, code=" << code;
450
451 // Reload the whitelist on settings op failure.
452 if (code != SignedSettings::SUCCESS)
453 CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
454 }
455
456 // Implementation of SignedSettingsHelper::Callback.
457 virtual void OnUnwhitelistCompleted(SignedSettings::ReturnCode code,
458 const std::string& email) {
459 VLOG(1) << "Remove " << email << " from whitelist, code=" << code;
460
461 // Reload the whitelist on settings op failure.
462 if (code != SignedSettings::SUCCESS)
463 CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
464 }
465
466 // Pending callbacks that need to be invoked after settings verification.
467 base::hash_map<std::string, std::vector<base::Closure> > callbacks_;
468
469 OwnershipService* ownership_service_;
470 MigrationHelper migration_helper_;
471
472 // In order to guard against occasional failure to fetch a property
473 // we allow for some number of retries.
474 int retries_left_;
475
476 friend class SignedSettingsHelper;
477 friend struct DefaultSingletonTraits<UserCrosSettingsTrust>;
478
479 DISALLOW_COPY_AND_ASSIGN(UserCrosSettingsTrust);
480 };
481
482 } // namespace
483
484 } // namespace chromeos
485
486 namespace chromeos {
487
488 UserCrosSettingsProvider::UserCrosSettingsProvider() {
489 // Trigger prefetching of settings.
490 UserCrosSettingsTrust::GetInstance();
491 }
492
493 // static
494 void UserCrosSettingsProvider::RegisterPrefs(PrefService* local_state) {
495 for (size_t i = 0; i < arraysize(kBooleanSettings); ++i)
496 RegisterSetting(local_state, kBooleanSettings[i]);
497 for (size_t i = 0; i < arraysize(kStringSettings); ++i)
498 RegisterSetting(local_state, kStringSettings[i]);
499 for (size_t i = 0; i < arraysize(kListSettings); ++i)
500 RegisterSetting(local_state, kListSettings[i]);
501 }
502
503 void UserCrosSettingsProvider::Reload() {
504 UserCrosSettingsTrust::GetInstance()->Reload();
505 }
506
507 void UserCrosSettingsProvider::DoSet(const std::string& path,
508 const base::Value& in_value) {
509 UserCrosSettingsTrust::GetInstance()->Set(path, in_value);
510 }
511
512 const base::Value* UserCrosSettingsProvider::Get(
513 const std::string& path) const {
514 if (HandlesSetting(path)) {
515 const PrefService* prefs = g_browser_process->local_state();
516 const PrefService::Preference* pref = prefs->FindPreference(path.c_str());
517 return pref->GetValue();
518 }
519 return NULL;
520 }
521
522 bool UserCrosSettingsProvider::GetTrusted(const std::string& path,
523 const base::Closure& callback) const {
524 return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
525 path, callback);
526 }
527
528 bool UserCrosSettingsProvider::HandlesSetting(const std::string& path) const {
529 return ::StartsWithASCII(path, "cros.accounts.", true) ||
530 ::StartsWithASCII(path, "cros.signed.", true) ||
531 ::StartsWithASCII(path, "cros.metrics.", true) ||
532 path == kDeviceOwner ||
533 path == kReleaseChannel;
534 }
535
536 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698