| 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/password_data_type_controller.h" | 5 #include "chrome/browser/sync/glue/password_data_type_controller.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
| 8 #include "base/logging.h" | |
| 9 #include "base/task.h" | 8 #include "base/task.h" |
| 10 #include "base/time.h" | |
| 11 #include "chrome/browser/password_manager/password_store.h" | 9 #include "chrome/browser/password_manager/password_store.h" |
| 12 #include "chrome/browser/profiles/profile.h" | 10 #include "chrome/browser/profiles/profile.h" |
| 13 #include "chrome/browser/sync/glue/password_change_processor.h" | 11 #include "chrome/browser/sync/profile_sync_factory.h" |
| 14 #include "chrome/browser/sync/glue/password_model_associator.h" | |
| 15 #include "chrome/browser/sync/profile_sync_service.h" | 12 #include "chrome/browser/sync/profile_sync_service.h" |
| 16 #include "chrome/browser/sync/profile_sync_factory.h" | 13 #include "chrome/browser/webdata/web_data_service.h" |
| 17 #include "content/browser/browser_thread.h" | 14 #include "content/browser/browser_thread.h" |
| 18 | 15 |
| 19 namespace browser_sync { | 16 namespace browser_sync { |
| 20 | 17 |
| 21 PasswordDataTypeController::PasswordDataTypeController( | 18 PasswordDataTypeController::PasswordDataTypeController( |
| 22 ProfileSyncFactory* profile_sync_factory, | 19 ProfileSyncFactory* profile_sync_factory, |
| 23 Profile* profile, | 20 Profile* profile, |
| 24 ProfileSyncService* sync_service) | 21 ProfileSyncService* sync_service) |
| 25 : profile_sync_factory_(profile_sync_factory), | 22 : NonFrontendDataTypeController(profile_sync_factory, |
| 26 profile_(profile), | 23 profile, |
| 27 sync_service_(sync_service), | 24 sync_service) { |
| 28 state_(NOT_RUNNING), | |
| 29 abort_association_(false), | |
| 30 abort_association_complete_(false, false), | |
| 31 datatype_stopped_(false, false) { | |
| 32 DCHECK(profile_sync_factory); | |
| 33 DCHECK(profile); | |
| 34 DCHECK(sync_service); | |
| 35 } | 25 } |
| 36 | 26 |
| 37 PasswordDataTypeController::~PasswordDataTypeController() { | 27 PasswordDataTypeController::~PasswordDataTypeController() { |
| 38 } | 28 } |
| 39 | 29 |
| 40 void PasswordDataTypeController::Start(StartCallback* start_callback) { | 30 bool PasswordDataTypeController::StartModels() { |
| 41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 42 DCHECK(start_callback); | 32 DCHECK_EQ(state_, MODEL_STARTING); |
| 43 if (state_ != NOT_RUNNING) { | |
| 44 start_callback->Run(BUSY, FROM_HERE); | |
| 45 delete start_callback; | |
| 46 return; | |
| 47 } | |
| 48 | |
| 49 password_store_ = profile_->GetPasswordStore(Profile::EXPLICIT_ACCESS); | 33 password_store_ = profile_->GetPasswordStore(Profile::EXPLICIT_ACCESS); |
| 50 if (!password_store_.get()) { | 34 if (!password_store_.get()) { |
| 51 LOG(ERROR) << "PasswordStore not initialized, password datatype controller" | 35 LOG(ERROR) << "PasswordStore not initialized, password datatype controller" |
| 52 << " aborting."; | 36 << " aborting."; |
| 53 state_ = NOT_RUNNING; | 37 StartDoneImpl(ABORTED, NOT_RUNNING, FROM_HERE); |
| 54 start_callback->Run(ABORTED, FROM_HERE); | 38 return false; |
| 55 delete start_callback; | |
| 56 return; | |
| 57 } | 39 } |
| 58 | |
| 59 start_callback_.reset(start_callback); | |
| 60 abort_association_ = false; | |
| 61 set_state(ASSOCIATING); | |
| 62 password_store_->ScheduleTask( | |
| 63 NewRunnableMethod(this, &PasswordDataTypeController::StartImpl)); | |
| 64 } | |
| 65 | |
| 66 // TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of | |
| 67 // distinguishing chrome shutdown from sync shutdown, we should be able to avoid | |
| 68 // this (http://crbug.com/55662). Further, all this functionality should be | |
| 69 // abstracted to a higher layer, where we could ensure all datatypes are doing | |
| 70 // the same thing (http://crbug.com/76232). | |
| 71 void PasswordDataTypeController::Stop() { | |
| 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 73 | |
| 74 // If Stop() is called while Start() is waiting for association to | |
| 75 // complete, we need to abort the association and wait for the PASSWORD | |
| 76 // thread to finish the StartImpl() task. | |
| 77 if (state_ == ASSOCIATING) { | |
| 78 { | |
| 79 base::AutoLock lock(abort_association_lock_); | |
| 80 abort_association_ = true; | |
| 81 if (model_associator_.get()) | |
| 82 model_associator_->AbortAssociation(); | |
| 83 } | |
| 84 // Wait for the model association to abort. | |
| 85 abort_association_complete_.Wait(); | |
| 86 StartDoneImpl(ABORTED, STOPPING); | |
| 87 } | |
| 88 | |
| 89 // If Stop() is called while Start() is waiting for another service to load, | |
| 90 // abort the start. | |
| 91 if (state_ == MODEL_STARTING) | |
| 92 StartDoneImpl(ABORTED, STOPPING); | |
| 93 | |
| 94 DCHECK(!start_callback_.get()); | |
| 95 | |
| 96 if (change_processor_ != NULL) | |
| 97 sync_service_->DeactivateDataType(this, change_processor_.get()); | |
| 98 | |
| 99 set_state(NOT_RUNNING); | |
| 100 DCHECK(password_store_.get()); | |
| 101 password_store_->ScheduleTask( | |
| 102 NewRunnableMethod(this, &PasswordDataTypeController::StopImpl)); | |
| 103 datatype_stopped_.Wait(); | |
| 104 } | |
| 105 | |
| 106 bool PasswordDataTypeController::enabled() { | |
| 107 return true; | 40 return true; |
| 108 } | 41 } |
| 109 | 42 |
| 43 bool PasswordDataTypeController::KickOffAssociation() { |
| 44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 45 DCHECK_EQ(state_, ASSOCIATING); |
| 46 DCHECK(password_store_.get()); |
| 47 password_store_->ScheduleTask( |
| 48 NewRunnableMethod(this, &PasswordDataTypeController::Associate)); |
| 49 return true; |
| 50 } |
| 51 |
| 52 void PasswordDataTypeController::CreateSyncComponents() { |
| 53 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 54 DCHECK_EQ(state_, ASSOCIATING); |
| 55 ProfileSyncFactory::SyncComponents sync_components = |
| 56 profile_sync_factory_->CreatePasswordSyncComponents( |
| 57 sync_service_, |
| 58 password_store_.get(), |
| 59 this); |
| 60 model_associator_.reset(sync_components.model_associator); |
| 61 change_processor_.reset(sync_components.change_processor); |
| 62 } |
| 63 |
| 64 bool PasswordDataTypeController::KickOffDestroy() { |
| 65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 66 DCHECK_EQ(state_, STOPPING); |
| 67 DCHECK(password_store_.get()); |
| 68 password_store_->ScheduleTask( |
| 69 NewRunnableMethod(this, &PasswordDataTypeController::Destroy)); |
| 70 return true; |
| 71 } |
| 72 |
| 110 syncable::ModelType PasswordDataTypeController::type() const { | 73 syncable::ModelType PasswordDataTypeController::type() const { |
| 111 return syncable::PASSWORDS; | 74 return syncable::PASSWORDS; |
| 112 } | 75 } |
| 113 | 76 |
| 114 browser_sync::ModelSafeGroup PasswordDataTypeController::model_safe_group() | 77 browser_sync::ModelSafeGroup PasswordDataTypeController::model_safe_group() |
| 115 const { | 78 const { |
| 116 return browser_sync::GROUP_PASSWORD; | 79 return browser_sync::GROUP_PASSWORD; |
| 117 } | 80 } |
| 118 | 81 |
| 119 std::string PasswordDataTypeController::name() const { | 82 void PasswordDataTypeController::RecordUnrecoverableError( |
| 120 // For logging only. | 83 const tracked_objects::Location& from_here, |
| 121 return "password"; | 84 const std::string& message) { |
| 85 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 86 UMA_HISTOGRAM_COUNTS("Sync.PasswordRunFailures", 1); |
| 122 } | 87 } |
| 123 | 88 |
| 124 DataTypeController::State PasswordDataTypeController::state() const { | 89 void PasswordDataTypeController::RecordAssociationTime(base::TimeDelta time) { |
| 125 return state_; | 90 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 91 UMA_HISTOGRAM_TIMES("Sync.PasswordAssociationTime", time); |
| 126 } | 92 } |
| 127 | 93 |
| 128 void PasswordDataTypeController::StartImpl() { | 94 void PasswordDataTypeController::RecordStartFailure(StartResult result) { |
| 129 // No additional services need to be started before we can proceed | |
| 130 // with model association. | |
| 131 { | |
| 132 base::AutoLock lock(abort_association_lock_); | |
| 133 if (abort_association_) { | |
| 134 abort_association_complete_.Signal(); | |
| 135 return; | |
| 136 } | |
| 137 ProfileSyncFactory::SyncComponents sync_components = | |
| 138 profile_sync_factory_->CreatePasswordSyncComponents( | |
| 139 sync_service_, | |
| 140 password_store_.get(), | |
| 141 this); | |
| 142 model_associator_.reset(sync_components.model_associator); | |
| 143 change_processor_.reset(sync_components.change_processor); | |
| 144 } | |
| 145 | |
| 146 if (!model_associator_->CryptoReadyIfNecessary()) { | |
| 147 StartFailed(NEEDS_CRYPTO); | |
| 148 return; | |
| 149 } | |
| 150 | |
| 151 bool sync_has_nodes = false; | |
| 152 if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) { | |
| 153 StartFailed(UNRECOVERABLE_ERROR); | |
| 154 return; | |
| 155 } | |
| 156 | |
| 157 base::TimeTicks start_time = base::TimeTicks::Now(); | |
| 158 bool merge_success = model_associator_->AssociateModels(); | |
| 159 UMA_HISTOGRAM_TIMES("Sync.PasswordAssociationTime", | |
| 160 base::TimeTicks::Now() - start_time); | |
| 161 if (!merge_success) { | |
| 162 StartFailed(ASSOCIATION_FAILED); | |
| 163 return; | |
| 164 } | |
| 165 | |
| 166 sync_service_->ActivateDataType(this, change_processor_.get()); | |
| 167 StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING); | |
| 168 } | |
| 169 | |
| 170 void PasswordDataTypeController::StartDone( | |
| 171 DataTypeController::StartResult result, | |
| 172 DataTypeController::State new_state) { | |
| 173 abort_association_complete_.Signal(); | |
| 174 base::AutoLock lock(abort_association_lock_); | |
| 175 if (!abort_association_) { | |
| 176 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 177 NewRunnableMethod( | |
| 178 this, | |
| 179 &PasswordDataTypeController::StartDoneImpl, | |
| 180 result, | |
| 181 new_state)); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 void PasswordDataTypeController::StartDoneImpl( | |
| 186 DataTypeController::StartResult result, | |
| 187 DataTypeController::State new_state) { | |
| 188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 189 set_state(new_state); | 96 UMA_HISTOGRAM_ENUMERATION("Sync.PasswordStartFailures", |
| 190 start_callback_->Run(result, FROM_HERE); | 97 result, |
| 191 start_callback_.reset(); | 98 MAX_START_RESULT); |
| 192 } | |
| 193 | |
| 194 void PasswordDataTypeController::StopImpl() { | |
| 195 if (model_associator_ != NULL) | |
| 196 model_associator_->DisassociateModels(); | |
| 197 | |
| 198 change_processor_.reset(); | |
| 199 model_associator_.reset(); | |
| 200 | |
| 201 datatype_stopped_.Signal(); | |
| 202 } | |
| 203 | |
| 204 void PasswordDataTypeController::StartFailed(StartResult result) { | |
| 205 change_processor_.reset(); | |
| 206 model_associator_.reset(); | |
| 207 StartDone(result, NOT_RUNNING); | |
| 208 } | |
| 209 | |
| 210 void PasswordDataTypeController::OnUnrecoverableError( | |
| 211 const tracked_objects::Location& from_here, const std::string& message) { | |
| 212 BrowserThread::PostTask( | |
| 213 BrowserThread::UI, FROM_HERE, | |
| 214 NewRunnableMethod(this, | |
| 215 &PasswordDataTypeController::OnUnrecoverableErrorImpl, | |
| 216 from_here, message)); | |
| 217 } | |
| 218 | |
| 219 void PasswordDataTypeController::OnUnrecoverableErrorImpl( | |
| 220 const tracked_objects::Location& from_here, | |
| 221 const std::string& message) { | |
| 222 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 223 sync_service_->OnUnrecoverableError(from_here, message); | |
| 224 } | 99 } |
| 225 | 100 |
| 226 } // namespace browser_sync | 101 } // namespace browser_sync |
| OLD | NEW |