pref_model_associator.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prefs/pref_model_associator.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/auto_reset.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_string_value_serializer.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/prefs/pref_service_syncable.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/api/sync_change.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/api/sync_error_factory.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/preference_specifics.pb.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/sync.pb.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncer::PREFERENCES;
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using syncer::PRIORITY_PREFERENCES;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const sync_pb::PreferenceSpecifics& GetSpecifics(const syncer::SyncData& pref) {
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(pref.GetDataType() == syncer::PREFERENCES ||
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         pref.GetDataType() == syncer::PRIORITY_PREFERENCES);
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (pref.GetDataType() == syncer::PRIORITY_PREFERENCES) {
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return pref.GetSpecifics().priority_preference().preference();
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return pref.GetSpecifics().preference();
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)sync_pb::PreferenceSpecifics* GetMutableSpecifics(
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const syncer::ModelType type,
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    sync_pb::EntitySpecifics* specifics) {
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (type == syncer::PRIORITY_PREFERENCES) {
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(!specifics->has_preference());
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return specifics->mutable_priority_preference()->mutable_preference();
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(!specifics->has_priority_preference());
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return specifics->mutable_preference();
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)PrefModelAssociator::PrefModelAssociator(syncer::ModelType type)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : models_associated_(false),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      processing_syncer_changes_(false),
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pref_service_(NULL),
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      type_(type) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(type_ == PREFERENCES || type_ == PRIORITY_PREFERENCES);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PrefModelAssociator::~PrefModelAssociator() {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_service_ = NULL;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrefModelAssociator::InitPrefAndAssociate(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncer::SyncData& sync_pref,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& pref_name,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncChangeList* sync_changes) {
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Value* user_pref_value = pref_service_->GetUserPrefValue(
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pref_name.c_str());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Associating preference " << pref_name;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sync_pref.IsValid()) {
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const sync_pb::PreferenceSpecifics& preference = GetSpecifics(sync_pref);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(pref_name, preference.name());
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::JSONReader reader;
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<Value> sync_value(reader.ReadToValue(preference.value()));
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!sync_value.get()) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to deserialize preference value: "
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << reader.GetErrorMessage();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (user_pref_value) {
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // We have both server and local values. Merge them.
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scoped_ptr<Value> new_value(
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          MergePreference(pref_name, *user_pref_value, *sync_value));
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Update the local preference based on what we got from the
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // sync server. Note: this only updates the user value store, which is
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ignored if the preference is policy controlled.
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (new_value->IsType(Value::TYPE_NULL)) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        pref_service_->ClearPref(pref_name.c_str());
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (!new_value->IsType(user_pref_value->GetType())) {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(WARNING) << "Synced value for " << preference.name()
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     << " is of type " << new_value->GetType()
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     << " which doesn't match pref type "
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     << user_pref_value->GetType();
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (!user_pref_value->Equals(new_value.get())) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        pref_service_->Set(pref_name.c_str(), *new_value);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If the merge resulted in an updated value, inform the syncer.
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!sync_value->Equals(new_value.get())) {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        syncer::SyncData sync_data;
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (!CreatePrefSyncData(pref_name, *new_value, &sync_data)) {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          LOG(ERROR) << "Failed to update preference.";
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        sync_changes->push_back(
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            syncer::SyncChange(FROM_HERE,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               syncer::SyncChange::ACTION_UPDATE,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               sync_data));
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else if (!sync_value->IsType(Value::TYPE_NULL)) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Only a server value exists. Just set the local user value.
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pref_service_->Set(pref_name.c_str(), *sync_value);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (user_pref_value) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The server does not know about this preference and should be added
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to the syncer's database.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncData sync_data;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!CreatePrefSyncData(pref_name, *user_pref_value, &sync_data)) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to update preference.";
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_changes->push_back(
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        syncer::SyncChange(FROM_HERE,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           syncer::SyncChange::ACTION_ADD,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           sync_data));
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This pref does not have a sync value but also does not have a user
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // controlled value (either it's a default value or it's policy controlled,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // either way it's not interesting). We can ignore it. Once it gets changed,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we'll send the new user controlled value to the syncer.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we add it to our list of synced preferences so we know what
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the server is aware of.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  synced_preferences_.insert(pref_name);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::ModelType type,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncer::SyncDataList& initial_sync_data,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(type_, type);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pref_service_);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!sync_processor_.get());
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sync_processor.get());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sync_error_factory.get());
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult merge_result(type);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_processor_ = sync_processor.Pass();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_error_factory_ = sync_error_factory.Pass();
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncChangeList new_changes;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<std::string> remaining_preferences = registered_preferences_;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Go through and check for all preferences we care about that sync already
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // knows about.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (syncer::SyncDataList::const_iterator sync_iter =
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           initial_sync_data.begin();
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       sync_iter != initial_sync_data.end();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++sync_iter) {
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_EQ(type_, sync_iter->GetDataType());
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const sync_pb::PreferenceSpecifics& preference = GetSpecifics(*sync_iter);
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& sync_pref_name = preference.name();
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (remaining_preferences.count(sync_pref_name) == 0) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We're not syncing this preference locally, ignore the sync data.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(zea): Eventually we want to be able to have the syncable service
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // reconstruct all sync data for it's datatype (therefore having
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // GetAllSyncData be a complete representation). We should store this data
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // somewhere, even if we don't use it.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remaining_preferences.erase(sync_pref_name);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Go through and build sync data for any remaining preferences.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<std::string>::iterator pref_name_iter =
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          remaining_preferences.begin();
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       pref_name_iter != remaining_preferences.end();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++pref_name_iter) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Push updates to sync.
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  merge_result.set_error(
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (merge_result.error().IsSet())
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return merge_result;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  models_associated_ = true;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_service_->OnIsSyncingChanged();
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return merge_result;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrefModelAssociator::StopSyncing(syncer::ModelType type) {
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(type_, type);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  models_associated_ = false;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_processor_.reset();
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_error_factory_.reset();
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_service_->OnIsSyncingChanged();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<Value> PrefModelAssociator::MergePreference(
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& name,
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Value& local_value,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value& server_value) {
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (name == prefs::kURLsToRestoreOnStartup) {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<Value>(MergeListValues(local_value, server_value)).Pass();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (name == prefs::kContentSettingsPatternPairs) {
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<Value>(
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        MergeDictionaryValues(local_value, server_value)).Pass();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If this is not a specially handled preference, server wins.
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return scoped_ptr<Value>(server_value.DeepCopy()).Pass();
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PrefModelAssociator::CreatePrefSyncData(
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value& value,
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    syncer::SyncData* sync_data) const {
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (value.IsType(Value::TYPE_NULL)) {
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Attempting to sync a null pref value for " << name;
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string serialized;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(zea): consider JSONWriter::Write since you don't have to check
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // failures to deserialize.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JSONStringValueSerializer json(&serialized);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!json.Serialize(value)) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to serialize preference value.";
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_pb::EntitySpecifics specifics;
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  sync_pb::PreferenceSpecifics* pref_specifics =
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GetMutableSpecifics(type_, &specifics);
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_specifics->set_name(name);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_specifics->set_value(serialized);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *sync_data = syncer::SyncData::CreateLocalData(name, name, specifics);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Value* PrefModelAssociator::MergeListValues(const Value& from_value,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const Value& to_value) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_value.GetType() == Value::TYPE_NULL)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return to_value.DeepCopy();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (to_value.GetType() == Value::TYPE_NULL)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return from_value.DeepCopy();
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(from_value.GetType() == Value::TYPE_LIST);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(to_value.GetType() == Value::TYPE_LIST);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ListValue& from_list_value = static_cast<const ListValue&>(from_value);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ListValue& to_list_value = static_cast<const ListValue&>(to_value);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListValue* result = to_list_value.DeepCopy();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ListValue::const_iterator i = from_list_value.begin();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != from_list_value.end(); ++i) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Value* value = (*i)->DeepCopy();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendIfNotPresent(value);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Value* PrefModelAssociator::MergeDictionaryValues(
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value& from_value,
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value& to_value) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_value.GetType() == Value::TYPE_NULL)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return to_value.DeepCopy();
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (to_value.GetType() == Value::TYPE_NULL)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return from_value.DeepCopy();
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(from_value.GetType(), Value::TYPE_DICTIONARY);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(to_value.GetType(), Value::TYPE_DICTIONARY);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DictionaryValue& from_dict_value =
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<const DictionaryValue&>(from_value);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DictionaryValue& to_dict_value =
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<const DictionaryValue&>(to_value);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* result = to_dict_value.DeepCopy();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (DictionaryValue::Iterator it(from_dict_value); !it.IsAtEnd();
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it.Advance()) {
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Value* from_value = &it.value();
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Value* to_key_value;
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (result->GetWithoutPathExpansion(it.key(), &to_key_value)) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (to_key_value->GetType() == Value::TYPE_DICTIONARY) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Value* merged_value = MergeDictionaryValues(*from_value, *to_key_value);
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result->SetWithoutPathExpansion(it.key(), merged_value);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note that for all other types we want to preserve the "to"
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // values so we do nothing here.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      result->SetWithoutPathExpansion(it.key(), from_value->DeepCopy());
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: This will build a model of all preferences registered as syncable
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with user controlled data. We do not track any information for preferences
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not registered locally as syncable and do not inform the syncer of
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// non-user controlled preferences.
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncDataList PrefModelAssociator::GetAllSyncData(
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::ModelType type)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const {
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(type_, type);
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncDataList current_data;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (PreferenceSet::const_iterator iter = synced_preferences_.begin();
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != synced_preferences_.end();
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++iter) {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string name = *iter;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PrefService::Preference* pref =
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pref_service_->FindPreference(name.c_str());
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(pref);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!pref->IsUserControlled() || pref->IsDefaultValue())
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // This is not data we care about.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(zea): plumb a way to read the user controlled value.
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncData sync_data;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!CreatePrefSyncData(name, *pref->GetValue(), &sync_data))
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_data.push_back(sync_data);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return current_data;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncError PrefModelAssociator::ProcessSyncChanges(
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& from_here,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncer::SyncChangeList& change_list) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!models_associated_) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncError error(FROM_HERE,
351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            syncer::SyncError::DATATYPE_ERROR,
352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            "Models not yet associated.",
353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            PREFERENCES);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return error;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncChangeList::const_iterator iter;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = change_list.begin(); iter != change_list.end(); ++iter) {
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_EQ(type_, iter->sync_data().GetDataType());
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string name;
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const sync_pb::PreferenceSpecifics& pref_specifics =
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        GetSpecifics(iter->sync_data());
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<Value> value(ReadPreferenceSpecifics(pref_specifics,
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    &name));
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We never delete preferences.
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Attempted to process sync delete change for " << name
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << ". Skipping.";
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip values we can't deserialize.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(zea): consider taking some further action such as erasing the bad
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // data.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.get())
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // It is possible that we may receive a change to a preference we do not
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // want to sync. For example if the user is syncing a Mac client and a
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Windows client, the Windows client does not support
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // kConfirmToQuitEnabled. Ignore updates from these preferences.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* pref_name = name.c_str();
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsPrefRegistered(pref_name))
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PrefService::Preference* pref =
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pref_service_->FindPreference(pref_name);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(pref);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This will only modify the user controlled value store, which takes
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // priority over the default value but is ignored if the preference is
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // policy controlled.
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pref_service_->Set(pref_name, *value);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Keep track of any newly synced preferences.
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (iter->change_type() == syncer::SyncChange::ACTION_ADD) {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      synced_preferences_.insert(name);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return syncer::SyncError();
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Value* PrefModelAssociator::ReadPreferenceSpecifics(
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::PreferenceSpecifics& preference,
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* name) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::JSONReader reader;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Value> value(reader.ReadToValue(preference.value()));
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value.get()) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string err = "Failed to deserialize preference value: " +
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reader.GetErrorMessage();
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << err;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *name = preference.name();
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value.release();
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool PrefModelAssociator::IsPrefSynced(const std::string& name) const {
42290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return synced_preferences_.find(name) != synced_preferences_.end();
42390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
42490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::set<std::string> PrefModelAssociator::registered_preferences() const {
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return registered_preferences_;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrefModelAssociator::RegisterPref(const char* name) {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!models_associated_ && registered_preferences_.count(name) == 0);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registered_preferences_.insert(name);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PrefModelAssociator::IsPrefRegistered(const char* name) {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return registered_preferences_.count(name) > 0;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (processing_syncer_changes_)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // These are changes originating from us, ignore.
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only process changes if we've already associated models.
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!models_associated_)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PrefService::Preference* preference =
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pref_service_->FindPreference(name.c_str());
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!preference)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsPrefRegistered(name.c_str()))
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // We are not syncing this preference.
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncChangeList changes;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!preference->IsUserModifiable()) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the preference is no longer user modifiable, it must now be controlled
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // by policy, whose values we do not sync. Just return. If the preference
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // stops being controlled by policy, it will revert back to the user value
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (which we continue to update with sync changes).
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (synced_preferences_.count(name) == 0) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Not in synced_preferences_ means no synced data. InitPrefAndAssociate(..)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will determine if we care about its data (e.g. if it has a default value
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and hasn't been changed yet we don't) and take care syncing any new data.
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitPrefAndAssociate(syncer::SyncData(), name, &changes);
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We are already syncing this preference, just update it's sync node.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncData sync_data;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to update preference.";
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changes.push_back(
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        syncer::SyncChange(FROM_HERE,
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           syncer::SyncChange::ACTION_UPDATE,
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           sync_data));
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncError error =
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) {
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pref_service_ == NULL);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_service_ = pref_service;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
492