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