| 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 |