1// Copyright 2014 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/shared_change_processor.h" 6 7#include "base/message_loop/message_loop_proxy.h" 8#include "components/sync_driver/generic_change_processor.h" 9#include "components/sync_driver/generic_change_processor_factory.h" 10#include "components/sync_driver/sync_api_component_factory.h" 11#include "sync/api/sync_change.h" 12 13using base::AutoLock; 14 15namespace browser_sync { 16 17SharedChangeProcessor::SharedChangeProcessor() 18 : disconnected_(false), 19 type_(syncer::UNSPECIFIED), 20 frontend_loop_(base::MessageLoopProxy::current()), 21 generic_change_processor_(NULL), 22 error_handler_(NULL) { 23} 24 25SharedChangeProcessor::~SharedChangeProcessor() { 26 // We can either be deleted when the DTC is destroyed (on UI 27 // thread), or when the syncer::SyncableService stop's syncing (datatype 28 // thread). |generic_change_processor_|, if non-NULL, must be 29 // deleted on |backend_loop_|. 30 if (frontend_loop_->BelongsToCurrentThread()) { 31 if (backend_loop_.get()) { 32 if (!backend_loop_->DeleteSoon(FROM_HERE, generic_change_processor_)) { 33 NOTREACHED(); 34 } 35 } else { 36 DCHECK(!generic_change_processor_); 37 } 38 } else { 39 DCHECK(backend_loop_.get()); 40 DCHECK(backend_loop_->BelongsToCurrentThread()); 41 delete generic_change_processor_; 42 } 43} 44 45base::WeakPtr<syncer::SyncableService> SharedChangeProcessor::Connect( 46 browser_sync::SyncApiComponentFactory* sync_factory, 47 GenericChangeProcessorFactory* processor_factory, 48 syncer::UserShare* user_share, 49 DataTypeErrorHandler* error_handler, 50 syncer::ModelType type, 51 const base::WeakPtr<syncer::SyncMergeResult>& merge_result) { 52 DCHECK(sync_factory); 53 DCHECK(error_handler); 54 DCHECK_NE(type, syncer::UNSPECIFIED); 55 backend_loop_ = base::MessageLoopProxy::current(); 56 AutoLock lock(monitor_lock_); 57 if (disconnected_) 58 return base::WeakPtr<syncer::SyncableService>(); 59 type_ = type; 60 error_handler_ = error_handler; 61 base::WeakPtr<syncer::SyncableService> local_service = 62 sync_factory->GetSyncableServiceForType(type); 63 if (!local_service.get()) { 64 LOG(WARNING) << "SyncableService destroyed before DTC was stopped."; 65 disconnected_ = true; 66 return base::WeakPtr<syncer::SyncableService>(); 67 } 68 69 generic_change_processor_ = 70 processor_factory->CreateGenericChangeProcessor(user_share, 71 error_handler, 72 local_service, 73 merge_result, 74 sync_factory).release(); 75 return local_service; 76} 77 78bool SharedChangeProcessor::Disconnect() { 79 // May be called from any thread. 80 DVLOG(1) << "Disconnecting change processor."; 81 AutoLock lock(monitor_lock_); 82 bool was_connected = !disconnected_; 83 disconnected_ = true; 84 error_handler_ = NULL; 85 return was_connected; 86} 87 88ChangeProcessor* SharedChangeProcessor::generic_change_processor() { 89 return generic_change_processor_; 90} 91 92int SharedChangeProcessor::GetSyncCount() { 93 DCHECK(backend_loop_.get()); 94 DCHECK(backend_loop_->BelongsToCurrentThread()); 95 AutoLock lock(monitor_lock_); 96 if (disconnected_) { 97 LOG(ERROR) << "Change processor disconnected."; 98 return 0; 99 } 100 return generic_change_processor_->GetSyncCountForType(type_); 101} 102 103syncer::SyncError SharedChangeProcessor::ProcessSyncChanges( 104 const tracked_objects::Location& from_here, 105 const syncer::SyncChangeList& list_of_changes) { 106 DCHECK(backend_loop_.get()); 107 DCHECK(backend_loop_->BelongsToCurrentThread()); 108 AutoLock lock(monitor_lock_); 109 if (disconnected_) { 110 // The DTC that disconnects us must ensure it posts a StopSyncing task. 111 // If we reach this, it means it just hasn't executed yet. 112 syncer::SyncError error(FROM_HERE, 113 syncer::SyncError::DATATYPE_ERROR, 114 "Change processor disconnected.", 115 type_); 116 return error; 117 } 118 return generic_change_processor_->ProcessSyncChanges( 119 from_here, list_of_changes); 120} 121 122syncer::SyncDataList SharedChangeProcessor::GetAllSyncData( 123 syncer::ModelType type) const { 124 syncer::SyncDataList data; 125 GetAllSyncDataReturnError(type, &data); // Handles the disconnect case. 126 return data; 127} 128 129syncer::SyncError SharedChangeProcessor::GetAllSyncDataReturnError( 130 syncer::ModelType type, 131 syncer::SyncDataList* data) const { 132 DCHECK(backend_loop_.get()); 133 DCHECK(backend_loop_->BelongsToCurrentThread()); 134 AutoLock lock(monitor_lock_); 135 if (disconnected_) { 136 syncer::SyncError error(FROM_HERE, 137 syncer::SyncError::DATATYPE_ERROR, 138 "Change processor disconnected.", 139 type_); 140 return error; 141 } 142 return generic_change_processor_->GetAllSyncDataReturnError(type, data); 143} 144 145syncer::SyncError SharedChangeProcessor::UpdateDataTypeContext( 146 syncer::ModelType type, 147 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status, 148 const std::string& context) { 149 DCHECK(backend_loop_.get()); 150 DCHECK(backend_loop_->BelongsToCurrentThread()); 151 AutoLock lock(monitor_lock_); 152 if (disconnected_) { 153 syncer::SyncError error(FROM_HERE, 154 syncer::SyncError::DATATYPE_ERROR, 155 "Change processor disconnected.", 156 type_); 157 return error; 158 } 159 return generic_change_processor_->UpdateDataTypeContext( 160 type, refresh_status, context); 161} 162 163bool SharedChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) { 164 DCHECK(backend_loop_.get()); 165 DCHECK(backend_loop_->BelongsToCurrentThread()); 166 AutoLock lock(monitor_lock_); 167 if (disconnected_) { 168 LOG(ERROR) << "Change processor disconnected."; 169 return false; 170 } 171 return generic_change_processor_->SyncModelHasUserCreatedNodes( 172 type_, has_nodes); 173} 174 175bool SharedChangeProcessor::CryptoReadyIfNecessary() { 176 DCHECK(backend_loop_.get()); 177 DCHECK(backend_loop_->BelongsToCurrentThread()); 178 AutoLock lock(monitor_lock_); 179 if (disconnected_) { 180 LOG(ERROR) << "Change processor disconnected."; 181 return true; // Otherwise we get into infinite spin waiting. 182 } 183 return generic_change_processor_->CryptoReadyIfNecessary(type_); 184} 185 186bool SharedChangeProcessor::GetDataTypeContext(std::string* context) const { 187 DCHECK(backend_loop_.get()); 188 DCHECK(backend_loop_->BelongsToCurrentThread()); 189 AutoLock lock(monitor_lock_); 190 if (disconnected_) { 191 LOG(ERROR) << "Change processor disconnected."; 192 return false; 193 } 194 return generic_change_processor_->GetDataTypeContext(type_, context); 195} 196 197syncer::SyncError SharedChangeProcessor::CreateAndUploadError( 198 const tracked_objects::Location& location, 199 const std::string& message) { 200 AutoLock lock(monitor_lock_); 201 if (!disconnected_) { 202 return error_handler_->CreateAndUploadError(location, message, type_); 203 } else { 204 return syncer::SyncError(location, 205 syncer::SyncError::DATATYPE_ERROR, 206 message, 207 type_); 208 } 209} 210 211} // namespace browser_sync 212