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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/sync/glue/frontend_data_type_controller.h" 6 7 #include "base/logging.h" 8 #include "chrome/browser/profiles/profile.h" 9 #include "chrome/browser/sync/glue/change_processor.h" 10 #include "chrome/browser/sync/glue/model_associator.h" 11 #include "chrome/browser/sync/profile_sync_factory.h" 12 #include "chrome/browser/sync/profile_sync_service.h" 13 #include "chrome/browser/sync/syncable/model_type.h" 14 #include "content/browser/browser_thread.h" 15 16 namespace browser_sync { 17 18 FrontendDataTypeController::FrontendDataTypeController() 19 : profile_sync_factory_(NULL), 20 profile_(NULL), 21 sync_service_(NULL) {} 22 23 FrontendDataTypeController::FrontendDataTypeController( 24 ProfileSyncFactory* profile_sync_factory, 25 Profile* profile, 26 ProfileSyncService* sync_service) 27 : profile_sync_factory_(profile_sync_factory), 28 profile_(profile), 29 sync_service_(sync_service), 30 state_(NOT_RUNNING) { 31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 32 DCHECK(profile_sync_factory); 33 DCHECK(profile); 34 DCHECK(sync_service); 35 } 36 37 FrontendDataTypeController::~FrontendDataTypeController() { 38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 39 } 40 41 void FrontendDataTypeController::Start(StartCallback* start_callback) { 42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 43 DCHECK(start_callback); 44 if (state_ != NOT_RUNNING) { 45 start_callback->Run(BUSY, FROM_HERE); 46 delete start_callback; 47 return; 48 } 49 50 start_callback_.reset(start_callback); 51 52 state_ = MODEL_STARTING; 53 if (!StartModels()) { 54 // If we are waiting for some external service to load before associating 55 // or we failed to start the models, we exit early. state_ will control 56 // what we perform next. 57 DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING); 58 return; 59 } 60 61 state_ = ASSOCIATING; 62 if (!Associate()) { 63 // We failed to associate and are aborting. 64 DCHECK_EQ(state_, NOT_RUNNING); 65 return; 66 } 67 DCHECK_EQ(state_, RUNNING); 68 } 69 70 bool FrontendDataTypeController::StartModels() { 71 DCHECK_EQ(state_, MODEL_STARTING); 72 // By default, no additional services need to be started before we can proceed 73 // with model association. 74 return true; 75 } 76 77 bool FrontendDataTypeController::Associate() { 78 DCHECK_EQ(state_, ASSOCIATING); 79 CreateSyncComponents(); 80 81 if (!model_associator_->CryptoReadyIfNecessary()) { 82 StartFailed(NEEDS_CRYPTO, FROM_HERE); 83 return false; 84 } 85 86 bool sync_has_nodes = false; 87 if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) { 88 StartFailed(UNRECOVERABLE_ERROR, FROM_HERE); 89 return false; 90 } 91 92 base::TimeTicks start_time = base::TimeTicks::Now(); 93 bool merge_success = model_associator_->AssociateModels(); 94 RecordAssociationTime(base::TimeTicks::Now() - start_time); 95 if (!merge_success) { 96 StartFailed(ASSOCIATION_FAILED, FROM_HERE); 97 return false; 98 } 99 100 sync_service_->ActivateDataType(this, change_processor_.get()); 101 state_ = RUNNING; 102 FinishStart(!sync_has_nodes ? OK_FIRST_RUN : OK, FROM_HERE); 103 return true; 104 } 105 106 void FrontendDataTypeController::Stop() { 107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 108 // If Stop() is called while Start() is waiting for the datatype model to 109 // load, abort the start. 110 if (state_ == MODEL_STARTING) 111 FinishStart(ABORTED, FROM_HERE); 112 DCHECK(!start_callback_.get()); 113 114 CleanupState(); 115 116 if (change_processor_ != NULL) 117 sync_service_->DeactivateDataType(this, change_processor_.get()); 118 119 if (model_associator_ != NULL) 120 model_associator_->DisassociateModels(); 121 122 change_processor_.reset(); 123 model_associator_.reset(); 124 125 state_ = NOT_RUNNING; 126 } 127 128 void FrontendDataTypeController::CleanupState() { 129 // Do nothing by default. 130 } 131 132 browser_sync::ModelSafeGroup FrontendDataTypeController::model_safe_group() 133 const { 134 return browser_sync::GROUP_UI; 135 } 136 137 std::string FrontendDataTypeController::name() const { 138 // For logging only. 139 return syncable::ModelTypeToString(type()); 140 } 141 142 DataTypeController::State FrontendDataTypeController::state() const { 143 return state_; 144 } 145 146 void FrontendDataTypeController::OnUnrecoverableError( 147 const tracked_objects::Location& from_here, const std::string& message) { 148 // The ProfileSyncService will invoke our Stop() method in response to this. 149 RecordUnrecoverableError(from_here, message); 150 sync_service_->OnUnrecoverableError(from_here, message); 151 } 152 153 void FrontendDataTypeController::FinishStart(StartResult result, 154 const tracked_objects::Location& location) { 155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 156 start_callback_->Run(result, location); 157 start_callback_.reset(); 158 } 159 160 void FrontendDataTypeController::StartFailed(StartResult result, 161 const tracked_objects::Location& location) { 162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 163 CleanupState(); 164 model_associator_.reset(); 165 change_processor_.reset(); 166 state_ = NOT_RUNNING; 167 start_callback_->Run(result, location); 168 start_callback_.reset(); 169 RecordStartFailure(result); 170 } 171 172 } // namespace browser_sync 173