shared_change_processor.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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
13using base::AutoLock;
14using content::BrowserThread;
15
16namespace browser_sync {
17
18SharedChangeProcessor::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
28SharedChangeProcessor::~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
48base::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    NOTREACHED() << "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
82bool 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
92syncer::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, "Change processor disconnected.", type_);
99    return error;
100  }
101  return generic_change_processor_->GetSyncDataForType(type_,
102                                                       current_sync_data);
103}
104
105int SharedChangeProcessor::GetSyncCount() {
106  DCHECK(backend_loop_.get());
107  DCHECK(backend_loop_->BelongsToCurrentThread());
108  AutoLock lock(monitor_lock_);
109  if (disconnected_) {
110    LOG(ERROR) << "Change processor disconnected.";
111    return 0;
112  }
113  return generic_change_processor_->GetSyncCountForType(type_);
114}
115
116syncer::SyncError SharedChangeProcessor::ProcessSyncChanges(
117    const tracked_objects::Location& from_here,
118    const syncer::SyncChangeList& list_of_changes) {
119  DCHECK(backend_loop_.get());
120  DCHECK(backend_loop_->BelongsToCurrentThread());
121  AutoLock lock(monitor_lock_);
122  if (disconnected_) {
123    // The DTC that disconnects us must ensure it posts a StopSyncing task.
124    // If we reach this, it means it just hasn't executed yet.
125    syncer::SyncError error(FROM_HERE, "Change processor disconnected.", type_);
126    return error;
127  }
128  return generic_change_processor_->ProcessSyncChanges(
129      from_here, list_of_changes);
130}
131
132bool SharedChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
133  DCHECK(backend_loop_.get());
134  DCHECK(backend_loop_->BelongsToCurrentThread());
135  AutoLock lock(monitor_lock_);
136  if (disconnected_) {
137    LOG(ERROR) << "Change processor disconnected.";
138    return false;
139  }
140  return generic_change_processor_->SyncModelHasUserCreatedNodes(
141      type_, has_nodes);
142}
143
144bool SharedChangeProcessor::CryptoReadyIfNecessary() {
145  DCHECK(backend_loop_.get());
146  DCHECK(backend_loop_->BelongsToCurrentThread());
147  AutoLock lock(monitor_lock_);
148  if (disconnected_) {
149    LOG(ERROR) << "Change processor disconnected.";
150    return true;  // Otherwise we get into infinite spin waiting.
151  }
152  return generic_change_processor_->CryptoReadyIfNecessary(type_);
153}
154
155void SharedChangeProcessor::ActivateDataType(
156    syncer::ModelSafeGroup model_safe_group) {
157  DCHECK(backend_loop_.get());
158  DCHECK(backend_loop_->BelongsToCurrentThread());
159  AutoLock lock(monitor_lock_);
160  if (disconnected_) {
161    LOG(ERROR) << "Change processor disconnected.";
162    return;
163  }
164  sync_service_->ActivateDataType(type_,
165                                  model_safe_group,
166                                  generic_change_processor_);
167}
168
169syncer::SyncError SharedChangeProcessor::CreateAndUploadError(
170    const tracked_objects::Location& location,
171    const std::string& message) {
172  AutoLock lock(monitor_lock_);
173  if (!disconnected_) {
174    return error_handler_->CreateAndUploadError(location, message, type_);
175  } else {
176    return syncer::SyncError(location, message, type_);
177  }
178}
179
180}  // namespace browser_sync
181