• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "components/sync_driver/sync_prefs.h"
6 
7 #include "base/logging.h"
8 #include "base/prefs/pref_member.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/values.h"
12 #include "build/build_config.h"
13 #include "components/pref_registry/pref_registry_syncable.h"
14 #include "components/sync_driver/pref_names.h"
15 
16 namespace sync_driver {
17 
~SyncPrefObserver()18 SyncPrefObserver::~SyncPrefObserver() {}
19 
SyncPrefs(PrefService * pref_service)20 SyncPrefs::SyncPrefs(PrefService* pref_service) : pref_service_(pref_service) {
21   DCHECK(pref_service);
22   RegisterPrefGroups();
23   // Watch the preference that indicates sync is managed so we can take
24   // appropriate action.
25   pref_sync_managed_.Init(
26       prefs::kSyncManaged,
27       pref_service_,
28       base::Bind(&SyncPrefs::OnSyncManagedPrefChanged, base::Unretained(this)));
29 }
30 
SyncPrefs()31 SyncPrefs::SyncPrefs() : pref_service_(NULL) {}
32 
~SyncPrefs()33 SyncPrefs::~SyncPrefs() { DCHECK(CalledOnValidThread()); }
34 
35 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)36 void SyncPrefs::RegisterProfilePrefs(
37     user_prefs::PrefRegistrySyncable* registry) {
38   registry->RegisterBooleanPref(
39       prefs::kSyncHasSetupCompleted,
40       false,
41       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
42   registry->RegisterBooleanPref(
43       prefs::kSyncSuppressStart,
44       false,
45       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
46   registry->RegisterInt64Pref(
47       prefs::kSyncLastSyncedTime,
48       0,
49       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
50   registry->RegisterInt64Pref(
51       prefs::kSyncFirstSyncTime,
52       0,
53       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
54 
55   // All datatypes are on by default, but this gets set explicitly
56   // when you configure sync (when turning it on), in
57   // ProfileSyncService::OnUserChoseDatatypes.
58   registry->RegisterBooleanPref(
59       prefs::kSyncKeepEverythingSynced,
60       true,
61       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
62 
63   syncer::ModelTypeSet user_types = syncer::UserTypes();
64 
65   // Include proxy types as well, as they can be individually selected,
66   // although they don't have sync representations.
67   user_types.PutAll(syncer::ProxyTypes());
68 
69   // Treat bookmarks and device info specially.
70   RegisterDataTypePreferredPref(registry, syncer::BOOKMARKS, true);
71   RegisterDataTypePreferredPref(registry, syncer::DEVICE_INFO, true);
72   user_types.Remove(syncer::BOOKMARKS);
73   user_types.Remove(syncer::DEVICE_INFO);
74 
75   // These two prefs are set from sync experiment to enable enhanced bookmarks.
76   registry->RegisterIntegerPref(
77       prefs::kEnhancedBookmarksExperimentEnabled,
78       0,
79       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
80 
81   registry->RegisterStringPref(
82       prefs::kEnhancedBookmarksExtensionId,
83       std::string(),
84       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
85 
86   // All types are set to off by default, which forces a configuration to
87   // explicitly enable them. GetPreferredTypes() will ensure that any new
88   // implicit types are enabled when their pref group is, or via
89   // KeepEverythingSynced.
90   for (syncer::ModelTypeSet::Iterator it = user_types.First(); it.Good();
91        it.Inc()) {
92     RegisterDataTypePreferredPref(registry, it.Get(), false);
93   }
94 
95   registry->RegisterBooleanPref(
96       prefs::kSyncManaged,
97       false,
98       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
99   registry->RegisterStringPref(
100       prefs::kSyncEncryptionBootstrapToken,
101       std::string(),
102       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
103   registry->RegisterStringPref(
104       prefs::kSyncKeystoreEncryptionBootstrapToken,
105       std::string(),
106       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
107 #if defined(OS_CHROMEOS)
108   registry->RegisterStringPref(
109       prefs::kSyncSpareBootstrapToken,
110       "",
111       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
112 #endif
113 
114   registry->RegisterBooleanPref(
115       prefs::kSyncHasAuthError,
116       false,
117       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
118 
119   registry->RegisterStringPref(
120       prefs::kSyncSessionsGUID,
121       std::string(),
122       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
123 
124   // We will start prompting people about new data types after the launch of
125   // SESSIONS - all previously launched data types are treated as if they are
126   // already acknowledged.
127   syncer::ModelTypeSet model_set;
128   model_set.Put(syncer::BOOKMARKS);
129   model_set.Put(syncer::PREFERENCES);
130   model_set.Put(syncer::PASSWORDS);
131   model_set.Put(syncer::AUTOFILL_PROFILE);
132   model_set.Put(syncer::AUTOFILL);
133   model_set.Put(syncer::THEMES);
134   model_set.Put(syncer::EXTENSIONS);
135   model_set.Put(syncer::NIGORI);
136   model_set.Put(syncer::SEARCH_ENGINES);
137   model_set.Put(syncer::APPS);
138   model_set.Put(syncer::APP_LIST);
139   model_set.Put(syncer::TYPED_URLS);
140   model_set.Put(syncer::SESSIONS);
141   model_set.Put(syncer::ARTICLES);
142   registry->RegisterListPref(prefs::kSyncAcknowledgedSyncTypes,
143                              syncer::ModelTypeSetToValue(model_set),
144                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
145 
146   registry->RegisterIntegerPref(
147       prefs::kSyncRemainingRollbackTries, 0,
148       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
149 }
150 
AddSyncPrefObserver(SyncPrefObserver * sync_pref_observer)151 void SyncPrefs::AddSyncPrefObserver(SyncPrefObserver* sync_pref_observer) {
152   DCHECK(CalledOnValidThread());
153   sync_pref_observers_.AddObserver(sync_pref_observer);
154 }
155 
RemoveSyncPrefObserver(SyncPrefObserver * sync_pref_observer)156 void SyncPrefs::RemoveSyncPrefObserver(SyncPrefObserver* sync_pref_observer) {
157   DCHECK(CalledOnValidThread());
158   sync_pref_observers_.RemoveObserver(sync_pref_observer);
159 }
160 
ClearPreferences()161 void SyncPrefs::ClearPreferences() {
162   DCHECK(CalledOnValidThread());
163   pref_service_->ClearPref(prefs::kSyncLastSyncedTime);
164   pref_service_->ClearPref(prefs::kSyncHasSetupCompleted);
165   pref_service_->ClearPref(prefs::kSyncEncryptionBootstrapToken);
166   pref_service_->ClearPref(prefs::kSyncKeystoreEncryptionBootstrapToken);
167 
168   // TODO(nick): The current behavior does not clear
169   // e.g. prefs::kSyncBookmarks.  Is that really what we want?
170 }
171 
HasSyncSetupCompleted() const172 bool SyncPrefs::HasSyncSetupCompleted() const {
173   DCHECK(CalledOnValidThread());
174   return pref_service_->GetBoolean(prefs::kSyncHasSetupCompleted);
175 }
176 
SetSyncSetupCompleted()177 void SyncPrefs::SetSyncSetupCompleted() {
178   DCHECK(CalledOnValidThread());
179   pref_service_->SetBoolean(prefs::kSyncHasSetupCompleted, true);
180   SetStartSuppressed(false);
181 }
182 
SyncHasAuthError() const183 bool SyncPrefs::SyncHasAuthError() const {
184   DCHECK(CalledOnValidThread());
185   return pref_service_->GetBoolean(prefs::kSyncHasAuthError);
186 }
187 
SetSyncAuthError(bool error)188 void SyncPrefs::SetSyncAuthError(bool error) {
189   DCHECK(CalledOnValidThread());
190   pref_service_->SetBoolean(prefs::kSyncHasAuthError, error);
191 }
192 
IsStartSuppressed() const193 bool SyncPrefs::IsStartSuppressed() const {
194   DCHECK(CalledOnValidThread());
195   return pref_service_->GetBoolean(prefs::kSyncSuppressStart);
196 }
197 
SetStartSuppressed(bool is_suppressed)198 void SyncPrefs::SetStartSuppressed(bool is_suppressed) {
199   DCHECK(CalledOnValidThread());
200   pref_service_->SetBoolean(prefs::kSyncSuppressStart, is_suppressed);
201 }
202 
GetLastSyncedTime() const203 base::Time SyncPrefs::GetLastSyncedTime() const {
204   DCHECK(CalledOnValidThread());
205   return base::Time::FromInternalValue(
206       pref_service_->GetInt64(prefs::kSyncLastSyncedTime));
207 }
208 
SetLastSyncedTime(base::Time time)209 void SyncPrefs::SetLastSyncedTime(base::Time time) {
210   DCHECK(CalledOnValidThread());
211   pref_service_->SetInt64(prefs::kSyncLastSyncedTime, time.ToInternalValue());
212 }
213 
HasKeepEverythingSynced() const214 bool SyncPrefs::HasKeepEverythingSynced() const {
215   DCHECK(CalledOnValidThread());
216   return pref_service_->GetBoolean(prefs::kSyncKeepEverythingSynced);
217 }
218 
SetKeepEverythingSynced(bool keep_everything_synced)219 void SyncPrefs::SetKeepEverythingSynced(bool keep_everything_synced) {
220   DCHECK(CalledOnValidThread());
221   pref_service_->SetBoolean(prefs::kSyncKeepEverythingSynced,
222                             keep_everything_synced);
223 }
224 
GetPreferredDataTypes(syncer::ModelTypeSet registered_types) const225 syncer::ModelTypeSet SyncPrefs::GetPreferredDataTypes(
226     syncer::ModelTypeSet registered_types) const {
227   DCHECK(CalledOnValidThread());
228 
229   if (pref_service_->GetBoolean(prefs::kSyncKeepEverythingSynced)) {
230     return registered_types;
231   }
232 
233   syncer::ModelTypeSet preferred_types;
234   for (syncer::ModelTypeSet::Iterator it = registered_types.First(); it.Good();
235        it.Inc()) {
236     if (GetDataTypePreferred(it.Get())) {
237       preferred_types.Put(it.Get());
238     }
239   }
240   return ResolvePrefGroups(registered_types, preferred_types);
241 }
242 
SetPreferredDataTypes(syncer::ModelTypeSet registered_types,syncer::ModelTypeSet preferred_types)243 void SyncPrefs::SetPreferredDataTypes(syncer::ModelTypeSet registered_types,
244                                       syncer::ModelTypeSet preferred_types) {
245   DCHECK(CalledOnValidThread());
246   DCHECK(registered_types.HasAll(preferred_types));
247   preferred_types = ResolvePrefGroups(registered_types, preferred_types);
248   for (syncer::ModelTypeSet::Iterator i = registered_types.First(); i.Good();
249        i.Inc()) {
250     SetDataTypePreferred(i.Get(), preferred_types.Has(i.Get()));
251   }
252 }
253 
IsManaged() const254 bool SyncPrefs::IsManaged() const {
255   DCHECK(CalledOnValidThread());
256   return pref_service_->GetBoolean(prefs::kSyncManaged);
257 }
258 
GetEncryptionBootstrapToken() const259 std::string SyncPrefs::GetEncryptionBootstrapToken() const {
260   DCHECK(CalledOnValidThread());
261   return pref_service_->GetString(prefs::kSyncEncryptionBootstrapToken);
262 }
263 
SetEncryptionBootstrapToken(const std::string & token)264 void SyncPrefs::SetEncryptionBootstrapToken(const std::string& token) {
265   DCHECK(CalledOnValidThread());
266   pref_service_->SetString(prefs::kSyncEncryptionBootstrapToken, token);
267 }
268 
GetKeystoreEncryptionBootstrapToken() const269 std::string SyncPrefs::GetKeystoreEncryptionBootstrapToken() const {
270   DCHECK(CalledOnValidThread());
271   return pref_service_->GetString(prefs::kSyncKeystoreEncryptionBootstrapToken);
272 }
273 
SetKeystoreEncryptionBootstrapToken(const std::string & token)274 void SyncPrefs::SetKeystoreEncryptionBootstrapToken(const std::string& token) {
275   DCHECK(CalledOnValidThread());
276   pref_service_->SetString(prefs::kSyncKeystoreEncryptionBootstrapToken, token);
277 }
278 
GetSyncSessionsGUID() const279 std::string SyncPrefs::GetSyncSessionsGUID() const {
280   DCHECK(CalledOnValidThread());
281   return pref_service_->GetString(prefs::kSyncSessionsGUID);
282 }
283 
SetSyncSessionsGUID(const std::string & guid)284 void SyncPrefs::SetSyncSessionsGUID(const std::string& guid) {
285   DCHECK(CalledOnValidThread());
286   pref_service_->SetString(prefs::kSyncSessionsGUID, guid);
287 }
288 
289 // static
GetPrefNameForDataType(syncer::ModelType data_type)290 const char* SyncPrefs::GetPrefNameForDataType(syncer::ModelType data_type) {
291   switch (data_type) {
292     case syncer::BOOKMARKS:
293       return prefs::kSyncBookmarks;
294     case syncer::PASSWORDS:
295       return prefs::kSyncPasswords;
296     case syncer::PREFERENCES:
297       return prefs::kSyncPreferences;
298     case syncer::AUTOFILL:
299       return prefs::kSyncAutofill;
300     case syncer::AUTOFILL_PROFILE:
301       return prefs::kSyncAutofillProfile;
302     case syncer::THEMES:
303       return prefs::kSyncThemes;
304     case syncer::TYPED_URLS:
305       return prefs::kSyncTypedUrls;
306     case syncer::EXTENSION_SETTINGS:
307       return prefs::kSyncExtensionSettings;
308     case syncer::EXTENSIONS:
309       return prefs::kSyncExtensions;
310     case syncer::APP_LIST:
311       return prefs::kSyncAppList;
312     case syncer::APP_SETTINGS:
313       return prefs::kSyncAppSettings;
314     case syncer::APPS:
315       return prefs::kSyncApps;
316     case syncer::SEARCH_ENGINES:
317       return prefs::kSyncSearchEngines;
318     case syncer::SESSIONS:
319       return prefs::kSyncSessions;
320     case syncer::APP_NOTIFICATIONS:
321       return prefs::kSyncAppNotifications;
322     case syncer::HISTORY_DELETE_DIRECTIVES:
323       return prefs::kSyncHistoryDeleteDirectives;
324     case syncer::SYNCED_NOTIFICATIONS:
325       return prefs::kSyncSyncedNotifications;
326     case syncer::SYNCED_NOTIFICATION_APP_INFO:
327       return prefs::kSyncSyncedNotificationAppInfo;
328     case syncer::DICTIONARY:
329       return prefs::kSyncDictionary;
330     case syncer::FAVICON_IMAGES:
331       return prefs::kSyncFaviconImages;
332     case syncer::FAVICON_TRACKING:
333       return prefs::kSyncFaviconTracking;
334     case syncer::SUPERVISED_USER_SETTINGS:
335       return prefs::kSyncSupervisedUserSettings;
336     case syncer::PROXY_TABS:
337       return prefs::kSyncTabs;
338     case syncer::PRIORITY_PREFERENCES:
339       return prefs::kSyncPriorityPreferences;
340     case syncer::SUPERVISED_USERS:
341       return prefs::kSyncSupervisedUsers;
342     case syncer::ARTICLES:
343       return prefs::kSyncArticles;
344     case syncer::SUPERVISED_USER_SHARED_SETTINGS:
345       return prefs::kSyncSupervisedUserSharedSettings;
346     case syncer::DEVICE_INFO:
347       return prefs::kSyncDeviceInfo;
348     default:
349       break;
350   }
351   NOTREACHED() << "Type is " << data_type;
352   return NULL;
353 }
354 
355 #if defined(OS_CHROMEOS)
GetSpareBootstrapToken() const356 std::string SyncPrefs::GetSpareBootstrapToken() const {
357   DCHECK(CalledOnValidThread());
358   return pref_service_->GetString(prefs::kSyncSpareBootstrapToken);
359 }
360 
SetSpareBootstrapToken(const std::string & token)361 void SyncPrefs::SetSpareBootstrapToken(const std::string& token) {
362   DCHECK(CalledOnValidThread());
363   pref_service_->SetString(prefs::kSyncSpareBootstrapToken, token);
364 }
365 #endif
366 
AcknowledgeSyncedTypes(syncer::ModelTypeSet types)367 void SyncPrefs::AcknowledgeSyncedTypes(syncer::ModelTypeSet types) {
368   DCHECK(CalledOnValidThread());
369   // Add the types to the current set of acknowledged
370   // types, and then store the resulting set in prefs.
371   const syncer::ModelTypeSet acknowledged_types =
372       Union(types,
373             syncer::ModelTypeSetFromValue(
374                 *pref_service_->GetList(prefs::kSyncAcknowledgedSyncTypes)));
375 
376   scoped_ptr<base::ListValue> value(
377       syncer::ModelTypeSetToValue(acknowledged_types));
378   pref_service_->Set(prefs::kSyncAcknowledgedSyncTypes, *value);
379 }
380 
GetRemainingRollbackTries() const381 int SyncPrefs::GetRemainingRollbackTries() const {
382   return pref_service_->GetInteger(prefs::kSyncRemainingRollbackTries);
383 }
384 
SetRemainingRollbackTries(int times)385 void SyncPrefs::SetRemainingRollbackTries(int times) {
386   pref_service_->SetInteger(prefs::kSyncRemainingRollbackTries, times);
387 }
388 
OnSyncManagedPrefChanged()389 void SyncPrefs::OnSyncManagedPrefChanged() {
390   DCHECK(CalledOnValidThread());
391   FOR_EACH_OBSERVER(SyncPrefObserver,
392                     sync_pref_observers_,
393                     OnSyncManagedPrefChange(*pref_sync_managed_));
394 }
395 
SetManagedForTest(bool is_managed)396 void SyncPrefs::SetManagedForTest(bool is_managed) {
397   DCHECK(CalledOnValidThread());
398   pref_service_->SetBoolean(prefs::kSyncManaged, is_managed);
399 }
400 
GetAcknowledgeSyncedTypesForTest() const401 syncer::ModelTypeSet SyncPrefs::GetAcknowledgeSyncedTypesForTest() const {
402   DCHECK(CalledOnValidThread());
403   return syncer::ModelTypeSetFromValue(
404       *pref_service_->GetList(prefs::kSyncAcknowledgedSyncTypes));
405 }
406 
RegisterPrefGroups()407 void SyncPrefs::RegisterPrefGroups() {
408   pref_groups_[syncer::APPS].Put(syncer::APP_NOTIFICATIONS);
409   pref_groups_[syncer::APPS].Put(syncer::APP_SETTINGS);
410   pref_groups_[syncer::APPS].Put(syncer::APP_LIST);
411 
412   pref_groups_[syncer::AUTOFILL].Put(syncer::AUTOFILL_PROFILE);
413 
414   pref_groups_[syncer::EXTENSIONS].Put(syncer::EXTENSION_SETTINGS);
415 
416   pref_groups_[syncer::PREFERENCES].Put(syncer::DICTIONARY);
417   pref_groups_[syncer::PREFERENCES].Put(syncer::PRIORITY_PREFERENCES);
418   pref_groups_[syncer::PREFERENCES].Put(syncer::SEARCH_ENGINES);
419 
420   pref_groups_[syncer::TYPED_URLS].Put(syncer::HISTORY_DELETE_DIRECTIVES);
421   pref_groups_[syncer::TYPED_URLS].Put(syncer::SESSIONS);
422   pref_groups_[syncer::TYPED_URLS].Put(syncer::FAVICON_IMAGES);
423   pref_groups_[syncer::TYPED_URLS].Put(syncer::FAVICON_TRACKING);
424 
425   pref_groups_[syncer::PROXY_TABS].Put(syncer::SESSIONS);
426   pref_groups_[syncer::PROXY_TABS].Put(syncer::FAVICON_IMAGES);
427   pref_groups_[syncer::PROXY_TABS].Put(syncer::FAVICON_TRACKING);
428 
429   // TODO(zea): put favicons in the bookmarks group as well once it handles
430   // those favicons.
431 }
432 
433 // static
RegisterDataTypePreferredPref(user_prefs::PrefRegistrySyncable * registry,syncer::ModelType type,bool is_preferred)434 void SyncPrefs::RegisterDataTypePreferredPref(
435     user_prefs::PrefRegistrySyncable* registry,
436     syncer::ModelType type,
437     bool is_preferred) {
438   const char* pref_name = GetPrefNameForDataType(type);
439   if (!pref_name) {
440     NOTREACHED();
441     return;
442   }
443   registry->RegisterBooleanPref(
444       pref_name,
445       is_preferred,
446       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
447 }
448 
GetDataTypePreferred(syncer::ModelType type) const449 bool SyncPrefs::GetDataTypePreferred(syncer::ModelType type) const {
450   DCHECK(CalledOnValidThread());
451   const char* pref_name = GetPrefNameForDataType(type);
452   if (!pref_name) {
453     NOTREACHED();
454     return false;
455   }
456 
457   // Device info is always enabled.
458   if (pref_name == prefs::kSyncDeviceInfo)
459     return true;
460 
461   if (type == syncer::PROXY_TABS &&
462       pref_service_->GetUserPrefValue(pref_name) == NULL &&
463       pref_service_->IsUserModifiablePreference(pref_name)) {
464     // If there is no tab sync preference yet (i.e. newly enabled type),
465     // default to the session sync preference value.
466     pref_name = GetPrefNameForDataType(syncer::SESSIONS);
467   }
468 
469   return pref_service_->GetBoolean(pref_name);
470 }
471 
SetDataTypePreferred(syncer::ModelType type,bool is_preferred)472 void SyncPrefs::SetDataTypePreferred(syncer::ModelType type,
473                                      bool is_preferred) {
474   DCHECK(CalledOnValidThread());
475   const char* pref_name = GetPrefNameForDataType(type);
476   if (!pref_name) {
477     NOTREACHED();
478     return;
479   }
480 
481   // Device info is always preferred.
482   if (type == syncer::DEVICE_INFO)
483     return;
484 
485   pref_service_->SetBoolean(pref_name, is_preferred);
486 }
487 
ResolvePrefGroups(syncer::ModelTypeSet registered_types,syncer::ModelTypeSet types) const488 syncer::ModelTypeSet SyncPrefs::ResolvePrefGroups(
489     syncer::ModelTypeSet registered_types,
490     syncer::ModelTypeSet types) const {
491   DCHECK(registered_types.HasAll(types));
492   syncer::ModelTypeSet types_with_groups = types;
493   for (PrefGroupsMap::const_iterator i = pref_groups_.begin();
494        i != pref_groups_.end();
495        ++i) {
496     if (types.Has(i->first))
497       types_with_groups.PutAll(i->second);
498   }
499   types_with_groups.RetainAll(registered_types);
500   return types_with_groups;
501 }
502 
GetFirstSyncTime() const503 base::Time SyncPrefs::GetFirstSyncTime() const {
504   return base::Time::FromInternalValue(
505       pref_service_->GetInt64(prefs::kSyncFirstSyncTime));
506 }
507 
SetFirstSyncTime(base::Time time)508 void SyncPrefs::SetFirstSyncTime(base::Time time) {
509   pref_service_->SetInt64(prefs::kSyncFirstSyncTime, time.ToInternalValue());
510 }
511 
ClearFirstSyncTime()512 void SyncPrefs::ClearFirstSyncTime() {
513   pref_service_->ClearPref(prefs::kSyncFirstSyncTime);
514 }
515 
516 }  // namespace sync_driver
517