Upload upstream chromium 73.0.3683.0
[platform/framework/web/chromium-efl.git] / components / sync_preferences / unknown_user_pref_accessor.cc
1 // Copyright 2018 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_preferences/unknown_user_pref_accessor.h"
6
7 #include <iterator>
8 #include <memory>
9
10 #include "base/json/json_string_value_serializer.h"
11 #include "base/logging.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/values.h"
15 #include "components/prefs/persistent_pref_store.h"
16 #include "components/prefs/pref_service.h"
17 #include "components/sync_preferences/pref_service_syncable.h"
18
19 namespace sync_preferences {
20
21 UnknownUserPrefAccessor::UnknownUserPrefAccessor(
22     PrefService* pref_service,
23     user_prefs::PrefRegistrySyncable* pref_registry,
24     PersistentPrefStore* user_prefs)
25     : pref_service_(pref_service),
26       pref_registry_(pref_registry),
27       user_prefs_(user_prefs) {}
28
29 UnknownUserPrefAccessor::~UnknownUserPrefAccessor() {}
30
31 UnknownUserPrefAccessor::PreferenceState
32 UnknownUserPrefAccessor::GetPreferenceState(
33     syncer::ModelType type,
34     const std::string& pref_name) const {
35   PreferenceState result;
36   result.registration_state = GetRegistrationState(type, pref_name);
37   switch (result.registration_state) {
38     case RegistrationState::kUnknown:
39     case RegistrationState::kUnknownWhitelisted:
40       if (!user_prefs_->GetValue(pref_name, &result.persisted_value)) {
41         result.persisted_value = nullptr;
42       }
43       break;
44     case RegistrationState::kSyncable:
45     case RegistrationState::kNotSyncable:
46       result.persisted_value = pref_service_->GetUserPrefValue(pref_name);
47       break;
48   }
49   return result;
50 }
51
52 void UnknownUserPrefAccessor::ClearPref(
53     const std::string& pref_name,
54     const PreferenceState& local_pref_state) {
55   switch (local_pref_state.registration_state) {
56     case RegistrationState::kUnknown:
57       NOTREACHED() << "Sync attempted to update an unknown pref which is not "
58                       "whitelisted: "
59                    << pref_name;
60       break;
61     case RegistrationState::kUnknownWhitelisted:
62       user_prefs_->RemoveValue(pref_name,
63                                WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
64       break;
65     case RegistrationState::kSyncable:
66       pref_service_->ClearPref(pref_name);
67       break;
68     case RegistrationState::kNotSyncable:
69       // As this can happen if different clients disagree about which
70       // preferences should be synced, we only log a warning.
71       DLOG(WARNING)
72           << "Sync attempted to update a pref which is not registered as "
73              "syncable. Ignoring the remote change for pref: "
74           << pref_name;
75       break;
76   }
77 }
78
79 int UnknownUserPrefAccessor::GetNumberOfSyncingUnknownPrefs() const {
80   return synced_unknown_prefs_.size();
81 }
82
83 namespace {
84
85 bool VerifyTypesBeforeSet(const std::string& pref_name,
86                           const base::Value* local_value,
87                           const base::Value& new_value) {
88   if (local_value == nullptr || local_value->type() == new_value.type()) {
89     return true;
90   }
91   UMA_HISTOGRAM_BOOLEAN("Sync.Preferences.RemotePrefTypeMismatch", true);
92   DLOG(WARNING) << "Unexpected type mis-match for pref. "
93                 << "Synced value for " << pref_name << " is of type "
94                 << new_value.type() << " which doesn't match the locally "
95                 << "present pref type: " << local_value->type();
96   return false;
97 }
98
99 }  // namespace
100
101 void UnknownUserPrefAccessor::SetPref(const std::string& pref_name,
102                                       const PreferenceState& local_pref_state,
103                                       const base::Value& value) {
104   // On type mis-match, we trust the local preference DB and ignore the remote
105   // change.
106   switch (local_pref_state.registration_state) {
107     case RegistrationState::kUnknown:
108       NOTREACHED() << "Sync attempted to update a unknown pref which is not "
109                       "whitelisted: "
110                    << pref_name;
111       break;
112     case RegistrationState::kUnknownWhitelisted:
113       if (VerifyTypesBeforeSet(pref_name, local_pref_state.persisted_value,
114                                value)) {
115         user_prefs_->SetValue(pref_name, value.CreateDeepCopy(),
116                               WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
117       }
118       synced_unknown_prefs_.insert(pref_name);
119       break;
120     case RegistrationState::kSyncable:
121       if (VerifyTypesBeforeSet(pref_name, local_pref_state.persisted_value,
122                                value)) {
123         pref_service_->Set(pref_name, value);
124       }
125       break;
126     case RegistrationState::kNotSyncable:
127       // As this can happen if different clients disagree about which
128       // preferences should be synced, we only log a warning.
129       DLOG(WARNING)
130           << "Sync attempted to update a pref which is not registered as "
131              "syncable. Ignoring the remote change for pref: "
132           << pref_name;
133       break;
134   }
135 }
136
137 void UnknownUserPrefAccessor::EnforceRegisteredTypeInStore(
138     const std::string& pref_name) {
139   const base::Value* persisted_value = nullptr;
140   if (user_prefs_->GetValue(pref_name, &persisted_value)) {
141     // Get the registered type (typically from the default value).
142     const PrefService::Preference* pref =
143         pref_service_->FindPreference(pref_name);
144     DCHECK(pref);
145     if (pref->GetType() != persisted_value->type()) {
146       // We see conflicting type information and there's a chance the local
147       // type-conflicting data came in via sync. Remove it.
148       // TODO(tschumann): The value should get removed silently. Add a method
149       // RemoveValueSilently() to WriteablePrefStore. Note, that as of today
150       // that removal will only notify other pref stores but not sync -- that's
151       // done on a higher level.
152       user_prefs_->RemoveValue(pref_name,
153                                WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
154       UMA_HISTOGRAM_BOOLEAN("Sync.Preferences.ClearedLocalPrefOnTypeMismatch",
155                             true);
156     }
157   }
158   synced_unknown_prefs_.erase(pref_name);
159 }
160
161 UnknownUserPrefAccessor::RegistrationState
162 UnknownUserPrefAccessor::GetRegistrationState(
163     syncer::ModelType type,
164     const std::string& pref_name) const {
165   uint32_t type_flag = 0;
166   switch (type) {
167     case syncer::PRIORITY_PREFERENCES:
168       type_flag = user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF;
169       break;
170     case syncer::PREFERENCES:
171       type_flag = user_prefs::PrefRegistrySyncable::SYNCABLE_PREF;
172       break;
173     default:
174       NOTREACHED() << "unexpected model type for preferences: " << type;
175   }
176   if (pref_registry_->defaults()->GetValue(pref_name, nullptr)) {
177     uint32_t flags = pref_registry_->GetRegistrationFlags(pref_name);
178     if (flags & type_flag) {
179       return RegistrationState::kSyncable;
180     }
181     // Imagine the case where a preference has been synced as SYNCABLE_PREF
182     // first and then got changed to SYNCABLE_PRIORITY_PREF:
183     // In that situation, it could be argued for both, the preferences to be
184     // considered unknown or not synced. However, as we plan to eventually also
185     // sync unknown preferences, we cannot label them as unknown and treat them
186     // as not synced instead. (The underlying problem is that priority
187     // preferences are a concept only known to sync. The persistent stores don't
188     // distinguish between those two).
189     return RegistrationState::kNotSyncable;
190   }
191   if (pref_registry_->IsWhitelistedLateRegistrationPref(pref_name)) {
192     return RegistrationState::kUnknownWhitelisted;
193   }
194   return RegistrationState::kUnknown;
195 }
196
197 }  // namespace sync_preferences