OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/glue/non_frontend_data_type_controller.h" | 5 #include "chrome/browser/sync/glue/non_frontend_data_type_controller.h" |
6 | 6 |
7 #include "base/bind.h" | |
8 #include "base/callback.h" | |
9 #include "base/logging.h" | 7 #include "base/logging.h" |
10 #include "chrome/browser/profiles/profile.h" | 8 #include "chrome/browser/profiles/profile.h" |
11 #include "chrome/browser/sync/api/sync_error.h" | 9 #include "chrome/browser/sync/api/sync_error.h" |
12 #include "chrome/browser/sync/glue/change_processor.h" | 10 #include "chrome/browser/sync/glue/change_processor.h" |
13 #include "chrome/browser/sync/glue/model_associator.h" | 11 #include "chrome/browser/sync/glue/model_associator.h" |
14 #include "chrome/browser/sync/profile_sync_factory.h" | 12 #include "chrome/browser/sync/profile_sync_factory.h" |
15 #include "chrome/browser/sync/profile_sync_service.h" | 13 #include "chrome/browser/sync/profile_sync_service.h" |
16 #include "chrome/browser/sync/syncable/model_type.h" | 14 #include "chrome/browser/sync/syncable/model_type.h" |
17 #include "content/browser/browser_thread.h" | 15 #include "content/browser/browser_thread.h" |
18 | 16 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 delete start_callback; | 53 delete start_callback; |
56 return; | 54 return; |
57 } | 55 } |
58 | 56 |
59 start_callback_.reset(start_callback); | 57 start_callback_.reset(start_callback); |
60 abort_association_ = false; | 58 abort_association_ = false; |
61 | 59 |
62 state_ = MODEL_STARTING; | 60 state_ = MODEL_STARTING; |
63 if (!StartModels()) { | 61 if (!StartModels()) { |
64 // If we are waiting for some external service to load before associating | 62 // If we are waiting for some external service to load before associating |
65 // or we failed to start the models, we exit early. | 63 // or we failed to start the models, we exit early. state_ will control |
| 64 // what we perform next. |
66 DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING); | 65 DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING); |
67 return; | 66 return; |
68 } | 67 } |
69 | 68 |
70 // Kick off association on the thread the datatype resides on. | 69 // Kick off association on the thread the datatype resides on. |
71 state_ = ASSOCIATING; | 70 state_ = ASSOCIATING; |
72 if (!StartAssociationAsync()) { | 71 if (!StartAssociationAsync()) { |
73 SyncError error(FROM_HERE, "Failed to post StartAssociation", type()); | 72 SyncError error(FROM_HERE, "Failed to post StartAssociation", type()); |
74 StartDoneImpl(ASSOCIATION_FAILED, DISABLED, error); | 73 StartDoneImpl(ASSOCIATION_FAILED, DISABLED, error); |
75 } | 74 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 base::TimeTicks start_time = base::TimeTicks::Now(); | 109 base::TimeTicks start_time = base::TimeTicks::Now(); |
111 SyncError error; | 110 SyncError error; |
112 bool merge_success = model_associator_->AssociateModels(&error); | 111 bool merge_success = model_associator_->AssociateModels(&error); |
113 RecordAssociationTime(base::TimeTicks::Now() - start_time); | 112 RecordAssociationTime(base::TimeTicks::Now() - start_time); |
114 if (!merge_success) { | 113 if (!merge_success) { |
115 StartFailed(ASSOCIATION_FAILED, error); | 114 StartFailed(ASSOCIATION_FAILED, error); |
116 return; | 115 return; |
117 } | 116 } |
118 | 117 |
119 profile_sync_service_->ActivateDataType(type(), model_safe_group(), | 118 profile_sync_service_->ActivateDataType(type(), model_safe_group(), |
120 change_processor()); | 119 change_processor_.get()); |
121 StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING, SyncError()); | 120 StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING, SyncError()); |
122 } | 121 } |
123 | 122 |
124 void NonFrontendDataTypeController::StartFailed(StartResult result, | 123 void NonFrontendDataTypeController::StartFailed(StartResult result, |
125 const SyncError& error) { | 124 const SyncError& error) { |
126 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | 125 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
127 model_associator_.reset(); | 126 model_associator_.reset(); |
128 change_processor_.reset(); | 127 change_processor_.reset(); |
129 StartDone(result, | 128 StartDone(result, |
130 result == ASSOCIATION_FAILED ? DISABLED : NOT_RUNNING, | 129 result == ASSOCIATION_FAILED ? DISABLED : NOT_RUNNING, |
131 error); | 130 error); |
132 } | 131 } |
133 | 132 |
134 void NonFrontendDataTypeController::StartDone( | 133 void NonFrontendDataTypeController::StartDone( |
135 DataTypeController::StartResult result, | 134 DataTypeController::StartResult result, |
136 DataTypeController::State new_state, | 135 DataTypeController::State new_state, |
137 const SyncError& error) { | 136 const SyncError& error) { |
138 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | 137 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
139 abort_association_complete_.Signal(); | 138 abort_association_complete_.Signal(); |
140 base::AutoLock lock(abort_association_lock_); | 139 base::AutoLock lock(abort_association_lock_); |
141 if (!abort_association_) { | 140 if (!abort_association_) { |
142 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 141 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
143 base::Bind(&NonFrontendDataTypeController::StartDoneImpl, | 142 NewRunnableMethod( |
144 this, | 143 this, |
145 result, | 144 &NonFrontendDataTypeController::StartDoneImpl, |
146 new_state, | 145 result, |
147 error)); | 146 new_state, |
| 147 error)); |
148 } | 148 } |
149 } | 149 } |
150 | 150 |
151 void NonFrontendDataTypeController::StartDoneImpl( | 151 void NonFrontendDataTypeController::StartDoneImpl( |
152 DataTypeController::StartResult result, | 152 DataTypeController::StartResult result, |
153 DataTypeController::State new_state, | 153 DataTypeController::State new_state, |
154 const SyncError& error) { | 154 const SyncError& error) { |
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
156 // It's possible to have StartDoneImpl called first from the UI thread | 156 |
157 // (due to Stop being called) and then posted from the non-UI thread. In | |
158 // this case, we drop the second call because we've already been stopped. | |
159 if (state_ == NOT_RUNNING) { | 157 if (state_ == NOT_RUNNING) { |
| 158 // During stop it is possible startdoneimpl can be called twice. Once from |
| 159 // the |StartDone| method and once from the |Stop| method. |
160 DCHECK(!start_callback_.get()); | 160 DCHECK(!start_callback_.get()); |
161 return; | 161 return; |
162 } | 162 } |
163 | |
164 state_ = new_state; | 163 state_ = new_state; |
165 if (state_ != RUNNING) { | 164 if (state_ != RUNNING) { |
166 // Start failed. | 165 // Start failed. |
167 StopModels(); | 166 StopModels(); |
168 RecordStartFailure(result); | 167 RecordStartFailure(result); |
169 } | 168 } |
170 | 169 |
171 // We have to release the callback before we call it, since it's possible | 170 // We have to release the callback before we call it, since it's possible |
172 // invoking the callback will trigger a call to STOP(), which will get | 171 // invoking the callback will trigger a call to STOP(), which will get |
173 // confused by the non-NULL start_callback_. | 172 // confused by the non-NULL start_callback_. |
174 scoped_ptr<StartCallback> callback(start_callback_.release()); | 173 scoped_ptr<StartCallback> callback(start_callback_.release()); |
175 callback->Run(result, error); | 174 callback->Run(result, error); |
176 } | 175 } |
177 | 176 |
178 // TODO(sync): Blocking the UI thread at shutdown is bad. The new API avoids | 177 // TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of |
179 // this. Once all non-frontend datatypes use the new API, we can get rid of this | 178 // distinguishing chrome shutdown from sync shutdown, we should be able to avoid |
180 // locking (see implementation in AutofillProfileDataTypeController). | 179 // this (http://crbug.com/55662). |
181 void NonFrontendDataTypeController::Stop() { | 180 void NonFrontendDataTypeController::Stop() { |
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
183 // If Stop() is called while Start() is waiting for association to | 182 // If Stop() is called while Start() is waiting for association to |
184 // complete, we need to abort the association and wait for the DB | 183 // complete, we need to abort the association and wait for the DB |
185 // thread to finish the StartImpl() task. | 184 // thread to finish the StartImpl() task. |
186 if (state_ == ASSOCIATING) { | 185 if (state_ == ASSOCIATING) { |
187 state_ = STOPPING; | 186 state_ = STOPPING; |
188 { | 187 { |
189 base::AutoLock lock(abort_association_lock_); | 188 base::AutoLock lock(abort_association_lock_); |
190 abort_association_ = true; | 189 abort_association_ = true; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 | 246 |
248 DataTypeController::State NonFrontendDataTypeController::state() const { | 247 DataTypeController::State NonFrontendDataTypeController::state() const { |
249 return state_; | 248 return state_; |
250 } | 249 } |
251 | 250 |
252 void NonFrontendDataTypeController::OnUnrecoverableError( | 251 void NonFrontendDataTypeController::OnUnrecoverableError( |
253 const tracked_objects::Location& from_here, | 252 const tracked_objects::Location& from_here, |
254 const std::string& message) { | 253 const std::string& message) { |
255 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | 254 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
256 RecordUnrecoverableError(from_here, message); | 255 RecordUnrecoverableError(from_here, message); |
257 BrowserThread::PostTask(BrowserThread::UI, from_here, | 256 BrowserThread::PostTask(BrowserThread::UI, from_here, NewRunnableMethod(this, |
258 base::Bind(&NonFrontendDataTypeController::OnUnrecoverableErrorImpl, | 257 &NonFrontendDataTypeController::OnUnrecoverableErrorImpl, from_here, |
259 this, | 258 message)); |
260 from_here, | |
261 message)); | |
262 } | 259 } |
263 | 260 |
264 void NonFrontendDataTypeController::OnUnrecoverableErrorImpl( | 261 void NonFrontendDataTypeController::OnUnrecoverableErrorImpl( |
265 const tracked_objects::Location& from_here, | 262 const tracked_objects::Location& from_here, |
266 const std::string& message) { | 263 const std::string& message) { |
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
268 profile_sync_service_->OnUnrecoverableError(from_here, message); | 265 profile_sync_service_->OnUnrecoverableError(from_here, message); |
269 } | 266 } |
270 | 267 |
271 ProfileSyncFactory* NonFrontendDataTypeController::profile_sync_factory() | 268 ProfileSyncFactory* NonFrontendDataTypeController::profile_sync_factory() |
272 const { | 269 const { |
273 return profile_sync_factory_; | 270 return profile_sync_factory_; |
274 } | 271 } |
275 | 272 |
276 Profile* NonFrontendDataTypeController::profile() const { | 273 Profile* NonFrontendDataTypeController::profile() const { |
277 return profile_; | 274 return profile_; |
278 } | 275 } |
279 | 276 |
280 ProfileSyncService* NonFrontendDataTypeController::profile_sync_service() | 277 ProfileSyncService* NonFrontendDataTypeController::profile_sync_service() |
281 const { | 278 const { |
282 return profile_sync_service_; | 279 return profile_sync_service_; |
283 } | 280 } |
284 | 281 |
285 void NonFrontendDataTypeController::set_start_callback( | |
286 StartCallback* callback) { | |
287 start_callback_.reset(callback); | |
288 } | |
289 void NonFrontendDataTypeController::set_state(State state) { | 282 void NonFrontendDataTypeController::set_state(State state) { |
290 state_ = state; | 283 state_ = state; |
291 } | 284 } |
292 | 285 |
293 AssociatorInterface* NonFrontendDataTypeController::associator() const { | |
294 return model_associator_.get(); | |
295 } | |
296 | |
297 void NonFrontendDataTypeController::set_model_associator( | 286 void NonFrontendDataTypeController::set_model_associator( |
298 AssociatorInterface* associator) { | 287 AssociatorInterface* associator) { |
299 model_associator_.reset(associator); | 288 model_associator_.reset(associator); |
300 } | 289 } |
301 | 290 |
302 ChangeProcessor* NonFrontendDataTypeController::change_processor() const { | |
303 return change_processor_.get(); | |
304 } | |
305 | |
306 void NonFrontendDataTypeController::set_change_processor( | 291 void NonFrontendDataTypeController::set_change_processor( |
307 ChangeProcessor* change_processor) { | 292 ChangeProcessor* change_processor) { |
308 change_processor_.reset(change_processor); | 293 change_processor_.reset(change_processor); |
309 } | 294 } |
310 | 295 |
311 } // namespace browser_sync | 296 } // namespace browser_sync |
OLD | NEW |