Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / sync / glue / sync_backend_registrar.cc
blobbcddbb28f7eef51f418efc6ee13d758967654b23
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 "base/profiler/scoped_tracker.h"
13 #include "chrome/browser/history/history_service_factory.h"
14 #include "chrome/browser/password_manager/password_store_factory.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/sync/glue/browser_thread_model_worker.h"
17 #include "chrome/browser/sync/glue/history_model_worker.h"
18 #include "chrome/browser/sync/glue/password_model_worker.h"
19 #include "chrome/browser/sync/glue/ui_model_worker.h"
20 #include "components/password_manager/core/browser/password_store.h"
21 #include "components/sync_driver/change_processor.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "sync/internal_api/public/engine/passive_model_worker.h"
24 #include "sync/internal_api/public/user_share.h"
26 using content::BrowserThread;
28 namespace browser_sync {
30 namespace {
32 // Returns true if the current thread is the native thread for the
33 // given group (or if it is undeterminable).
34 bool IsOnThreadForGroup(syncer::ModelType type, syncer::ModelSafeGroup group) {
35 switch (group) {
36 case syncer::GROUP_PASSIVE:
37 return IsControlType(type);
38 case syncer::GROUP_UI:
39 return BrowserThread::CurrentlyOn(BrowserThread::UI);
40 case syncer::GROUP_DB:
41 return BrowserThread::CurrentlyOn(BrowserThread::DB);
42 case syncer::GROUP_FILE:
43 return BrowserThread::CurrentlyOn(BrowserThread::FILE);
44 case syncer::GROUP_HISTORY:
45 // TODO(sync): How to check we're on the right thread?
46 return type == syncer::TYPED_URLS;
47 case syncer::GROUP_PASSWORD:
48 // TODO(sync): How to check we're on the right thread?
49 return type == syncer::PASSWORDS;
50 case syncer::MODEL_SAFE_GROUP_COUNT:
51 default:
52 return false;
56 } // namespace
58 SyncBackendRegistrar::SyncBackendRegistrar(
59 const std::string& name,
60 Profile* profile,
61 scoped_ptr<base::Thread> sync_thread) :
62 name_(name),
63 profile_(profile) {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65 CHECK(profile_);
67 // TODO(pavely): Remove ScopedTracker below once crbug.com/426272 is fixed.
68 tracked_objects::ScopedTracker tracker1(FROM_HERE_WITH_EXPLICIT_FUNCTION(
69 "426272 SyncBackendRegistrar::ctor thread"));
70 sync_thread_ = sync_thread.Pass();
71 if (!sync_thread_) {
72 sync_thread_.reset(new base::Thread("Chrome_SyncThread"));
73 base::Thread::Options options;
74 options.timer_slack = base::TIMER_SLACK_MAXIMUM;
75 CHECK(sync_thread_->StartWithOptions(options));
78 workers_[syncer::GROUP_DB] = new DatabaseModelWorker(this);
79 workers_[syncer::GROUP_DB]->RegisterForLoopDestruction();
81 workers_[syncer::GROUP_FILE] = new FileModelWorker(this);
82 workers_[syncer::GROUP_FILE]->RegisterForLoopDestruction();
84 workers_[syncer::GROUP_UI] = new UIModelWorker(this);
85 workers_[syncer::GROUP_UI]->RegisterForLoopDestruction();
87 // GROUP_PASSIVE worker does work on sync_loop_. But sync_loop_ is not
88 // stopped until all workers have stopped. To break the cycle, use UI loop
89 // instead.
90 workers_[syncer::GROUP_PASSIVE] =
91 new syncer::PassiveModelWorker(sync_thread_->message_loop(), this);
92 workers_[syncer::GROUP_PASSIVE]->RegisterForLoopDestruction();
94 // TODO(pavely): Remove ScopedTracker below once crbug.com/426272 is fixed.
95 tracked_objects::ScopedTracker tracker2(FROM_HERE_WITH_EXPLICIT_FUNCTION(
96 "426272 SyncBackendRegistrar::ctor history"));
97 history::HistoryService* history_service =
98 HistoryServiceFactory::GetForProfile(profile,
99 ServiceAccessType::IMPLICIT_ACCESS);
100 if (history_service) {
101 workers_[syncer::GROUP_HISTORY] =
102 new HistoryModelWorker(history_service->AsWeakPtr(), this);
103 workers_[syncer::GROUP_HISTORY]->RegisterForLoopDestruction();
107 // TODO(pavely): Remove ScopedTracker below once crbug.com/426272 is fixed.
108 tracked_objects::ScopedTracker tracker3(FROM_HERE_WITH_EXPLICIT_FUNCTION(
109 "426272 SyncBackendRegistrar::ctor passwords"));
110 scoped_refptr<password_manager::PasswordStore> password_store =
111 PasswordStoreFactory::GetForProfile(profile,
112 ServiceAccessType::IMPLICIT_ACCESS);
113 if (password_store.get()) {
114 workers_[syncer::GROUP_PASSWORD] =
115 new PasswordModelWorker(password_store, this);
116 workers_[syncer::GROUP_PASSWORD]->RegisterForLoopDestruction();
120 void SyncBackendRegistrar::SetInitialTypes(syncer::ModelTypeSet initial_types) {
121 base::AutoLock lock(lock_);
123 // This function should be called only once, shortly after construction. The
124 // routing info at that point is expected to be empty.
125 DCHECK(routing_info_.empty());
127 // Set our initial state to reflect the current status of the sync directory.
128 // This will ensure that our calculations in ConfigureDataTypes() will always
129 // return correct results.
130 for (syncer::ModelTypeSet::Iterator it = initial_types.First();
131 it.Good(); it.Inc()) {
132 routing_info_[it.Get()] = syncer::GROUP_PASSIVE;
135 if (!workers_.count(syncer::GROUP_HISTORY)) {
136 LOG_IF(WARNING, initial_types.Has(syncer::TYPED_URLS))
137 << "History store disabled, cannot sync Omnibox History";
138 routing_info_.erase(syncer::TYPED_URLS);
141 if (!workers_.count(syncer::GROUP_PASSWORD)) {
142 LOG_IF(WARNING, initial_types.Has(syncer::PASSWORDS))
143 << "Password store not initialized, cannot sync passwords";
144 routing_info_.erase(syncer::PASSWORDS);
147 last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_);
150 bool SyncBackendRegistrar::IsNigoriEnabled() const {
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152 base::AutoLock lock(lock_);
153 return routing_info_.find(syncer::NIGORI) != routing_info_.end();
156 syncer::ModelTypeSet SyncBackendRegistrar::ConfigureDataTypes(
157 syncer::ModelTypeSet types_to_add,
158 syncer::ModelTypeSet types_to_remove) {
159 DCHECK(Intersection(types_to_add, types_to_remove).Empty());
160 syncer::ModelTypeSet filtered_types_to_add = types_to_add;
161 if (workers_.count(syncer::GROUP_HISTORY) == 0) {
162 LOG(WARNING) << "No history worker -- removing TYPED_URLS";
163 filtered_types_to_add.Remove(syncer::TYPED_URLS);
165 if (workers_.count(syncer::GROUP_PASSWORD) == 0) {
166 LOG(WARNING) << "No password worker -- removing PASSWORDS";
167 filtered_types_to_add.Remove(syncer::PASSWORDS);
170 base::AutoLock lock(lock_);
171 syncer::ModelTypeSet newly_added_types;
172 for (syncer::ModelTypeSet::Iterator it =
173 filtered_types_to_add.First();
174 it.Good(); it.Inc()) {
175 // Add a newly specified data type as syncer::GROUP_PASSIVE into the
176 // routing_info, if it does not already exist.
177 if (routing_info_.count(it.Get()) == 0) {
178 routing_info_[it.Get()] = syncer::GROUP_PASSIVE;
179 newly_added_types.Put(it.Get());
182 for (syncer::ModelTypeSet::Iterator it = types_to_remove.First();
183 it.Good(); it.Inc()) {
184 routing_info_.erase(it.Get());
187 // TODO(akalin): Use SVLOG/SLOG if we add any more logging.
188 DVLOG(1) << name_ << ": Adding types "
189 << syncer::ModelTypeSetToString(types_to_add)
190 << " (with newly-added types "
191 << syncer::ModelTypeSetToString(newly_added_types)
192 << ") and removing types "
193 << syncer::ModelTypeSetToString(types_to_remove)
194 << " to get new routing info "
195 <<syncer::ModelSafeRoutingInfoToString(routing_info_);
196 last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_);
198 return newly_added_types;
201 syncer::ModelTypeSet SyncBackendRegistrar::GetLastConfiguredTypes() const {
202 return last_configured_types_;
205 void SyncBackendRegistrar::RequestWorkerStopOnUIThread() {
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
207 base::AutoLock lock(lock_);
208 for (WorkerMap::const_iterator it = workers_.begin();
209 it != workers_.end(); ++it) {
210 it->second->RequestStop();
214 void SyncBackendRegistrar::ActivateDataType(
215 syncer::ModelType type,
216 syncer::ModelSafeGroup group,
217 sync_driver::ChangeProcessor* change_processor,
218 syncer::UserShare* user_share) {
219 DVLOG(1) << "Activate: " << syncer::ModelTypeToString(type);
221 base::AutoLock lock(lock_);
222 // Ensure that the given data type is in the PASSIVE group.
223 syncer::ModelSafeRoutingInfo::iterator i = routing_info_.find(type);
224 DCHECK(i != routing_info_.end());
225 DCHECK_EQ(i->second, syncer::GROUP_PASSIVE);
226 routing_info_[type] = group;
228 // Add the data type's change processor to the list of change
229 // processors so it can receive updates.
230 DCHECK_EQ(processors_.count(type), 0U);
231 processors_[type] = change_processor;
233 // Start the change processor.
234 change_processor->Start(user_share);
235 DCHECK(GetProcessorUnsafe(type));
238 void SyncBackendRegistrar::DeactivateDataType(syncer::ModelType type) {
239 DVLOG(1) << "Deactivate: " << syncer::ModelTypeToString(type);
241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || IsControlType(type));
242 base::AutoLock lock(lock_);
244 routing_info_.erase(type);
245 ignore_result(processors_.erase(type));
246 DCHECK(!GetProcessorUnsafe(type));
249 bool SyncBackendRegistrar::IsTypeActivatedForTest(
250 syncer::ModelType type) const {
251 return GetProcessor(type) != NULL;
254 void SyncBackendRegistrar::OnChangesApplied(
255 syncer::ModelType model_type,
256 int64 model_version,
257 const syncer::BaseTransaction* trans,
258 const syncer::ImmutableChangeRecordList& changes) {
259 sync_driver::ChangeProcessor* processor = GetProcessor(model_type);
260 if (!processor)
261 return;
263 processor->ApplyChangesFromSyncModel(trans, model_version, changes);
266 void SyncBackendRegistrar::OnChangesComplete(syncer::ModelType model_type) {
267 sync_driver::ChangeProcessor* processor = GetProcessor(model_type);
268 if (!processor)
269 return;
271 // This call just notifies the processor that it can commit; it
272 // already buffered any changes it plans to makes so needs no
273 // further information.
274 processor->CommitChangesFromSyncModel();
277 void SyncBackendRegistrar::GetWorkers(
278 std::vector<scoped_refptr<syncer::ModelSafeWorker> >* out) {
279 base::AutoLock lock(lock_);
280 out->clear();
281 for (WorkerMap::const_iterator it = workers_.begin();
282 it != workers_.end(); ++it) {
283 out->push_back(it->second.get());
287 void SyncBackendRegistrar::GetModelSafeRoutingInfo(
288 syncer::ModelSafeRoutingInfo* out) {
289 base::AutoLock lock(lock_);
290 syncer::ModelSafeRoutingInfo copy(routing_info_);
291 out->swap(copy);
294 sync_driver::ChangeProcessor* SyncBackendRegistrar::GetProcessor(
295 syncer::ModelType type) const {
296 base::AutoLock lock(lock_);
297 sync_driver::ChangeProcessor* processor = GetProcessorUnsafe(type);
298 if (!processor)
299 return NULL;
301 // We can only check if |processor| exists, as otherwise the type is
302 // mapped to syncer::GROUP_PASSIVE.
303 CHECK(IsCurrentThreadSafeForModel(type));
304 return processor;
307 sync_driver::ChangeProcessor* SyncBackendRegistrar::GetProcessorUnsafe(
308 syncer::ModelType type) const {
309 lock_.AssertAcquired();
310 std::map<syncer::ModelType, sync_driver::ChangeProcessor*>::const_iterator
311 it = processors_.find(type);
313 // Until model association happens for a datatype, it will not
314 // appear in the processors list. During this time, it is OK to
315 // drop changes on the floor (since model association has not
316 // happened yet). When the data type is activated, model
317 // association takes place then the change processor is added to the
318 // |processors_| list.
319 if (it == processors_.end())
320 return NULL;
322 return it->second;
325 bool SyncBackendRegistrar::IsCurrentThreadSafeForModel(
326 syncer::ModelType model_type) const {
327 lock_.AssertAcquired();
328 return IsOnThreadForGroup(model_type,
329 GetGroupForModelType(model_type, routing_info_));
332 SyncBackendRegistrar::~SyncBackendRegistrar() {
333 DCHECK(workers_.empty());
336 void SyncBackendRegistrar::OnWorkerLoopDestroyed(syncer::ModelSafeGroup group) {
337 RemoveWorker(group);
340 void SyncBackendRegistrar::OnWorkerUnregistrationDone(
341 syncer::ModelSafeGroup group) {
342 RemoveWorker(group);
345 void SyncBackendRegistrar::RemoveWorker(syncer::ModelSafeGroup group) {
346 DVLOG(1) << "Remove " << ModelSafeGroupToString(group) << " worker.";
348 bool last_worker = false;
350 base::AutoLock al(lock_);
351 WorkerMap::iterator it = workers_.find(group);
352 CHECK(it != workers_.end());
353 stopped_workers_.push_back(it->second);
354 workers_.erase(it);
355 last_worker = workers_.empty();
358 if (last_worker) {
359 // Self-destruction after last worker.
360 DVLOG(1) << "Destroy registrar on loop of "
361 << ModelSafeGroupToString(group);
362 delete this;
366 scoped_ptr<base::Thread> SyncBackendRegistrar::ReleaseSyncThread() {
367 return sync_thread_.Pass();
370 void SyncBackendRegistrar::Shutdown() {
371 // All data types should have been deactivated by now.
372 DCHECK(processors_.empty());
374 // Unregister worker from observing loop destruction.
375 base::AutoLock al(lock_);
376 for (WorkerMap::iterator it = workers_.begin();
377 it != workers_.end(); ++it) {
378 it->second->UnregisterForLoopDestruction(
379 base::Bind(&SyncBackendRegistrar::OnWorkerUnregistrationDone,
380 base::Unretained(this)));
384 base::Thread* SyncBackendRegistrar::sync_thread() {
385 return sync_thread_.get();
388 } // namespace browser_sync