Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: chrome/browser/sync/glue/autofill_data_type_controller.cc

Issue 6811003: [Sync] Make generic non-frontend thread datatype controller. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Copy paste :( Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/autofill_data_type_controller.h" 5 #include "chrome/browser/sync/glue/autofill_data_type_controller.h"
6 6
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h" 7 #include "base/metrics/histogram.h"
9 #include "base/task.h" 8 #include "base/task.h"
10 #include "base/time.h"
11 #include "chrome/browser/profiles/profile.h" 9 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/sync/glue/autofill_change_processor.h"
13 #include "chrome/browser/sync/glue/autofill_model_associator.h"
14 #include "chrome/browser/sync/profile_sync_factory.h" 10 #include "chrome/browser/sync/profile_sync_factory.h"
15 #include "chrome/browser/sync/profile_sync_service.h" 11 #include "chrome/browser/sync/profile_sync_service.h"
16 #include "chrome/browser/webdata/web_data_service.h" 12 #include "chrome/browser/webdata/web_data_service.h"
17 #include "content/browser/browser_thread.h" 13 #include "content/browser/browser_thread.h"
18 #include "content/common/notification_service.h" 14 #include "content/common/notification_service.h"
15 #include "content/common/notification_source.h"
16 #include "content/common/notification_type.h"
19 17
20 namespace browser_sync { 18 namespace browser_sync {
21 19
22 AutofillDataTypeController::AutofillDataTypeController( 20 AutofillDataTypeController::AutofillDataTypeController(
23 ProfileSyncFactory* profile_sync_factory, 21 ProfileSyncFactory* profile_sync_factory,
24 Profile* profile, 22 Profile* profile)
25 ProfileSyncService* sync_service) 23 : NonFrontendDataTypeController(profile_sync_factory,
26 : profile_sync_factory_(profile_sync_factory), 24 profile),
27 profile_(profile), 25 personal_data_(NULL) {
28 sync_service_(sync_service),
29 state_(NOT_RUNNING),
30 personal_data_(NULL),
31 abort_association_(false),
32 abort_association_complete_(false, false),
33 datatype_stopped_(false, false) {
34 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
35 DCHECK(profile_sync_factory);
36 DCHECK(profile);
37 DCHECK(sync_service);
38 } 26 }
39 27
40 AutofillDataTypeController::~AutofillDataTypeController() { 28 AutofillDataTypeController::~AutofillDataTypeController() {
41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 29 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
42
43 // TODO(zea): remove once crbug.com/61804 is resolved.
44 CHECK_EQ(state_, NOT_RUNNING) << "AutofillDataTypeController destroyed "
45 << "without being stopped.";
46 CHECK(!change_processor_.get()) << "AutofillDataTypeController destroyed "
47 << "while holding a change processor.";
48 } 30 }
49 31
50 void AutofillDataTypeController::Start(StartCallback* start_callback) { 32 bool AutofillDataTypeController::StartModels() {
51 VLOG(1) << "Starting autofill data controller.";
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
53 DCHECK(start_callback); 34 DCHECK_EQ(state(), MODEL_STARTING);
54 if (state() != NOT_RUNNING) {
55 start_callback->Run(BUSY, FROM_HERE);
56 delete start_callback;
57 return;
58 }
59
60 start_callback_.reset(start_callback);
61 abort_association_ = false;
62
63 // Waiting for the personal data is subtle: we do this as the PDM resets 35 // Waiting for the personal data is subtle: we do this as the PDM resets
64 // its cache of unique IDs once it gets loaded. If we were to proceed with 36 // its cache of unique IDs once it gets loaded. If we were to proceed with
65 // association, the local ids in the mappings would wind up colliding. 37 // association, the local ids in the mappings would wind up colliding.
66 personal_data_ = profile_->GetPersonalDataManager(); 38 personal_data_ = profile()->GetPersonalDataManager();
67 if (!personal_data_->IsDataLoaded()) { 39 if (!personal_data_->IsDataLoaded()) {
68 set_state(MODEL_STARTING);
69 personal_data_->SetObserver(this); 40 personal_data_->SetObserver(this);
70 return; 41 return false;
71 } 42 }
72 43
73 ContinueStartAfterPersonalDataLoaded(); 44 web_data_service_ = profile()->GetWebDataService(Profile::IMPLICIT_ACCESS);
45 if (web_data_service_.get() && web_data_service_->IsDatabaseLoaded()) {
46 return true;
47 } else {
48 notification_registrar_.Add(this, NotificationType::WEB_DATABASE_LOADED,
49 NotificationService::AllSources());
50 return false;
51 }
74 } 52 }
75 53
76 void AutofillDataTypeController::ContinueStartAfterPersonalDataLoaded() { 54 void AutofillDataTypeController::OnPersonalDataLoaded() {
77 web_data_service_ = profile_->GetWebDataService(Profile::IMPLICIT_ACCESS); 55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
56 DCHECK_EQ(state(), MODEL_STARTING);
57 personal_data_->RemoveObserver(this);
58 web_data_service_ = profile()->GetWebDataService(Profile::IMPLICIT_ACCESS);
78 if (web_data_service_.get() && web_data_service_->IsDatabaseLoaded()) { 59 if (web_data_service_.get() && web_data_service_->IsDatabaseLoaded()) {
79 set_state(ASSOCIATING); 60 set_state(ASSOCIATING);
80 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 61 if (!StartAssociationAsync()) {
81 NewRunnableMethod( 62 StartDoneImpl(ASSOCIATION_FAILED, NOT_RUNNING, FROM_HERE);
82 this, 63 }
83 &AutofillDataTypeController::StartImpl));
84 } else { 64 } else {
85 set_state(MODEL_STARTING);
86 notification_registrar_.Add(this, NotificationType::WEB_DATABASE_LOADED, 65 notification_registrar_.Add(this, NotificationType::WEB_DATABASE_LOADED,
87 NotificationService::AllSources()); 66 NotificationService::AllSources());
88 } 67 }
89 } 68 }
90 69
91 void AutofillDataTypeController::OnPersonalDataLoaded() {
92 DCHECK_EQ(state_, MODEL_STARTING);
93 personal_data_->RemoveObserver(this);
94 ContinueStartAfterPersonalDataLoaded();
95 }
96
97 void AutofillDataTypeController::Observe(NotificationType type, 70 void AutofillDataTypeController::Observe(NotificationType type,
98 const NotificationSource& source, 71 const NotificationSource& source,
99 const NotificationDetails& details) { 72 const NotificationDetails& details) {
100 VLOG(1) << "Web database loaded observed."; 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 DCHECK_EQ(state(), MODEL_STARTING);
101 notification_registrar_.RemoveAll(); 75 notification_registrar_.RemoveAll();
102 set_state(ASSOCIATING); 76 set_state(ASSOCIATING);
103 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 77 if (!StartAssociationAsync()) {
104 NewRunnableMethod( 78 StartDoneImpl(ASSOCIATION_FAILED, NOT_RUNNING, FROM_HERE);
105 this, 79 }
106 &AutofillDataTypeController::StartImpl));
107 } 80 }
108 81
109 // TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of 82 bool AutofillDataTypeController::StartAssociationAsync() {
110 // distinguishing chrome shutdown from sync shutdown, we should be able to avoid
111 // this (http://crbug.com/55662). Further, all this functionality should be
112 // abstracted to a higher layer, where we could ensure all datatypes are doing
113 // the same thing (http://crbug.com/76232).
114 void AutofillDataTypeController::Stop() {
115 VLOG(1) << "Stopping autofill data type controller.";
116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84 DCHECK_EQ(state(), ASSOCIATING);
85 return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
86 NewRunnableMethod(
87 this,
88 &AutofillDataTypeController::StartAssociation));
89 }
117 90
118 // If Stop() is called while Start() is waiting for association to 91 void AutofillDataTypeController::CreateSyncComponents() {
119 // complete, we need to abort the association and wait for the DB 92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
120 // thread to finish the StartImpl() task. 93 DCHECK_EQ(state(), ASSOCIATING);
121 if (state_ == ASSOCIATING) { 94 ProfileSyncFactory::SyncComponents sync_components =
122 { 95 profile_sync_factory()->
123 base::AutoLock lock(abort_association_lock_); 96 CreateAutofillSyncComponents(
124 abort_association_ = true; 97 profile_sync_service(),
125 if (model_associator_.get()) 98 web_data_service_->GetDatabase(),
126 model_associator_->AbortAssociation(); 99 personal_data_,
127 } 100 this);
128 // Wait for the model association to abort. 101 set_model_associator(sync_components.model_associator);
129 abort_association_complete_.Wait(); 102 set_change_processor(sync_components.change_processor);
130 StartDoneImpl(ABORTED, STOPPING, FROM_HERE); 103 }
131 }
132 104
133 // If Stop() is called while Start() is waiting for the personal 105 void AutofillDataTypeController::StopModels() {
134 // data manager or web data service to load, abort the start. 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
135 if (state_ == MODEL_STARTING) 107 DCHECK(state() == STOPPING || state() == NOT_RUNNING);
136 StartDoneImpl(ABORTED, STOPPING, FROM_HERE);
137
138 DCHECK(!start_callback_.get());
139
140 // Deactivate the change processor on the UI thread. We dont want to listen
141 // for any more changes or process them from server.
142 notification_registrar_.RemoveAll(); 108 notification_registrar_.RemoveAll();
143 personal_data_->RemoveObserver(this); 109 personal_data_->RemoveObserver(this);
144 if (change_processor_ != NULL && change_processor_->IsRunning())
145 sync_service_->DeactivateDataType(this, change_processor_.get());
146
147 set_state(NOT_RUNNING);
148 if (BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
149 NewRunnableMethod(
150 this,
151 &AutofillDataTypeController::StopImpl))) {
152 // We need to ensure the data type has fully stoppped before continuing. In
153 // particular, during shutdown we may attempt to destroy the
154 // profile_sync_service before we've removed its observers (BUG 61804).
155 datatype_stopped_.Wait();
156 } else if (change_processor_.get()) {
157 // TODO(zea): remove once crbug.com/61804 is resolved.
158 LOG(FATAL) << "AutofillDataTypeController::Stop() called after DB thread"
159 << " killed.";
160 }
161 CHECK(!change_processor_.get()) << "AutofillChangeProcessor not released.";
162 } 110 }
163 111
164 bool AutofillDataTypeController::enabled() { 112 bool AutofillDataTypeController::StopAssociationAsync() {
165 return true; 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114 DCHECK_EQ(state(), STOPPING);
115 return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
116 NewRunnableMethod(
117 this,
118 &AutofillDataTypeController::StopAssociation));
166 } 119 }
167 120
168 syncable::ModelType AutofillDataTypeController::type() const { 121 syncable::ModelType AutofillDataTypeController::type() const {
169 return syncable::AUTOFILL; 122 return syncable::AUTOFILL;
170 } 123 }
171 124
172 browser_sync::ModelSafeGroup AutofillDataTypeController::model_safe_group() 125 browser_sync::ModelSafeGroup AutofillDataTypeController::model_safe_group()
173 const { 126 const {
174 return browser_sync::GROUP_DB; 127 return browser_sync::GROUP_DB;
175 } 128 }
176 129
177 std::string AutofillDataTypeController::name() const { 130 void AutofillDataTypeController::RecordUnrecoverableError(
178 // For logging only.
179 return "autofill";
180 }
181
182 DataTypeController::State AutofillDataTypeController::state() const {
183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
184 return state_;
185 }
186
187 ProfileSyncFactory::SyncComponents
188 AutofillDataTypeController::CreateSyncComponents(
189 ProfileSyncService* profile_sync_service,
190 WebDatabase* web_database,
191 PersonalDataManager* personal_data,
192 browser_sync::UnrecoverableErrorHandler* error_handler) {
193 return profile_sync_factory_->CreateAutofillSyncComponents(
194 profile_sync_service,
195 web_database,
196 personal_data,
197 this);
198 }
199
200 void AutofillDataTypeController::StartImpl() {
201 VLOG(1) << "Autofill data type controller StartImpl called.";
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
203 // No additional services need to be started before we can proceed
204 // with model association.
205 {
206 base::AutoLock lock(abort_association_lock_);
207 if (abort_association_) {
208 abort_association_complete_.Signal();
209 return;
210 }
211 ProfileSyncFactory::SyncComponents sync_components =
212 CreateSyncComponents(
213 sync_service_,
214 web_data_service_->GetDatabase(),
215 profile_->GetPersonalDataManager(),
216 this);
217 model_associator_.reset(sync_components.model_associator);
218 change_processor_.reset(sync_components.change_processor);
219 }
220
221 if (!model_associator_->CryptoReadyIfNecessary()) {
222 StartFailed(NEEDS_CRYPTO);
223 return;
224 }
225
226 bool sync_has_nodes = false;
227 if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
228 StartFailed(UNRECOVERABLE_ERROR);
229 return;
230 }
231
232 base::TimeTicks start_time = base::TimeTicks::Now();
233 bool merge_success = model_associator_->AssociateModels();
234 UMA_HISTOGRAM_TIMES("Sync.AutofillAssociationTime",
235 base::TimeTicks::Now() - start_time);
236 VLOG(1) << "Autofill association time: " <<
237 (base::TimeTicks::Now() - start_time).InSeconds();
238 if (!merge_success) {
239 StartFailed(ASSOCIATION_FAILED);
240 return;
241 }
242
243 sync_service_->ActivateDataType(this, change_processor_.get());
244 StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING);
245 }
246
247 void AutofillDataTypeController::StartDone(
248 DataTypeController::StartResult result,
249 DataTypeController::State new_state) {
250 VLOG(1) << "Autofill data type controller StartDone called.";
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
252
253 abort_association_complete_.Signal();
254 base::AutoLock lock(abort_association_lock_);
255 if (!abort_association_) {
256 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
257 NewRunnableMethod(
258 this,
259 &AutofillDataTypeController::StartDoneImpl,
260 result,
261 new_state,
262 FROM_HERE));
263 }
264 }
265
266 void AutofillDataTypeController::StartDoneImpl(
267 DataTypeController::StartResult result,
268 DataTypeController::State new_state,
269 const tracked_objects::Location& location) {
270 VLOG(1) << "Autofill data type controller StartDoneImpl called.";
271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
272
273 set_state(new_state);
274 start_callback_->Run(result, location);
275 start_callback_.reset();
276
277 if (result == UNRECOVERABLE_ERROR || result == ASSOCIATION_FAILED) {
278 UMA_HISTOGRAM_ENUMERATION("Sync.AutofillStartFailures",
279 result,
280 MAX_START_RESULT);
281 }
282 }
283
284 void AutofillDataTypeController::StopImpl() {
285 VLOG(1) << "Autofill data type controller StopImpl called.";
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
287
288 if (model_associator_ != NULL)
289 model_associator_->DisassociateModels();
290
291 change_processor_.reset();
292 model_associator_.reset();
293
294 datatype_stopped_.Signal();
295 }
296
297 void AutofillDataTypeController::StartFailed(StartResult result) {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
299 change_processor_.reset();
300 model_associator_.reset();
301 StartDone(result, NOT_RUNNING);
302 }
303
304 void AutofillDataTypeController::OnUnrecoverableError(
305 const tracked_objects::Location& from_here, 131 const tracked_objects::Location& from_here,
306 const std::string& message) { 132 const std::string& message) {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 133 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
308 BrowserThread::PostTask(
309 BrowserThread::UI, FROM_HERE,
310 NewRunnableMethod(this,
311 &AutofillDataTypeController::OnUnrecoverableErrorImpl,
312 from_here, message));
313 UMA_HISTOGRAM_COUNTS("Sync.AutofillRunFailures", 1); 134 UMA_HISTOGRAM_COUNTS("Sync.AutofillRunFailures", 1);
314 } 135 }
315 136
316 void AutofillDataTypeController::OnUnrecoverableErrorImpl( 137 void AutofillDataTypeController::RecordAssociationTime(base::TimeDelta time) {
317 const tracked_objects::Location& from_here, 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
318 const std::string& message) { 139 UMA_HISTOGRAM_TIMES("Sync.AutofillAssociationTime", time);
140 }
141
142 void AutofillDataTypeController::RecordStartFailure(StartResult result) {
319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
320 sync_service_->OnUnrecoverableError(from_here, message); 144 UMA_HISTOGRAM_ENUMERATION("Sync.AutofillStartFailures",
145 result,
146 MAX_START_RESULT);
147 }
148
149 PersonalDataManager* AutofillDataTypeController::personal_data() const {
150 return personal_data_;
151 }
152
153 WebDataService* AutofillDataTypeController::web_data_service() const {
154 return web_data_service_;
321 } 155 }
322 156
323 } // namespace browser_sync 157 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698