Add a Notification Settings Button to all web notifications behind the web platform...
[chromium-blink-merge.git] / chrome / browser / sync / glue / sync_backend_registrar.cc
blobf5211187eb2917c06afaa0b6174db5728c12eff4
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 "chrome/browser/sync/glue/history_model_worker.h"
16 #include "chrome/browser/sync/glue/ui_model_worker.h"
17 #include "components/password_manager/core/browser/password_store.h"
18 #include "components/password_manager/sync/browser/password_model_worker.h"
19 #include "components/sync_driver/change_processor.h"
20 #include "components/sync_driver/glue/browser_thread_model_worker.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "sync/internal_api/public/engine/passive_model_worker.h"
23 #include "sync/internal_api/public/user_share.h"
25 using content::BrowserThread;
27 namespace browser_sync {
29 namespace {
31 // Returns true if the current thread is the native thread for the
32 // given group (or if it is undeterminable).
33 bool IsOnThreadForGroup(syncer::ModelType type, syncer::ModelSafeGroup group) {
34 switch (group) {
35 case syncer::GROUP_PASSIVE:
36 return IsControlType(type);
37 case syncer::GROUP_UI:
38 return BrowserThread::CurrentlyOn(BrowserThread::UI);
39 case syncer::GROUP_DB:
40 return BrowserThread::CurrentlyOn(BrowserThread::DB);
41 case syncer::GROUP_FILE:
42 return BrowserThread::CurrentlyOn(BrowserThread::FILE);
43 case syncer::GROUP_HISTORY:
44 // TODO(sync): How to check we're on the right thread?
45 return type == syncer::TYPED_URLS;
46 case syncer::GROUP_PASSWORD:
47 // TODO(sync): How to check we're on the right thread?
48 return type == syncer::PASSWORDS;
49 case syncer::MODEL_SAFE_GROUP_COUNT:
50 default:
51 return false;
55 } // namespace
57 SyncBackendRegistrar::SyncBackendRegistrar(
58 const std::string& name,
59 Profile* profile,
60 scoped_ptr<base::Thread> sync_thread) :
61 name_(name),
62 profile_(profile) {
63 DCHECK_CURRENTLY_ON(BrowserThread::UI);
64 CHECK(profile_);
66 sync_thread_ = sync_thread.Pass();
67 if (!sync_thread_) {
68 sync_thread_.reset(new base::Thread("Chrome_SyncThread"));
69 base::Thread::Options options;
70 options.timer_slack = base::TIMER_SLACK_MAXIMUM;
71 CHECK(sync_thread_->StartWithOptions(options));
74 workers_[syncer::GROUP_DB] = new BrowserThreadModelWorker(
75 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB),
76 syncer::GROUP_DB, this);
77 workers_[syncer::GROUP_DB]->RegisterForLoopDestruction();
79 workers_[syncer::GROUP_FILE] = new BrowserThreadModelWorker(
80 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
81 syncer::GROUP_FILE, 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 history::HistoryService* history_service =
95 HistoryServiceFactory::GetForProfile(profile,
96 ServiceAccessType::IMPLICIT_ACCESS);
97 if (history_service) {
98 workers_[syncer::GROUP_HISTORY] =
99 new HistoryModelWorker(history_service->AsWeakPtr(), this);
100 workers_[syncer::GROUP_HISTORY]->RegisterForLoopDestruction();
104 scoped_refptr<password_manager::PasswordStore> password_store =
105 PasswordStoreFactory::GetForProfile(profile,
106 ServiceAccessType::IMPLICIT_ACCESS);
107 if (password_store.get()) {
108 workers_[syncer::GROUP_PASSWORD] =
109 new PasswordModelWorker(password_store, this);
110 workers_[syncer::GROUP_PASSWORD]->RegisterForLoopDestruction();
114 void SyncBackendRegistrar::SetInitialTypes(syncer::ModelTypeSet initial_types) {
115 base::AutoLock lock(lock_);
117 // This function should be called only once, shortly after construction. The
118 // routing info at that point is expected to be empty.
119 DCHECK(routing_info_.empty());
121 // Set our initial state to reflect the current status of the sync directory.
122 // This will ensure that our calculations in ConfigureDataTypes() will always
123 // return correct results.
124 for (syncer::ModelTypeSet::Iterator it = initial_types.First();
125 it.Good(); it.Inc()) {
126 routing_info_[it.Get()] = syncer::GROUP_PASSIVE;
129 if (!workers_.count(syncer::GROUP_HISTORY)) {
130 LOG_IF(WARNING, initial_types.Has(syncer::TYPED_URLS))
131 << "History store disabled, cannot sync Omnibox History";
132 routing_info_.erase(syncer::TYPED_URLS);
135 if (!workers_.count(syncer::GROUP_PASSWORD)) {
136 LOG_IF(WARNING, initial_types.Has(syncer::PASSWORDS))
137 << "Password store not initialized, cannot sync passwords";
138 routing_info_.erase(syncer::PASSWORDS);
141 last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_);
144 bool SyncBackendRegistrar::IsNigoriEnabled() const {
145 DCHECK_CURRENTLY_ON(BrowserThread::UI);
146 base::AutoLock lock(lock_);
147 return routing_info_.find(syncer::NIGORI) != routing_info_.end();
150 syncer::ModelTypeSet SyncBackendRegistrar::ConfigureDataTypes(
151 syncer::ModelTypeSet types_to_add,
152 syncer::ModelTypeSet types_to_remove) {
153 DCHECK(Intersection(types_to_add, types_to_remove).Empty());
154 syncer::ModelTypeSet filtered_types_to_add = types_to_add;
155 if (workers_.count(syncer::GROUP_HISTORY) == 0) {
156 LOG(WARNING) << "No history worker -- removing TYPED_URLS";
157 filtered_types_to_add.Remove(syncer::TYPED_URLS);
159 if (workers_.count(syncer::GROUP_PASSWORD) == 0) {
160 LOG(WARNING) << "No password worker -- removing PASSWORDS";
161 filtered_types_to_add.Remove(syncer::PASSWORDS);
164 base::AutoLock lock(lock_);
165 syncer::ModelTypeSet newly_added_types;
166 for (syncer::ModelTypeSet::Iterator it =
167 filtered_types_to_add.First();
168 it.Good(); it.Inc()) {
169 // Add a newly specified data type as syncer::GROUP_PASSIVE into the
170 // routing_info, if it does not already exist.
171 if (routing_info_.count(it.Get()) == 0) {
172 routing_info_[it.Get()] = syncer::GROUP_PASSIVE;
173 newly_added_types.Put(it.Get());
176 for (syncer::ModelTypeSet::Iterator it = types_to_remove.First();
177 it.Good(); it.Inc()) {
178 routing_info_.erase(it.Get());
181 // TODO(akalin): Use SVLOG/SLOG if we add any more logging.
182 DVLOG(1) << name_ << ": Adding types "
183 << syncer::ModelTypeSetToString(types_to_add)
184 << " (with newly-added types "
185 << syncer::ModelTypeSetToString(newly_added_types)
186 << ") and removing types "
187 << syncer::ModelTypeSetToString(types_to_remove)
188 << " to get new routing info "
189 <<syncer::ModelSafeRoutingInfoToString(routing_info_);
190 last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_);
192 return newly_added_types;
195 syncer::ModelTypeSet SyncBackendRegistrar::GetLastConfiguredTypes() const {
196 return last_configured_types_;
199 void SyncBackendRegistrar::RequestWorkerStopOnUIThread() {
200 DCHECK_CURRENTLY_ON(BrowserThread::UI);
201 base::AutoLock lock(lock_);
202 for (WorkerMap::const_iterator it = workers_.begin();
203 it != workers_.end(); ++it) {
204 it->second->RequestStop();
208 void SyncBackendRegistrar::ActivateDataType(
209 syncer::ModelType type,
210 syncer::ModelSafeGroup group,
211 sync_driver::ChangeProcessor* change_processor,
212 syncer::UserShare* user_share) {
213 DVLOG(1) << "Activate: " << syncer::ModelTypeToString(type);
215 base::AutoLock lock(lock_);
216 // Ensure that the given data type is in the PASSIVE group.
217 syncer::ModelSafeRoutingInfo::iterator i = routing_info_.find(type);
218 DCHECK(i != routing_info_.end());
219 DCHECK_EQ(i->second, syncer::GROUP_PASSIVE);
220 routing_info_[type] = group;
222 // Add the data type's change processor to the list of change
223 // processors so it can receive updates.
224 DCHECK_EQ(processors_.count(type), 0U);
225 processors_[type] = change_processor;
227 // Start the change processor.
228 change_processor->Start(user_share);
229 DCHECK(GetProcessorUnsafe(type));
232 void SyncBackendRegistrar::DeactivateDataType(syncer::ModelType type) {
233 DVLOG(1) << "Deactivate: " << syncer::ModelTypeToString(type);
235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || IsControlType(type));
236 base::AutoLock lock(lock_);
238 routing_info_.erase(type);
239 ignore_result(processors_.erase(type));
240 DCHECK(!GetProcessorUnsafe(type));
243 bool SyncBackendRegistrar::IsTypeActivatedForTest(
244 syncer::ModelType type) const {
245 return GetProcessor(type) != NULL;
248 void SyncBackendRegistrar::OnChangesApplied(
249 syncer::ModelType model_type,
250 int64 model_version,
251 const syncer::BaseTransaction* trans,
252 const syncer::ImmutableChangeRecordList& changes) {
253 sync_driver::ChangeProcessor* processor = GetProcessor(model_type);
254 if (!processor)
255 return;
257 processor->ApplyChangesFromSyncModel(trans, model_version, changes);
260 void SyncBackendRegistrar::OnChangesComplete(syncer::ModelType model_type) {
261 sync_driver::ChangeProcessor* processor = GetProcessor(model_type);
262 if (!processor)
263 return;
265 // This call just notifies the processor that it can commit; it
266 // already buffered any changes it plans to makes so needs no
267 // further information.
268 processor->CommitChangesFromSyncModel();
271 void SyncBackendRegistrar::GetWorkers(
272 std::vector<scoped_refptr<syncer::ModelSafeWorker> >* out) {
273 base::AutoLock lock(lock_);
274 out->clear();
275 for (WorkerMap::const_iterator it = workers_.begin();
276 it != workers_.end(); ++it) {
277 out->push_back(it->second.get());
281 void SyncBackendRegistrar::GetModelSafeRoutingInfo(
282 syncer::ModelSafeRoutingInfo* out) {
283 base::AutoLock lock(lock_);
284 syncer::ModelSafeRoutingInfo copy(routing_info_);
285 out->swap(copy);
288 sync_driver::ChangeProcessor* SyncBackendRegistrar::GetProcessor(
289 syncer::ModelType type) const {
290 base::AutoLock lock(lock_);
291 sync_driver::ChangeProcessor* processor = GetProcessorUnsafe(type);
292 if (!processor)
293 return NULL;
295 // We can only check if |processor| exists, as otherwise the type is
296 // mapped to syncer::GROUP_PASSIVE.
297 CHECK(IsCurrentThreadSafeForModel(type));
298 return processor;
301 sync_driver::ChangeProcessor* SyncBackendRegistrar::GetProcessorUnsafe(
302 syncer::ModelType type) const {
303 lock_.AssertAcquired();
304 std::map<syncer::ModelType, sync_driver::ChangeProcessor*>::const_iterator
305 it = processors_.find(type);
307 // Until model association happens for a datatype, it will not
308 // appear in the processors list. During this time, it is OK to
309 // drop changes on the floor (since model association has not
310 // happened yet). When the data type is activated, model
311 // association takes place then the change processor is added to the
312 // |processors_| list.
313 if (it == processors_.end())
314 return NULL;
316 return it->second;
319 bool SyncBackendRegistrar::IsCurrentThreadSafeForModel(
320 syncer::ModelType model_type) const {
321 lock_.AssertAcquired();
322 return IsOnThreadForGroup(model_type,
323 GetGroupForModelType(model_type, routing_info_));
326 SyncBackendRegistrar::~SyncBackendRegistrar() {
327 DCHECK(workers_.empty());
330 void SyncBackendRegistrar::OnWorkerLoopDestroyed(syncer::ModelSafeGroup group) {
331 RemoveWorker(group);
334 void SyncBackendRegistrar::OnWorkerUnregistrationDone(
335 syncer::ModelSafeGroup group) {
336 RemoveWorker(group);
339 void SyncBackendRegistrar::RemoveWorker(syncer::ModelSafeGroup group) {
340 DVLOG(1) << "Remove " << ModelSafeGroupToString(group) << " worker.";
342 bool last_worker = false;
344 base::AutoLock al(lock_);
345 WorkerMap::iterator it = workers_.find(group);
346 CHECK(it != workers_.end());
347 stopped_workers_.push_back(it->second);
348 workers_.erase(it);
349 last_worker = workers_.empty();
352 if (last_worker) {
353 // Self-destruction after last worker.
354 DVLOG(1) << "Destroy registrar on loop of "
355 << ModelSafeGroupToString(group);
356 delete this;
360 scoped_ptr<base::Thread> SyncBackendRegistrar::ReleaseSyncThread() {
361 return sync_thread_.Pass();
364 void SyncBackendRegistrar::Shutdown() {
365 // All data types should have been deactivated by now.
366 DCHECK(processors_.empty());
368 // Unregister worker from observing loop destruction.
369 base::AutoLock al(lock_);
370 for (WorkerMap::iterator it = workers_.begin();
371 it != workers_.end(); ++it) {
372 it->second->UnregisterForLoopDestruction(
373 base::Bind(&SyncBackendRegistrar::OnWorkerUnregistrationDone,
374 base::Unretained(this)));
378 base::Thread* SyncBackendRegistrar::sync_thread() {
379 return sync_thread_.get();
382 } // namespace browser_sync