| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/threading/thread_restrictions.h" | 10 #include "base/threading/thread_restrictions.h" |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 DCHECK(profile_sync_service_); | 41 DCHECK(profile_sync_service_); |
| 42 } | 42 } |
| 43 | 43 |
| 44 void NonFrontendDataTypeController::LoadModels( | 44 void NonFrontendDataTypeController::LoadModels( |
| 45 const ModelLoadCallback& model_load_callback) { | 45 const ModelLoadCallback& model_load_callback) { |
| 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 47 DCHECK(!model_load_callback.is_null()); | 47 DCHECK(!model_load_callback.is_null()); |
| 48 start_association_called_.Reset(); | 48 start_association_called_.Reset(); |
| 49 start_models_failed_ = false; | 49 start_models_failed_ = false; |
| 50 if (state_ != NOT_RUNNING) { | 50 if (state_ != NOT_RUNNING) { |
| 51 model_load_callback.Run(type(), SyncError(FROM_HERE, | 51 model_load_callback.Run(type(), csync::SyncError(FROM_HERE, |
| 52 "Model already loaded", | 52 "Model already loaded", |
| 53 type())); | 53 type())); |
| 54 return; | 54 return; |
| 55 } | 55 } |
| 56 | 56 |
| 57 state_ = MODEL_STARTING; | 57 state_ = MODEL_STARTING; |
| 58 if (!StartModels()) { | 58 if (!StartModels()) { |
| 59 start_models_failed_ = true; | 59 start_models_failed_ = true; |
| 60 // We failed to start the models. There is no point in waiting. | 60 // We failed to start the models. There is no point in waiting. |
| 61 // Note: This code is deprecated. The only 2 datatypes here, | 61 // Note: This code is deprecated. The only 2 datatypes here, |
| 62 // passwords and typed urls, dont have any special loading. So if we | 62 // passwords and typed urls, dont have any special loading. So if we |
| 63 // get a false it means they failed. | 63 // get a false it means they failed. |
| 64 DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING | 64 DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING |
| 65 || state_ == DISABLED); | 65 || state_ == DISABLED); |
| 66 model_load_callback.Run(type(), SyncError(FROM_HERE, | 66 model_load_callback.Run(type(), csync::SyncError(FROM_HERE, |
| 67 "Failed loading", | 67 "Failed loading", |
| 68 type())); | 68 type())); |
| 69 return; | 69 return; |
| 70 } | 70 } |
| 71 state_ = MODEL_LOADED; | 71 state_ = MODEL_LOADED; |
| 72 | 72 |
| 73 model_load_callback.Run(type(), SyncError()); | 73 model_load_callback.Run(type(), csync::SyncError()); |
| 74 } | 74 } |
| 75 | 75 |
| 76 void NonFrontendDataTypeController::OnModelLoaded() { | 76 void NonFrontendDataTypeController::OnModelLoaded() { |
| 77 NOTREACHED(); | 77 NOTREACHED(); |
| 78 } | 78 } |
| 79 | 79 |
| 80 void NonFrontendDataTypeController::StartAssociating( | 80 void NonFrontendDataTypeController::StartAssociating( |
| 81 const StartCallback& start_callback) { | 81 const StartCallback& start_callback) { |
| 82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 83 DCHECK(!start_callback.is_null()); | 83 DCHECK(!start_callback.is_null()); |
| 84 DCHECK_EQ(state_, MODEL_LOADED); | 84 DCHECK_EQ(state_, MODEL_LOADED); |
| 85 | 85 |
| 86 // Kick off association on the thread the datatype resides on. | 86 // Kick off association on the thread the datatype resides on. |
| 87 state_ = ASSOCIATING; | 87 state_ = ASSOCIATING; |
| 88 start_callback_ = start_callback; | 88 start_callback_ = start_callback; |
| 89 if (!StartAssociationAsync()) { | 89 if (!StartAssociationAsync()) { |
| 90 SyncError error(FROM_HERE, "Failed to post StartAssociation", type()); | 90 csync::SyncError error( |
| 91 FROM_HERE, "Failed to post StartAssociation", type()); |
| 91 StartDoneImpl(ASSOCIATION_FAILED, DISABLED, error); | 92 StartDoneImpl(ASSOCIATION_FAILED, DISABLED, error); |
| 92 } | 93 } |
| 93 } | 94 } |
| 94 | 95 |
| 95 void NonFrontendDataTypeController::StopWhileAssociating() { | 96 void NonFrontendDataTypeController::StopWhileAssociating() { |
| 96 state_ = STOPPING; | 97 state_ = STOPPING; |
| 97 { | 98 { |
| 98 base::AutoLock lock(abort_association_lock_); | 99 base::AutoLock lock(abort_association_lock_); |
| 99 abort_association_ = true; | 100 abort_association_ = true; |
| 100 if (model_associator_.get()) | 101 if (model_associator_.get()) |
| 101 model_associator_->AbortAssociation(); | 102 model_associator_->AbortAssociation(); |
| 102 if (!start_association_called_.IsSignaled()) { | 103 if (!start_association_called_.IsSignaled()) { |
| 103 StartDoneImpl(ABORTED, NOT_RUNNING, SyncError()); | 104 StartDoneImpl(ABORTED, NOT_RUNNING, csync::SyncError()); |
| 104 return; // There is nothing more for us to do. | 105 return; // There is nothing more for us to do. |
| 105 } | 106 } |
| 106 } | 107 } |
| 107 | 108 |
| 108 // Wait for the model association to abort. | 109 // Wait for the model association to abort. |
| 109 if (start_association_called_.IsSignaled()) { | 110 if (start_association_called_.IsSignaled()) { |
| 110 LOG(INFO) << "Stopping after |StartAssocation| is called."; | 111 LOG(INFO) << "Stopping after |StartAssocation| is called."; |
| 111 if (start_models_failed_) { | 112 if (start_models_failed_) { |
| 112 LOG(INFO) << "Start models failed"; | 113 LOG(INFO) << "Start models failed"; |
| 113 abort_association_complete_.Wait(); | 114 abort_association_complete_.Wait(); |
| 114 } else { | 115 } else { |
| 115 LOG(INFO) << "Start models succeeded"; | 116 LOG(INFO) << "Start models succeeded"; |
| 116 abort_association_complete_.Wait(); | 117 abort_association_complete_.Wait(); |
| 117 } | 118 } |
| 118 } else { | 119 } else { |
| 119 LOG(INFO) << "Stopping before |StartAssocation| is called."; | 120 LOG(INFO) << "Stopping before |StartAssocation| is called."; |
| 120 if (start_models_failed_) { | 121 if (start_models_failed_) { |
| 121 LOG(INFO) << "Start models failed"; | 122 LOG(INFO) << "Start models failed"; |
| 122 abort_association_complete_.Wait(); | 123 abort_association_complete_.Wait(); |
| 123 } else { | 124 } else { |
| 124 LOG(INFO) << "Start models succeeded"; | 125 LOG(INFO) << "Start models succeeded"; |
| 125 abort_association_complete_.Wait(); | 126 abort_association_complete_.Wait(); |
| 126 } | 127 } |
| 127 | 128 |
| 128 } | 129 } |
| 129 | 130 |
| 130 StartDoneImpl(ABORTED, STOPPING, SyncError()); | 131 StartDoneImpl(ABORTED, STOPPING, csync::SyncError()); |
| 131 } | 132 } |
| 132 | 133 |
| 133 namespace { | 134 namespace { |
| 134 // Helper function that signals the UI thread once the StopAssociation task | 135 // Helper function that signals the UI thread once the StopAssociation task |
| 135 // has finished completing (this task is queued after the StopAssociation task). | 136 // has finished completing (this task is queued after the StopAssociation task). |
| 136 void SignalCallback(base::WaitableEvent* wait_event) { | 137 void SignalCallback(base::WaitableEvent* wait_event) { |
| 137 wait_event->Signal(); | 138 wait_event->Signal(); |
| 138 } | 139 } |
| 139 } // namespace | 140 } // namespace |
| 140 | 141 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 | 278 |
| 278 bool NonFrontendDataTypeController::StartModels() { | 279 bool NonFrontendDataTypeController::StartModels() { |
| 279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 280 DCHECK_EQ(state_, MODEL_STARTING); | 281 DCHECK_EQ(state_, MODEL_STARTING); |
| 281 // By default, no additional services need to be started before we can proceed | 282 // By default, no additional services need to be started before we can proceed |
| 282 // with model association, so do nothing. | 283 // with model association, so do nothing. |
| 283 return true; | 284 return true; |
| 284 } | 285 } |
| 285 | 286 |
| 286 void NonFrontendDataTypeController::StartFailed(StartResult result, | 287 void NonFrontendDataTypeController::StartFailed(StartResult result, |
| 287 const SyncError& error) { | 288 const csync::SyncError& error) { |
| 288 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | 289 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 289 | 290 |
| 290 if (IsUnrecoverableResult(result)) | 291 if (IsUnrecoverableResult(result)) |
| 291 RecordUnrecoverableError(FROM_HERE, "StartFailed"); | 292 RecordUnrecoverableError(FROM_HERE, "StartFailed"); |
| 292 StopAssociation(); | 293 StopAssociation(); |
| 293 StartDone(result, | 294 StartDone(result, |
| 294 result == ASSOCIATION_FAILED ? DISABLED : NOT_RUNNING, | 295 result == ASSOCIATION_FAILED ? DISABLED : NOT_RUNNING, |
| 295 error); | 296 error); |
| 296 } | 297 } |
| 297 | 298 |
| 298 void NonFrontendDataTypeController::StartDone( | 299 void NonFrontendDataTypeController::StartDone( |
| 299 DataTypeController::StartResult result, | 300 DataTypeController::StartResult result, |
| 300 DataTypeController::State new_state, | 301 DataTypeController::State new_state, |
| 301 const SyncError& error) { | 302 const csync::SyncError& error) { |
| 302 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | 303 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 303 abort_association_complete_.Signal(); | 304 abort_association_complete_.Signal(); |
| 304 base::AutoLock lock(abort_association_lock_); | 305 base::AutoLock lock(abort_association_lock_); |
| 305 if (!abort_association_) { | 306 if (!abort_association_) { |
| 306 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 307 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 307 base::Bind(&NonFrontendDataTypeController::StartDoneImpl, | 308 base::Bind(&NonFrontendDataTypeController::StartDoneImpl, |
| 308 this, | 309 this, |
| 309 result, | 310 result, |
| 310 new_state, | 311 new_state, |
| 311 error)); | 312 error)); |
| 312 } | 313 } |
| 313 } | 314 } |
| 314 | 315 |
| 315 void NonFrontendDataTypeController::StartDoneImpl( | 316 void NonFrontendDataTypeController::StartDoneImpl( |
| 316 DataTypeController::StartResult result, | 317 DataTypeController::StartResult result, |
| 317 DataTypeController::State new_state, | 318 DataTypeController::State new_state, |
| 318 const SyncError& error) { | 319 const csync::SyncError& error) { |
| 319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 320 // It's possible to have StartDoneImpl called first from the UI thread | 321 // It's possible to have StartDoneImpl called first from the UI thread |
| 321 // (due to Stop being called) and then posted from the non-UI thread. In | 322 // (due to Stop being called) and then posted from the non-UI thread. In |
| 322 // this case, we drop the second call because we've already been stopped. | 323 // this case, we drop the second call because we've already been stopped. |
| 323 if (state_ == NOT_RUNNING) { | 324 if (state_ == NOT_RUNNING) { |
| 324 DCHECK(start_callback_.is_null()); | 325 DCHECK(start_callback_.is_null()); |
| 325 return; | 326 return; |
| 326 } | 327 } |
| 327 | 328 |
| 328 state_ = new_state; | 329 state_ = new_state; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 abort_association_complete_.Signal(); | 433 abort_association_complete_.Signal(); |
| 433 return; | 434 return; |
| 434 } | 435 } |
| 435 start_association_called_.Signal(); | 436 start_association_called_.Signal(); |
| 436 CreateSyncComponents(); | 437 CreateSyncComponents(); |
| 437 } | 438 } |
| 438 | 439 |
| 439 DCHECK_EQ(state_, ASSOCIATING); | 440 DCHECK_EQ(state_, ASSOCIATING); |
| 440 | 441 |
| 441 if (!model_associator_->CryptoReadyIfNecessary()) { | 442 if (!model_associator_->CryptoReadyIfNecessary()) { |
| 442 StartFailed(NEEDS_CRYPTO, SyncError()); | 443 StartFailed(NEEDS_CRYPTO, csync::SyncError()); |
| 443 return; | 444 return; |
| 444 } | 445 } |
| 445 | 446 |
| 446 bool sync_has_nodes = false; | 447 bool sync_has_nodes = false; |
| 447 if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) { | 448 if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) { |
| 448 SyncError error(FROM_HERE, "Failed to load sync nodes", type()); | 449 csync::SyncError error(FROM_HERE, "Failed to load sync nodes", type()); |
| 449 StartFailed(UNRECOVERABLE_ERROR, error); | 450 StartFailed(UNRECOVERABLE_ERROR, error); |
| 450 return; | 451 return; |
| 451 } | 452 } |
| 452 | 453 |
| 453 base::TimeTicks start_time = base::TimeTicks::Now(); | 454 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 454 SyncError error; | 455 csync::SyncError error; |
| 455 error = model_associator_->AssociateModels(); | 456 error = model_associator_->AssociateModels(); |
| 456 // TODO(lipalani): crbug.com/122690 - handle abort. | 457 // TODO(lipalani): crbug.com/122690 - handle abort. |
| 457 RecordAssociationTime(base::TimeTicks::Now() - start_time); | 458 RecordAssociationTime(base::TimeTicks::Now() - start_time); |
| 458 if (error.IsSet()) { | 459 if (error.IsSet()) { |
| 459 StartFailed(ASSOCIATION_FAILED, error); | 460 StartFailed(ASSOCIATION_FAILED, error); |
| 460 return; | 461 return; |
| 461 } | 462 } |
| 462 | 463 |
| 463 profile_sync_service_->ActivateDataType(type(), model_safe_group(), | 464 profile_sync_service_->ActivateDataType(type(), model_safe_group(), |
| 464 change_processor()); | 465 change_processor()); |
| 465 StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING, SyncError()); | 466 StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING, csync::SyncError()); |
| 466 } | 467 } |
| 467 | 468 |
| 468 bool NonFrontendDataTypeController::StopAssociationAsync() { | 469 bool NonFrontendDataTypeController::StopAssociationAsync() { |
| 469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 470 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 470 DCHECK_EQ(state(), STOPPING); | 471 DCHECK_EQ(state(), STOPPING); |
| 471 if (PostTaskOnBackendThread( | 472 if (PostTaskOnBackendThread( |
| 472 FROM_HERE, | 473 FROM_HERE, |
| 473 base::Bind( | 474 base::Bind( |
| 474 &NonFrontendDataTypeController::StopAssociation, this))) { | 475 &NonFrontendDataTypeController::StopAssociation, this))) { |
| 475 // The remote thread will hold on to a reference to this object until | 476 // The remote thread will hold on to a reference to this object until |
| (...skipping 12 matching lines...) Expand all Loading... |
| 488 return true; | 489 return true; |
| 489 } | 490 } |
| 490 } | 491 } |
| 491 return false; | 492 return false; |
| 492 } | 493 } |
| 493 | 494 |
| 494 void NonFrontendDataTypeController::StopAssociation() { | 495 void NonFrontendDataTypeController::StopAssociation() { |
| 495 DCHECK(!HasOneRef()); | 496 DCHECK(!HasOneRef()); |
| 496 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | 497 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 497 if (model_associator_.get()) { | 498 if (model_associator_.get()) { |
| 498 SyncError error; // Not used. | 499 csync::SyncError error; // Not used. |
| 499 error = model_associator_->DisassociateModels(); | 500 error = model_associator_->DisassociateModels(); |
| 500 } | 501 } |
| 501 model_associator_.reset(); | 502 model_associator_.reset(); |
| 502 change_processor_.reset(); | 503 change_processor_.reset(); |
| 503 } | 504 } |
| 504 | 505 |
| 505 } // namespace browser_sync | 506 } // namespace browser_sync |
| OLD | NEW |