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 |