Home | History | Annotate | Download | only in glue
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sync/glue/shared_change_processor.h"
      6 
      7 #include "chrome/browser/sync/glue/generic_change_processor.h"
      8 #include "chrome/browser/sync/profile_sync_components_factory.h"
      9 #include "chrome/browser/sync/profile_sync_service.h"
     10 #include "content/public/browser/browser_thread.h"
     11 #include "sync/api/sync_change.h"
     12 
     13 using base::AutoLock;
     14 using content::BrowserThread;
     15 
     16 namespace browser_sync {
     17 
     18 SharedChangeProcessor::SharedChangeProcessor()
     19     : disconnected_(false),
     20       type_(syncer::UNSPECIFIED),
     21       sync_service_(NULL),
     22       generic_change_processor_(NULL),
     23       error_handler_(NULL) {
     24   // We're always created on the UI thread.
     25   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     26 }
     27 
     28 SharedChangeProcessor::~SharedChangeProcessor() {
     29   // We can either be deleted when the DTC is destroyed (on UI
     30   // thread), or when the syncer::SyncableService stop's syncing (datatype
     31   // thread).  |generic_change_processor_|, if non-NULL, must be
     32   // deleted on |backend_loop_|.
     33   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     34     if (backend_loop_.get()) {
     35       if (!backend_loop_->DeleteSoon(FROM_HERE, generic_change_processor_)) {
     36         NOTREACHED();
     37       }
     38     } else {
     39       DCHECK(!generic_change_processor_);
     40     }
     41   } else {
     42     DCHECK(backend_loop_.get());
     43     DCHECK(backend_loop_->BelongsToCurrentThread());
     44     delete generic_change_processor_;
     45   }
     46 }
     47 
     48 base::WeakPtr<syncer::SyncableService> SharedChangeProcessor::Connect(
     49     ProfileSyncComponentsFactory* sync_factory,
     50     ProfileSyncService* sync_service,
     51     DataTypeErrorHandler* error_handler,
     52     syncer::ModelType type,
     53     const base::WeakPtr<syncer::SyncMergeResult>& merge_result) {
     54   DCHECK(sync_factory);
     55   DCHECK(sync_service);
     56   DCHECK(error_handler);
     57   DCHECK_NE(type, syncer::UNSPECIFIED);
     58   backend_loop_ = base::MessageLoopProxy::current();
     59   AutoLock lock(monitor_lock_);
     60   if (disconnected_)
     61     return base::WeakPtr<syncer::SyncableService>();
     62   type_ = type;
     63   sync_service_ = sync_service;
     64   error_handler_ = error_handler;
     65   base::WeakPtr<syncer::SyncableService> local_service =
     66       sync_factory->GetSyncableServiceForType(type);
     67   if (!local_service.get()) {
     68     LOG(WARNING) << "SyncableService destroyed before DTC was stopped.";
     69     disconnected_ = true;
     70     return base::WeakPtr<syncer::SyncableService>();
     71   }
     72 
     73   // TODO(zea): Pass |merge_result| to the generic change processor.
     74   generic_change_processor_ =
     75       sync_factory->CreateGenericChangeProcessor(sync_service_,
     76                                                  error_handler,
     77                                                  local_service,
     78                                                  merge_result);
     79   return local_service;
     80 }
     81 
     82 bool SharedChangeProcessor::Disconnect() {
     83   // May be called from any thread.
     84   DVLOG(1) << "Disconnecting change processor.";
     85   AutoLock lock(monitor_lock_);
     86   bool was_connected = !disconnected_;
     87   disconnected_ = true;
     88   error_handler_ = NULL;
     89   return was_connected;
     90 }
     91 
     92 syncer::SyncError SharedChangeProcessor::GetSyncData(
     93     syncer::SyncDataList* current_sync_data) {
     94   DCHECK(backend_loop_.get());
     95   DCHECK(backend_loop_->BelongsToCurrentThread());
     96   AutoLock lock(monitor_lock_);
     97   if (disconnected_) {
     98     syncer::SyncError error(FROM_HERE,
     99                             syncer::SyncError::DATATYPE_ERROR,
    100                             "Change processor disconnected.",
    101                             type_);
    102     return error;
    103   }
    104   return generic_change_processor_->GetSyncDataForType(type_,
    105                                                        current_sync_data);
    106 }
    107 
    108 int SharedChangeProcessor::GetSyncCount() {
    109   DCHECK(backend_loop_.get());
    110   DCHECK(backend_loop_->BelongsToCurrentThread());
    111   AutoLock lock(monitor_lock_);
    112   if (disconnected_) {
    113     LOG(ERROR) << "Change processor disconnected.";
    114     return 0;
    115   }
    116   return generic_change_processor_->GetSyncCountForType(type_);
    117 }
    118 
    119 syncer::SyncError SharedChangeProcessor::ProcessSyncChanges(
    120     const tracked_objects::Location& from_here,
    121     const syncer::SyncChangeList& list_of_changes) {
    122   DCHECK(backend_loop_.get());
    123   DCHECK(backend_loop_->BelongsToCurrentThread());
    124   AutoLock lock(monitor_lock_);
    125   if (disconnected_) {
    126     // The DTC that disconnects us must ensure it posts a StopSyncing task.
    127     // If we reach this, it means it just hasn't executed yet.
    128     syncer::SyncError error(FROM_HERE,
    129                             syncer::SyncError::DATATYPE_ERROR,
    130                             "Change processor disconnected.",
    131                             type_);
    132     return error;
    133   }
    134   return generic_change_processor_->ProcessSyncChanges(
    135       from_here, list_of_changes);
    136 }
    137 
    138 bool SharedChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
    139   DCHECK(backend_loop_.get());
    140   DCHECK(backend_loop_->BelongsToCurrentThread());
    141   AutoLock lock(monitor_lock_);
    142   if (disconnected_) {
    143     LOG(ERROR) << "Change processor disconnected.";
    144     return false;
    145   }
    146   return generic_change_processor_->SyncModelHasUserCreatedNodes(
    147       type_, has_nodes);
    148 }
    149 
    150 bool SharedChangeProcessor::CryptoReadyIfNecessary() {
    151   DCHECK(backend_loop_.get());
    152   DCHECK(backend_loop_->BelongsToCurrentThread());
    153   AutoLock lock(monitor_lock_);
    154   if (disconnected_) {
    155     LOG(ERROR) << "Change processor disconnected.";
    156     return true;  // Otherwise we get into infinite spin waiting.
    157   }
    158   return generic_change_processor_->CryptoReadyIfNecessary(type_);
    159 }
    160 
    161 void SharedChangeProcessor::ActivateDataType(
    162     syncer::ModelSafeGroup model_safe_group) {
    163   DCHECK(backend_loop_.get());
    164   DCHECK(backend_loop_->BelongsToCurrentThread());
    165   AutoLock lock(monitor_lock_);
    166   if (disconnected_) {
    167     LOG(ERROR) << "Change processor disconnected.";
    168     return;
    169   }
    170   sync_service_->ActivateDataType(type_,
    171                                   model_safe_group,
    172                                   generic_change_processor_);
    173 }
    174 
    175 syncer::SyncError SharedChangeProcessor::CreateAndUploadError(
    176     const tracked_objects::Location& location,
    177     const std::string& message) {
    178   AutoLock lock(monitor_lock_);
    179   if (!disconnected_) {
    180     return error_handler_->CreateAndUploadError(location, message, type_);
    181   } else {
    182     return syncer::SyncError(location,
    183                              syncer::SyncError::DATATYPE_ERROR,
    184                              message,
    185                              type_);
    186   }
    187 }
    188 
    189 }  // namespace browser_sync
    190