Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / sync / glue / sync_backend_registrar.cc
blobe50628406aa4a77e89d58a18aa1e4a6f97977544
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.
5 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
7 #include <cstddef>
9 #include "base/compiler_specific.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "chrome/browser/history/history_service_factory.h"
13 #include "chrome/browser/password_manager/password_store_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "components/password_manager/core/browser/password_store.h"
16 #include "components/password_manager/sync/browser/password_model_worker.h"
17 #include "components/sync_driver/change_processor.h"
18 #include "components/sync_driver/glue/browser_thread_model_worker.h"
19 #include "components/sync_driver/glue/history_model_worker.h"
20 #include "components/sync_driver/glue/ui_model_worker.h"
21 #include "sync/internal_api/public/engine/passive_model_worker.h"
22 #include "sync/internal_api/public/user_share.h"
24 namespace browser_sync {
26 SyncBackendRegistrar::SyncBackendRegistrar(
27 const std::string& name,
28 Profile* profile,
29 scoped_ptr<base::Thread> sync_thread,
30 const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
31 const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
32 const scoped_refptr<base::SingleThreadTaskRunner>& file_thread)
33 : name_(name),
34 profile_(profile),
35 ui_thread_(ui_thread),
36 db_thread_(db_thread),
37 file_thread_(file_thread) {
38 DCHECK(ui_thread_->BelongsToCurrentThread());
39 CHECK(profile_);
41 sync_thread_ = sync_thread.Pass();
42 if (!sync_thread_) {
43 sync_thread_.reset(new base::Thread("Chrome_SyncThread"));
44 base::Thread::Options options;
45 options.timer_slack = base::TIMER_SLACK_MAXIMUM;
46 CHECK(sync_thread_->StartWithOptions(options));
49 workers_[syncer::GROUP_DB] =
50 new BrowserThreadModelWorker(db_thread_, syncer::GROUP_DB, this);
51 workers_[syncer::GROUP_DB]->RegisterForLoopDestruction();
53 workers_[syncer::GROUP_FILE] =
54 new BrowserThreadModelWorker(file_thread_, syncer::GROUP_FILE, this);
55 workers_[syncer::GROUP_FILE]->RegisterForLoopDestruction();
57 workers_[syncer::GROUP_UI] = new UIModelWorker(ui_thread_, this);
58 workers_[syncer::GROUP_UI]->RegisterForLoopDestruction();
60 // GROUP_PASSIVE worker does work on sync_loop_. But sync_loop_ is not
61 // stopped until all workers have stopped. To break the cycle, use UI loop
62 // instead.
63 workers_[syncer::GROUP_PASSIVE] =
64 new syncer::PassiveModelWorker(sync_thread_->message_loop(), this);
65 workers_[syncer::GROUP_PASSIVE]->RegisterForLoopDestruction();
67 history::HistoryService* history_service =
68 HistoryServiceFactory::GetForProfile(profile,
69 ServiceAccessType::IMPLICIT_ACCESS);
70 if (history_service) {
71 workers_[syncer::GROUP_HISTORY] =
72 new HistoryModelWorker(history_service->AsWeakPtr(), ui_thread_, this);
73 workers_[syncer::GROUP_HISTORY]->RegisterForLoopDestruction();
77 scoped_refptr<password_manager::PasswordStore> password_store =
78 PasswordStoreFactory::GetForProfile(profile,
79 ServiceAccessType::IMPLICIT_ACCESS);
80 if (password_store.get()) {
81 workers_[syncer::GROUP_PASSWORD] =
82 new PasswordModelWorker(password_store, this);
83 workers_[syncer::GROUP_PASSWORD]->RegisterForLoopDestruction();
87 void SyncBackendRegistrar::SetInitialTypes(syncer::ModelTypeSet initial_types) {
88 base::AutoLock lock(lock_);
90 // This function should be called only once, shortly after construction. The
91 // routing info at that point is expected to be empty.
92 DCHECK(routing_info_.empty());
94 // Set our initial state to reflect the current status of the sync directory.
95 // This will ensure that our calculations in ConfigureDataTypes() will always
96 // return correct results.
97 for (syncer::ModelTypeSet::Iterator it = initial_types.First();
98 it.Good(); it.Inc()) {
99 routing_info_[it.Get()] = syncer::GROUP_PASSIVE;
102 if (!workers_.count(syncer::GROUP_HISTORY)) {
103 LOG_IF(WARNING, initial_types.Has(syncer::TYPED_URLS))
104 << "History store disabled, cannot sync Omnibox History";
105 routing_info_.erase(syncer::TYPED_URLS);
108 if (!workers_.count(syncer::GROUP_PASSWORD)) {
109 LOG_IF(WARNING, initial_types.Has(syncer::PASSWORDS))
110 << "Password store not initialized, cannot sync passwords";
111 routing_info_.erase(syncer::PASSWORDS);
114 last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_);
117 bool SyncBackendRegistrar::IsNigoriEnabled() const {
118 DCHECK(ui_thread_->BelongsToCurrentThread());
119 base::AutoLock lock(lock_);
120 return routing_info_.find(syncer::NIGORI) != routing_info_.end();
123 syncer::ModelTypeSet SyncBackendRegistrar::ConfigureDataTypes(
124 syncer::ModelTypeSet types_to_add,
125 syncer::ModelTypeSet types_to_remove) {
126 DCHECK(Intersection(types_to_add, types_to_remove).Empty());
127 syncer::ModelTypeSet filtered_types_to_add = types_to_add;
128 if (workers_.count(syncer::GROUP_HISTORY) == 0) {
129 LOG(WARNING) << "No history worker -- removing TYPED_URLS";
130 filtered_types_to_add.Remove(syncer::TYPED_URLS);
132 if (workers_.count(syncer::GROUP_PASSWORD) == 0) {
133 LOG(WARNING) << "No password worker -- removing PASSWORDS";
134 filtered_types_to_add.Remove(syncer::PASSWORDS);
137 base::AutoLock lock(lock_);
138 syncer::ModelTypeSet newly_added_types;
139 for (syncer::ModelTypeSet::Iterator it =
140 filtered_types_to_add.First();
141 it.Good(); it.Inc()) {
142 // Add a newly specified data type as syncer::GROUP_PASSIVE into the
143 // routing_info, if it does not already exist.
144 if (routing_info_.count(it.Get()) == 0) {
145 routing_info_[it.Get()] = syncer::GROUP_PASSIVE;
146 newly_added_types.Put(it.Get());
149 for (syncer::ModelTypeSet::Iterator it = types_to_remove.First();
150 it.Good(); it.Inc()) {
151 routing_info_.erase(it.Get());
154 // TODO(akalin): Use SVLOG/SLOG if we add any more logging.
155 DVLOG(1) << name_ << ": Adding types "
156 << syncer::ModelTypeSetToString(types_to_add)
157 << " (with newly-added types "
158 << syncer::ModelTypeSetToString(newly_added_types)
159 << ") and removing types "
160 << syncer::ModelTypeSetToString(types_to_remove)
161 << " to get new routing info "
162 <<syncer::ModelSafeRoutingInfoToString(routing_info_);
163 last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_);
165 return newly_added_types;
168 syncer::ModelTypeSet SyncBackendRegistrar::GetLastConfiguredTypes() const {
169 return last_configured_types_;
172 void SyncBackendRegistrar::RequestWorkerStopOnUIThread() {
173 DCHECK(ui_thread_->BelongsToCurrentThread());
174 base::AutoLock lock(lock_);
175 for (WorkerMap::const_iterator it = workers_.begin();
176 it != workers_.end(); ++it) {
177 it->second->RequestStop();
181 void SyncBackendRegistrar::ActivateDataType(
182 syncer::ModelType type,
183 syncer::ModelSafeGroup group,
184 sync_driver::ChangeProcessor* change_processor,
185 syncer::UserShare* user_share) {
186 DVLOG(1) << "Activate: " << syncer::ModelTypeToString(type);
188 base::AutoLock lock(lock_);
189 // Ensure that the given data type is in the PASSIVE group.
190 syncer::ModelSafeRoutingInfo::iterator i = routing_info_.find(type);
191 DCHECK(i != routing_info_.end());
192 DCHECK_EQ(i->second, syncer::GROUP_PASSIVE);
193 routing_info_[type] = group;
195 // Add the data type's change processor to the list of change
196 // processors so it can receive updates.
197 DCHECK_EQ(processors_.count(type), 0U);
198 processors_[type] = change_processor;
200 // Start the change processor.
201 change_processor->Start(user_share);
202 DCHECK(GetProcessorUnsafe(type));
205 void SyncBackendRegistrar::DeactivateDataType(syncer::ModelType type) {
206 DVLOG(1) << "Deactivate: " << syncer::ModelTypeToString(type);
208 DCHECK(ui_thread_->BelongsToCurrentThread() || IsControlType(type));
209 base::AutoLock lock(lock_);
211 routing_info_.erase(type);
212 ignore_result(processors_.erase(type));
213 DCHECK(!GetProcessorUnsafe(type));
216 bool SyncBackendRegistrar::IsTypeActivatedForTest(
217 syncer::ModelType type) const {
218 return GetProcessor(type) != NULL;
221 void SyncBackendRegistrar::OnChangesApplied(
222 syncer::ModelType model_type,
223 int64 model_version,
224 const syncer::BaseTransaction* trans,
225 const syncer::ImmutableChangeRecordList& changes) {
226 sync_driver::ChangeProcessor* processor = GetProcessor(model_type);
227 if (!processor)
228 return;
230 processor->ApplyChangesFromSyncModel(trans, model_version, changes);
233 void SyncBackendRegistrar::OnChangesComplete(syncer::ModelType model_type) {
234 sync_driver::ChangeProcessor* processor = GetProcessor(model_type);
235 if (!processor)
236 return;
238 // This call just notifies the processor that it can commit; it
239 // already buffered any changes it plans to makes so needs no
240 // further information.
241 processor->CommitChangesFromSyncModel();
244 void SyncBackendRegistrar::GetWorkers(
245 std::vector<scoped_refptr<syncer::ModelSafeWorker> >* out) {
246 base::AutoLock lock(lock_);
247 out->clear();
248 for (WorkerMap::const_iterator it = workers_.begin();
249 it != workers_.end(); ++it) {
250 out->push_back(it->second.get());
254 void SyncBackendRegistrar::GetModelSafeRoutingInfo(
255 syncer::ModelSafeRoutingInfo* out) {
256 base::AutoLock lock(lock_);
257 syncer::ModelSafeRoutingInfo copy(routing_info_);
258 out->swap(copy);
261 sync_driver::ChangeProcessor* SyncBackendRegistrar::GetProcessor(
262 syncer::ModelType type) const {
263 base::AutoLock lock(lock_);
264 sync_driver::ChangeProcessor* processor = GetProcessorUnsafe(type);
265 if (!processor)
266 return NULL;
268 // We can only check if |processor| exists, as otherwise the type is
269 // mapped to syncer::GROUP_PASSIVE.
270 CHECK(IsCurrentThreadSafeForModel(type));
271 return processor;
274 sync_driver::ChangeProcessor* SyncBackendRegistrar::GetProcessorUnsafe(
275 syncer::ModelType type) const {
276 lock_.AssertAcquired();
277 std::map<syncer::ModelType, sync_driver::ChangeProcessor*>::const_iterator
278 it = processors_.find(type);
280 // Until model association happens for a datatype, it will not
281 // appear in the processors list. During this time, it is OK to
282 // drop changes on the floor (since model association has not
283 // happened yet). When the data type is activated, model
284 // association takes place then the change processor is added to the
285 // |processors_| list.
286 if (it == processors_.end())
287 return NULL;
289 return it->second;
292 bool SyncBackendRegistrar::IsCurrentThreadSafeForModel(
293 syncer::ModelType model_type) const {
294 lock_.AssertAcquired();
295 return IsOnThreadForGroup(model_type,
296 GetGroupForModelType(model_type, routing_info_));
299 bool SyncBackendRegistrar::IsOnThreadForGroup(
300 syncer::ModelType type,
301 syncer::ModelSafeGroup group) const {
302 switch (group) {
303 case syncer::GROUP_PASSIVE:
304 return IsControlType(type);
305 case syncer::GROUP_UI:
306 return ui_thread_->BelongsToCurrentThread();
307 case syncer::GROUP_DB:
308 return db_thread_->BelongsToCurrentThread();
309 case syncer::GROUP_FILE:
310 return file_thread_->BelongsToCurrentThread();
311 case syncer::GROUP_HISTORY:
312 // TODO(sync): How to check we're on the right thread?
313 return type == syncer::TYPED_URLS;
314 case syncer::GROUP_PASSWORD:
315 // TODO(sync): How to check we're on the right thread?
316 return type == syncer::PASSWORDS;
317 case syncer::MODEL_SAFE_GROUP_COUNT:
318 default:
319 return false;
323 SyncBackendRegistrar::~SyncBackendRegistrar() {
324 DCHECK(workers_.empty());
327 void SyncBackendRegistrar::OnWorkerLoopDestroyed(syncer::ModelSafeGroup group) {
328 RemoveWorker(group);
331 void SyncBackendRegistrar::OnWorkerUnregistrationDone(
332 syncer::ModelSafeGroup group) {
333 RemoveWorker(group);
336 void SyncBackendRegistrar::RemoveWorker(syncer::ModelSafeGroup group) {
337 DVLOG(1) << "Remove " << ModelSafeGroupToString(group) << " worker.";
339 bool last_worker = false;
341 base::AutoLock al(lock_);
342 WorkerMap::iterator it = workers_.find(group);
343 CHECK(it != workers_.end());
344 stopped_workers_.push_back(it->second);
345 workers_.erase(it);
346 last_worker = workers_.empty();
349 if (last_worker) {
350 // Self-destruction after last worker.
351 DVLOG(1) << "Destroy registrar on loop of "
352 << ModelSafeGroupToString(group);
353 delete this;
357 scoped_ptr<base::Thread> SyncBackendRegistrar::ReleaseSyncThread() {
358 return sync_thread_.Pass();
361 void SyncBackendRegistrar::Shutdown() {
362 // All data types should have been deactivated by now.
363 DCHECK(processors_.empty());
365 // Unregister worker from observing loop destruction.
366 base::AutoLock al(lock_);
367 for (WorkerMap::iterator it = workers_.begin();
368 it != workers_.end(); ++it) {
369 it->second->UnregisterForLoopDestruction(
370 base::Bind(&SyncBackendRegistrar::OnWorkerUnregistrationDone,
371 base::Unretained(this)));
375 base::Thread* SyncBackendRegistrar::sync_thread() {
376 return sync_thread_.get();
379 } // namespace browser_sync