Home | History | Annotate | Download | only in glue
      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/autofill_data_type_controller.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/metrics/histogram.h"
      9 #include "base/task.h"
     10 #include "base/time.h"
     11 #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"
     15 #include "chrome/browser/sync/profile_sync_service.h"
     16 #include "chrome/browser/webdata/web_data_service.h"
     17 #include "content/browser/browser_thread.h"
     18 #include "content/common/notification_service.h"
     19 
     20 namespace browser_sync {
     21 
     22 AutofillDataTypeController::AutofillDataTypeController(
     23     ProfileSyncFactory* profile_sync_factory,
     24     Profile* profile,
     25     ProfileSyncService* sync_service)
     26     : profile_sync_factory_(profile_sync_factory),
     27       profile_(profile),
     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 }
     39 
     40 AutofillDataTypeController::~AutofillDataTypeController() {
     41   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 }
     49 
     50 void AutofillDataTypeController::Start(StartCallback* start_callback) {
     51   VLOG(1) << "Starting autofill data controller.";
     52   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     53   DCHECK(start_callback);
     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
     64   // 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.
     66   personal_data_ = profile_->GetPersonalDataManager();
     67   if (!personal_data_->IsDataLoaded()) {
     68     set_state(MODEL_STARTING);
     69     personal_data_->SetObserver(this);
     70     return;
     71   }
     72 
     73   ContinueStartAfterPersonalDataLoaded();
     74 }
     75 
     76 void AutofillDataTypeController::ContinueStartAfterPersonalDataLoaded() {
     77   web_data_service_ = profile_->GetWebDataService(Profile::IMPLICIT_ACCESS);
     78   if (web_data_service_.get() && web_data_service_->IsDatabaseLoaded()) {
     79     set_state(ASSOCIATING);
     80     BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
     81                             NewRunnableMethod(
     82                                 this,
     83                                 &AutofillDataTypeController::StartImpl));
     84   } else {
     85     set_state(MODEL_STARTING);
     86     notification_registrar_.Add(this, NotificationType::WEB_DATABASE_LOADED,
     87                                 NotificationService::AllSources());
     88   }
     89 }
     90 
     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,
     98                                          const NotificationSource& source,
     99                                          const NotificationDetails& details) {
    100   VLOG(1) << "Web database loaded observed.";
    101   notification_registrar_.RemoveAll();
    102   set_state(ASSOCIATING);
    103   BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
    104                           NewRunnableMethod(
    105                               this,
    106                               &AutofillDataTypeController::StartImpl));
    107 }
    108 
    109 // TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of
    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));
    117 
    118   // If Stop() is called while Start() is waiting for association to
    119   // complete, we need to abort the association and wait for the DB
    120   // thread to finish the StartImpl() task.
    121   if (state_ == ASSOCIATING) {
    122     {
    123       base::AutoLock lock(abort_association_lock_);
    124       abort_association_ = true;
    125       if (model_associator_.get())
    126         model_associator_->AbortAssociation();
    127     }
    128     // Wait for the model association to abort.
    129     abort_association_complete_.Wait();
    130     StartDoneImpl(ABORTED, STOPPING, FROM_HERE);
    131   }
    132 
    133   // If Stop() is called while Start() is waiting for the personal
    134   // data manager or web data service to load, abort the start.
    135   if (state_ == MODEL_STARTING)
    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();
    143   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 }
    163 
    164 bool AutofillDataTypeController::enabled() {
    165   return true;
    166 }
    167 
    168 syncable::ModelType AutofillDataTypeController::type() const {
    169   return syncable::AUTOFILL;
    170 }
    171 
    172 browser_sync::ModelSafeGroup AutofillDataTypeController::model_safe_group()
    173     const {
    174   return browser_sync::GROUP_DB;
    175 }
    176 
    177 std::string AutofillDataTypeController::name() const {
    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,
    306     const std::string& message) {
    307   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);
    314 }
    315 
    316 void AutofillDataTypeController::OnUnrecoverableErrorImpl(
    317     const tracked_objects::Location& from_here,
    318     const std::string& message) {
    319   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    320   sync_service_->OnUnrecoverableError(from_here, message);
    321 }
    322 
    323 }  // namespace browser_sync
    324