| OLD | NEW |
| (Empty) |
| 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/non_ui_data_type_controller.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/threading/thread_task_runner_handle.h" | |
| 11 #include "components/sync/base/bind_to_task_runner.h" | |
| 12 #include "components/sync/base/data_type_histogram.h" | |
| 13 #include "components/sync/base/model_type.h" | |
| 14 #include "components/sync/driver/generic_change_processor_factory.h" | |
| 15 #include "components/sync/driver/sync_api_component_factory.h" | |
| 16 #include "components/sync/driver/sync_client.h" | |
| 17 #include "components/sync/driver/sync_service.h" | |
| 18 #include "components/sync/model/data_type_error_handler_impl.h" | |
| 19 #include "components/sync/model/sync_error.h" | |
| 20 #include "components/sync/model/sync_merge_result.h" | |
| 21 #include "components/sync/model/syncable_service.h" | |
| 22 | |
| 23 namespace syncer { | |
| 24 | |
| 25 SharedChangeProcessor* NonUIDataTypeController::CreateSharedChangeProcessor() { | |
| 26 return new SharedChangeProcessor(type()); | |
| 27 } | |
| 28 | |
| 29 NonUIDataTypeController::NonUIDataTypeController( | |
| 30 ModelType type, | |
| 31 const base::Closure& dump_stack, | |
| 32 SyncClient* sync_client, | |
| 33 ModelSafeGroup model_safe_group, | |
| 34 scoped_refptr<base::SequencedTaskRunner> model_thread) | |
| 35 : DirectoryDataTypeController(type, | |
| 36 dump_stack, | |
| 37 sync_client, | |
| 38 model_safe_group), | |
| 39 user_share_(nullptr), | |
| 40 processor_factory_(new GenericChangeProcessorFactory()), | |
| 41 state_(NOT_RUNNING), | |
| 42 model_thread_(std::move(model_thread)) {} | |
| 43 | |
| 44 void NonUIDataTypeController::LoadModels( | |
| 45 const ModelLoadCallback& model_load_callback) { | |
| 46 DCHECK(CalledOnValidThread()); | |
| 47 model_load_callback_ = model_load_callback; | |
| 48 if (state() != NOT_RUNNING) { | |
| 49 model_load_callback.Run(type(), | |
| 50 SyncError(FROM_HERE, SyncError::DATATYPE_ERROR, | |
| 51 "Model already running", type())); | |
| 52 return; | |
| 53 } | |
| 54 | |
| 55 state_ = MODEL_STARTING; | |
| 56 // Since we can't be called multiple times before Stop() is called, | |
| 57 // |shared_change_processor_| must be null here. | |
| 58 DCHECK(!shared_change_processor_.get()); | |
| 59 shared_change_processor_ = CreateSharedChangeProcessor(); | |
| 60 DCHECK(shared_change_processor_.get()); | |
| 61 if (!StartModels()) { | |
| 62 // If we are waiting for some external service to load before associating | |
| 63 // or we failed to start the models, we exit early. | |
| 64 DCHECK(state() == MODEL_STARTING || state() == NOT_RUNNING); | |
| 65 return; | |
| 66 } | |
| 67 | |
| 68 OnModelLoaded(); | |
| 69 } | |
| 70 | |
| 71 void NonUIDataTypeController::OnModelLoaded() { | |
| 72 DCHECK(CalledOnValidThread()); | |
| 73 DCHECK_EQ(state_, MODEL_STARTING); | |
| 74 state_ = MODEL_LOADED; | |
| 75 model_load_callback_.Run(type(), SyncError()); | |
| 76 } | |
| 77 | |
| 78 bool NonUIDataTypeController::StartModels() { | |
| 79 DCHECK(CalledOnValidThread()); | |
| 80 DCHECK_EQ(state_, MODEL_STARTING); | |
| 81 // By default, no additional services need to be started before we can proceed | |
| 82 // with model association. | |
| 83 return true; | |
| 84 } | |
| 85 | |
| 86 void NonUIDataTypeController::StopModels() { | |
| 87 DCHECK(CalledOnValidThread()); | |
| 88 } | |
| 89 | |
| 90 bool NonUIDataTypeController::PostTaskOnModelThread( | |
| 91 const tracked_objects::Location& from_here, | |
| 92 const base::Closure& task) { | |
| 93 DCHECK(CalledOnValidThread()); | |
| 94 return model_thread_->PostTask(from_here, task); | |
| 95 } | |
| 96 | |
| 97 void NonUIDataTypeController::StartAssociating( | |
| 98 const StartCallback& start_callback) { | |
| 99 DCHECK(CalledOnValidThread()); | |
| 100 DCHECK(!start_callback.is_null()); | |
| 101 DCHECK_EQ(state_, MODEL_LOADED); | |
| 102 state_ = ASSOCIATING; | |
| 103 | |
| 104 // Store UserShare now while on UI thread to avoid potential race | |
| 105 // condition in StartAssociationWithSharedChangeProcessor. | |
| 106 DCHECK(sync_client_->GetSyncService()); | |
| 107 user_share_ = sync_client_->GetSyncService()->GetUserShare(); | |
| 108 | |
| 109 start_callback_ = start_callback; | |
| 110 if (!StartAssociationAsync()) { | |
| 111 SyncError error(FROM_HERE, SyncError::DATATYPE_ERROR, | |
| 112 "Failed to post StartAssociation", type()); | |
| 113 SyncMergeResult local_merge_result(type()); | |
| 114 local_merge_result.set_error(error); | |
| 115 StartDone(ASSOCIATION_FAILED, local_merge_result, SyncMergeResult(type())); | |
| 116 // StartDone should have cleared the SharedChangeProcessor. | |
| 117 DCHECK(!shared_change_processor_.get()); | |
| 118 return; | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 void NonUIDataTypeController::Stop() { | |
| 123 DCHECK(CalledOnValidThread()); | |
| 124 | |
| 125 if (state() == NOT_RUNNING) | |
| 126 return; | |
| 127 | |
| 128 // Disconnect the change processor. At this point, the | |
| 129 // SyncableService can no longer interact with the Syncer, even if | |
| 130 // it hasn't finished MergeDataAndStartSyncing. | |
| 131 DisconnectSharedChangeProcessor(); | |
| 132 | |
| 133 // If we haven't finished starting, we need to abort the start. | |
| 134 bool service_started = state() == ASSOCIATING || state() == RUNNING; | |
| 135 state_ = service_started ? STOPPING : NOT_RUNNING; | |
| 136 StopModels(); | |
| 137 | |
| 138 if (service_started) | |
| 139 StopSyncableService(); | |
| 140 | |
| 141 shared_change_processor_ = nullptr; | |
| 142 state_ = NOT_RUNNING; | |
| 143 } | |
| 144 | |
| 145 std::string NonUIDataTypeController::name() const { | |
| 146 // For logging only. | |
| 147 return ModelTypeToString(type()); | |
| 148 } | |
| 149 | |
| 150 DataTypeController::State NonUIDataTypeController::state() const { | |
| 151 return state_; | |
| 152 } | |
| 153 | |
| 154 void NonUIDataTypeController::SetGenericChangeProcessorFactoryForTest( | |
| 155 std::unique_ptr<GenericChangeProcessorFactory> factory) { | |
| 156 DCHECK_EQ(state_, NOT_RUNNING); | |
| 157 processor_factory_ = std::move(factory); | |
| 158 } | |
| 159 | |
| 160 NonUIDataTypeController::NonUIDataTypeController() | |
| 161 : DirectoryDataTypeController(UNSPECIFIED, | |
| 162 base::Closure(), | |
| 163 nullptr, | |
| 164 GROUP_PASSIVE) {} | |
| 165 | |
| 166 NonUIDataTypeController::~NonUIDataTypeController() {} | |
| 167 | |
| 168 void NonUIDataTypeController::StartDone( | |
| 169 DataTypeController::ConfigureResult start_result, | |
| 170 const SyncMergeResult& local_merge_result, | |
| 171 const SyncMergeResult& syncer_merge_result) { | |
| 172 DCHECK(CalledOnValidThread()); | |
| 173 | |
| 174 DataTypeController::State new_state; | |
| 175 if (IsSuccessfulResult(start_result)) { | |
| 176 new_state = RUNNING; | |
| 177 } else { | |
| 178 new_state = (start_result == ASSOCIATION_FAILED ? DISABLED : NOT_RUNNING); | |
| 179 } | |
| 180 | |
| 181 // If we failed to start up, and we haven't been stopped yet, we need to | |
| 182 // ensure we clean up the local service and shared change processor properly. | |
| 183 if (new_state != RUNNING && state() != NOT_RUNNING && state() != STOPPING) { | |
| 184 DisconnectSharedChangeProcessor(); | |
| 185 StopSyncableService(); | |
| 186 shared_change_processor_ = nullptr; | |
| 187 } | |
| 188 | |
| 189 // It's possible to have StartDone called first from the UI thread | |
| 190 // (due to Stop being called) and then posted from the non-UI thread. In | |
| 191 // this case, we drop the second call because we've already been stopped. | |
| 192 if (state_ == NOT_RUNNING) { | |
| 193 return; | |
| 194 } | |
| 195 | |
| 196 state_ = new_state; | |
| 197 if (state_ != RUNNING) { | |
| 198 // Start failed. | |
| 199 StopModels(); | |
| 200 RecordStartFailure(start_result); | |
| 201 } | |
| 202 | |
| 203 start_callback_.Run(start_result, local_merge_result, syncer_merge_result); | |
| 204 } | |
| 205 | |
| 206 void NonUIDataTypeController::RecordStartFailure(ConfigureResult result) { | |
| 207 DCHECK(CalledOnValidThread()); | |
| 208 UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeStartFailures", | |
| 209 ModelTypeToHistogramInt(type()), MODEL_TYPE_COUNT); | |
| 210 #define PER_DATA_TYPE_MACRO(type_str) \ | |
| 211 UMA_HISTOGRAM_ENUMERATION("Sync." type_str "ConfigureFailure", result, \ | |
| 212 MAX_CONFIGURE_RESULT); | |
| 213 SYNC_DATA_TYPE_HISTOGRAM(type()); | |
| 214 #undef PER_DATA_TYPE_MACRO | |
| 215 } | |
| 216 | |
| 217 void NonUIDataTypeController::DisableImpl(const SyncError& error) { | |
| 218 DCHECK(CalledOnValidThread()); | |
| 219 if (!model_load_callback_.is_null()) { | |
| 220 model_load_callback_.Run(type(), error); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 bool NonUIDataTypeController::StartAssociationAsync() { | |
| 225 DCHECK(CalledOnValidThread()); | |
| 226 DCHECK_EQ(state(), ASSOCIATING); | |
| 227 return PostTaskOnModelThread( | |
| 228 FROM_HERE, | |
| 229 base::Bind( | |
| 230 &SharedChangeProcessor::StartAssociation, shared_change_processor_, | |
| 231 BindToCurrentThread(base::Bind(&NonUIDataTypeController::StartDone, | |
| 232 base::AsWeakPtr(this))), | |
| 233 sync_client_, processor_factory_.get(), user_share_, | |
| 234 base::Passed(CreateErrorHandler()))); | |
| 235 } | |
| 236 | |
| 237 ChangeProcessor* NonUIDataTypeController::GetChangeProcessor() const { | |
| 238 DCHECK(CalledOnValidThread()); | |
| 239 DCHECK_EQ(state_, RUNNING); | |
| 240 return shared_change_processor_->generic_change_processor(); | |
| 241 } | |
| 242 | |
| 243 void NonUIDataTypeController::DisconnectSharedChangeProcessor() { | |
| 244 DCHECK(CalledOnValidThread()); | |
| 245 // |shared_change_processor_| can already be null if Stop() is | |
| 246 // called after StartDone(_, DISABLED, _). | |
| 247 if (shared_change_processor_.get()) { | |
| 248 shared_change_processor_->Disconnect(); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 void NonUIDataTypeController::StopSyncableService() { | |
| 253 DCHECK(CalledOnValidThread()); | |
| 254 if (shared_change_processor_.get()) { | |
| 255 PostTaskOnModelThread(FROM_HERE, | |
| 256 base::Bind(&SharedChangeProcessor::StopLocalService, | |
| 257 shared_change_processor_)); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 std::unique_ptr<DataTypeErrorHandler> | |
| 262 NonUIDataTypeController::CreateErrorHandler() { | |
| 263 DCHECK(CalledOnValidThread()); | |
| 264 return base::MakeUnique<DataTypeErrorHandlerImpl>( | |
| 265 base::ThreadTaskRunnerHandle::Get(), dump_stack_, | |
| 266 base::Bind(&NonUIDataTypeController::DisableImpl, base::AsWeakPtr(this))); | |
| 267 } | |
| 268 | |
| 269 } // namespace syncer | |
| OLD | NEW |