• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "build/build_config.h"
6 
7 #include <algorithm>
8 
9 #include "base/command_line.h"
10 #include "base/compiler_specific.h"
11 #include "base/file_util.h"
12 #include "base/task.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "base/utf_string_conversions.h"
15 #include "chrome/browser/net/gaia/token_service.h"
16 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/sync/engine/syncapi.h"
19 #include "chrome/browser/sync/glue/autofill_model_associator.h"
20 #include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
21 #include "chrome/browser/sync/glue/change_processor.h"
22 #include "chrome/browser/sync/glue/database_model_worker.h"
23 #include "chrome/browser/sync/glue/history_model_worker.h"
24 #include "chrome/browser/sync/glue/http_bridge.h"
25 #include "chrome/browser/sync/glue/password_model_worker.h"
26 #include "chrome/browser/sync/glue/sync_backend_host.h"
27 #include "chrome/browser/sync/js_arg_list.h"
28 #include "chrome/browser/sync/notifier/sync_notifier.h"
29 #include "chrome/browser/sync/notifier/sync_notifier_factory.h"
30 #include "chrome/browser/sync/sessions/session_state.h"
31 // TODO(tim): Remove this! We should have a syncapi pass-thru instead.
32 #include "chrome/browser/sync/syncable/directory_manager.h"  // Cryptographer.
33 #include "chrome/browser/sync/syncable/model_type.h"
34 #include "chrome/browser/sync/syncable/nigori_util.h"
35 #include "chrome/common/chrome_switches.h"
36 #include "chrome/common/chrome_version_info.h"
37 #include "chrome/common/net/gaia/gaia_constants.h"
38 #include "chrome/common/pref_names.h"
39 #include "content/browser/browser_thread.h"
40 #include "content/common/notification_service.h"
41 #include "content/common/notification_type.h"
42 #include "googleurl/src/gurl.h"
43 #include "webkit/glue/webkit_glue.h"
44 
45 static const int kSaveChangesIntervalSeconds = 10;
46 static const FilePath::CharType kSyncDataFolderName[] =
47     FILE_PATH_LITERAL("Sync Data");
48 
49 using browser_sync::DataTypeController;
50 using sync_notifier::SyncNotifierFactory;
51 typedef TokenService::TokenAvailableDetails TokenAvailableDetails;
52 
53 typedef GoogleServiceAuthError AuthError;
54 
55 namespace browser_sync {
56 
57 using sessions::SyncSessionSnapshot;
58 using sync_api::SyncCredentials;
59 
SyncBackendHost(Profile * profile)60 SyncBackendHost::SyncBackendHost(Profile* profile)
61     : core_(new Core(ALLOW_THIS_IN_INITIALIZER_LIST(this))),
62       core_thread_("Chrome_SyncCoreThread"),
63       frontend_loop_(MessageLoop::current()),
64       profile_(profile),
65       frontend_(NULL),
66       sync_data_folder_path_(
67           profile_->GetPath().Append(kSyncDataFolderName)),
68       last_auth_error_(AuthError::None()),
69       syncapi_initialized_(false) {
70 }
71 
SyncBackendHost()72 SyncBackendHost::SyncBackendHost()
73     : core_thread_("Chrome_SyncCoreThread"),
74       frontend_loop_(MessageLoop::current()),
75       profile_(NULL),
76       frontend_(NULL),
77       last_auth_error_(AuthError::None()),
78       syncapi_initialized_(false) {
79 }
80 
~SyncBackendHost()81 SyncBackendHost::~SyncBackendHost() {
82   DCHECK(!core_ && !frontend_) << "Must call Shutdown before destructor.";
83   DCHECK(registrar_.workers.empty());
84 }
85 
Initialize(SyncFrontend * frontend,const GURL & sync_service_url,const syncable::ModelTypeSet & types,net::URLRequestContextGetter * baseline_context_getter,const SyncCredentials & credentials,bool delete_sync_data_folder)86 void SyncBackendHost::Initialize(
87     SyncFrontend* frontend,
88     const GURL& sync_service_url,
89     const syncable::ModelTypeSet& types,
90     net::URLRequestContextGetter* baseline_context_getter,
91     const SyncCredentials& credentials,
92     bool delete_sync_data_folder) {
93   if (!core_thread_.Start())
94     return;
95 
96   frontend_ = frontend;
97   DCHECK(frontend);
98 
99   // Create a worker for the UI thread and route bookmark changes to it.
100   // TODO(tim): Pull this into a method to reuse.  For now we don't even
101   // need to lock because we init before the syncapi exists and we tear down
102   // after the syncapi is destroyed.  Make sure to NULL-check workers_ indices
103   // when a new type is synced as the worker may already exist and you just
104   // need to update routing_info_.
105   registrar_.workers[GROUP_DB] = new DatabaseModelWorker();
106   registrar_.workers[GROUP_UI] = new UIModelWorker();
107   registrar_.workers[GROUP_PASSIVE] = new ModelSafeWorker();
108 
109   if (CommandLine::ForCurrentProcess()->HasSwitch(
110       switches::kEnableSyncTypedUrls) || types.count(syncable::TYPED_URLS)) {
111     // TODO(tim): Bug 53916.  HistoryModelWorker crashes, so avoid adding it
112     // unless specifically requested until bug is fixed.
113     registrar_.workers[GROUP_HISTORY] =
114         new HistoryModelWorker(
115             profile_->GetHistoryService(Profile::IMPLICIT_ACCESS));
116   }
117 
118   // Any datatypes that we want the syncer to pull down must
119   // be in the routing_info map.  We set them to group passive, meaning that
120   // updates will be applied, but not dispatched to the UI thread yet.
121   for (syncable::ModelTypeSet::const_iterator it = types.begin();
122       it != types.end(); ++it) {
123     registrar_.routing_info[(*it)] = GROUP_PASSIVE;
124   }
125 
126   PasswordStore* password_store =
127       profile_->GetPasswordStore(Profile::IMPLICIT_ACCESS);
128   if (password_store) {
129     registrar_.workers[GROUP_PASSWORD] =
130         new PasswordModelWorker(password_store);
131   } else {
132     LOG_IF(WARNING, types.count(syncable::PASSWORDS) > 0) << "Password store "
133         << "not initialized, cannot sync passwords";
134     registrar_.routing_info.erase(syncable::PASSWORDS);
135   }
136 
137   // Nigori is populated by default now.
138   registrar_.routing_info[syncable::NIGORI] = GROUP_PASSIVE;
139 
140   // TODO(akalin): Create SyncNotifier here and pass it in as part of
141   // DoInitializeOptions.
142   core_->CreateSyncNotifier(baseline_context_getter);
143 
144   InitCore(Core::DoInitializeOptions(
145       sync_service_url,
146       MakeHttpBridgeFactory(baseline_context_getter),
147       credentials,
148       delete_sync_data_folder,
149       RestoreEncryptionBootstrapToken(),
150       false));
151 }
152 
PersistEncryptionBootstrapToken(const std::string & token)153 void SyncBackendHost::PersistEncryptionBootstrapToken(
154     const std::string& token) {
155   PrefService* prefs = profile_->GetPrefs();
156 
157   prefs->SetString(prefs::kEncryptionBootstrapToken, token);
158   prefs->ScheduleSavePersistentPrefs();
159 }
160 
RestoreEncryptionBootstrapToken()161 std::string SyncBackendHost::RestoreEncryptionBootstrapToken() {
162   PrefService* prefs = profile_->GetPrefs();
163   std::string token = prefs->GetString(prefs::kEncryptionBootstrapToken);
164   return token;
165 }
166 
IsNigoriEnabled() const167 bool SyncBackendHost::IsNigoriEnabled() const {
168   base::AutoLock lock(registrar_lock_);
169   // Note that NIGORI is only ever added/removed from routing_info once,
170   // during initialization / first configuration, so there is no real 'race'
171   // possible here or possibility of stale return value.
172   return registrar_.routing_info.find(syncable::NIGORI) !=
173       registrar_.routing_info.end();
174 }
175 
IsUsingExplicitPassphrase()176 bool SyncBackendHost::IsUsingExplicitPassphrase() {
177   return IsNigoriEnabled() && syncapi_initialized_ &&
178       core_->syncapi()->InitialSyncEndedForAllEnabledTypes() &&
179       core_->syncapi()->IsUsingExplicitPassphrase();
180 }
181 
IsCryptographerReady(const sync_api::BaseTransaction * trans) const182 bool SyncBackendHost::IsCryptographerReady(
183     const sync_api::BaseTransaction* trans) const {
184   return syncapi_initialized_ && trans->GetCryptographer()->is_ready();
185 }
186 
GetJsBackend()187 JsBackend* SyncBackendHost::GetJsBackend() {
188   if (syncapi_initialized_) {
189     return core_.get();
190   } else {
191     NOTREACHED();
192     return NULL;
193   }
194 }
195 
MakeHttpBridgeFactory(net::URLRequestContextGetter * getter)196 sync_api::HttpPostProviderFactory* SyncBackendHost::MakeHttpBridgeFactory(
197     net::URLRequestContextGetter* getter) {
198   return new HttpBridgeFactory(getter);
199 }
200 
InitCore(const Core::DoInitializeOptions & options)201 void SyncBackendHost::InitCore(const Core::DoInitializeOptions& options) {
202   core_thread_.message_loop()->PostTask(FROM_HERE,
203       NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize,
204                         options));
205 }
206 
UpdateCredentials(const SyncCredentials & credentials)207 void SyncBackendHost::UpdateCredentials(const SyncCredentials& credentials) {
208   core_thread_.message_loop()->PostTask(FROM_HERE,
209       NewRunnableMethod(core_.get(),
210                         &SyncBackendHost::Core::DoUpdateCredentials,
211                         credentials));
212 }
213 
StartSyncingWithServer()214 void SyncBackendHost::StartSyncingWithServer() {
215   core_thread_.message_loop()->PostTask(FROM_HERE,
216       NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoStartSyncing));
217 }
218 
SetPassphrase(const std::string & passphrase,bool is_explicit)219 void SyncBackendHost::SetPassphrase(const std::string& passphrase,
220                                     bool is_explicit) {
221   if (!IsNigoriEnabled()) {
222     LOG(WARNING) << "Silently dropping SetPassphrase request.";
223     return;
224   }
225 
226   // This should only be called by the frontend.
227   DCHECK_EQ(MessageLoop::current(), frontend_loop_);
228   if (core_->processing_passphrase()) {
229     VLOG(1) << "Attempted to call SetPassphrase while already waiting for "
230             << " result from previous SetPassphrase call. Silently dropping.";
231     return;
232   }
233   core_->set_processing_passphrase();
234 
235   // If encryption is enabled and we've got a SetPassphrase
236   core_thread_.message_loop()->PostTask(FROM_HERE,
237       NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoSetPassphrase,
238                         passphrase, is_explicit));
239 }
240 
Shutdown(bool sync_disabled)241 void SyncBackendHost::Shutdown(bool sync_disabled) {
242   // Thread shutdown should occur in the following order:
243   // - SyncerThread
244   // - CoreThread
245   // - UI Thread (stops some time after we return from this call).
246   if (core_thread_.IsRunning()) {  // Not running in tests.
247     core_thread_.message_loop()->PostTask(FROM_HERE,
248         NewRunnableMethod(core_.get(),
249                           &SyncBackendHost::Core::DoShutdown,
250                           sync_disabled));
251   }
252 
253   // Before joining the core_thread_, we wait for the UIModelWorker to
254   // give us the green light that it is not depending on the frontend_loop_ to
255   // process any more tasks. Stop() blocks until this termination condition
256   // is true.
257   if (ui_worker())
258     ui_worker()->Stop();
259 
260   // Stop will return once the thread exits, which will be after DoShutdown
261   // runs. DoShutdown needs to run from core_thread_ because the sync backend
262   // requires any thread that opened sqlite handles to relinquish them
263   // personally. We need to join threads, because otherwise the main Chrome
264   // thread (ui loop) can exit before DoShutdown finishes, at which point
265   // virtually anything the sync backend does (or the post-back to
266   // frontend_loop_ by our Core) will epically fail because the CRT won't be
267   // initialized.
268   // Since we are blocking the UI thread here, we need to turn ourselves in
269   // with the ThreadRestriction police.  For sentencing and how we plan to fix
270   // this, see bug 19757.
271   {
272     base::ThreadRestrictions::ScopedAllowIO allow_io;
273     core_thread_.Stop();
274   }
275 
276   registrar_.routing_info.clear();
277   registrar_.workers[GROUP_DB] = NULL;
278   registrar_.workers[GROUP_HISTORY] = NULL;
279   registrar_.workers[GROUP_UI] = NULL;
280   registrar_.workers[GROUP_PASSIVE] = NULL;
281   registrar_.workers[GROUP_PASSWORD] = NULL;
282   registrar_.workers.erase(GROUP_DB);
283   registrar_.workers.erase(GROUP_HISTORY);
284   registrar_.workers.erase(GROUP_UI);
285   registrar_.workers.erase(GROUP_PASSIVE);
286   registrar_.workers.erase(GROUP_PASSWORD);
287   frontend_ = NULL;
288   core_ = NULL;  // Releases reference to core_.
289 }
290 
291 syncable::AutofillMigrationState
GetAutofillMigrationState()292     SyncBackendHost::GetAutofillMigrationState() {
293   return core_->syncapi()->GetAutofillMigrationState();
294 }
295 
SetAutofillMigrationState(syncable::AutofillMigrationState state)296 void SyncBackendHost::SetAutofillMigrationState(
297     syncable::AutofillMigrationState state) {
298   return core_->syncapi()->SetAutofillMigrationState(state);
299 }
300 
301 syncable::AutofillMigrationDebugInfo
GetAutofillMigrationDebugInfo()302     SyncBackendHost::GetAutofillMigrationDebugInfo() {
303   return core_->syncapi()->GetAutofillMigrationDebugInfo();
304 }
305 
SetAutofillMigrationDebugInfo(syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,const syncable::AutofillMigrationDebugInfo & info)306 void SyncBackendHost::SetAutofillMigrationDebugInfo(
307     syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
308     const syncable::AutofillMigrationDebugInfo& info) {
309   return core_->syncapi()->SetAutofillMigrationDebugInfo(property_to_set, info);
310 }
311 
ConfigureAutofillMigration()312 void SyncBackendHost::ConfigureAutofillMigration() {
313   if (GetAutofillMigrationState() == syncable::NOT_DETERMINED) {
314     sync_api::ReadTransaction trans(GetUserShare());
315     sync_api::ReadNode autofil_root_node(&trans);
316 
317     // Check for the presence of autofill node.
318     if (!autofil_root_node.InitByTagLookup(browser_sync::kAutofillTag)) {
319         SetAutofillMigrationState(syncable::INSUFFICIENT_INFO_TO_DETERMINE);
320       return;
321     }
322 
323     // Check for children under autofill node.
324     if (autofil_root_node.GetFirstChildId() == static_cast<int64>(0)) {
325       SetAutofillMigrationState(syncable::INSUFFICIENT_INFO_TO_DETERMINE);
326       return;
327     }
328 
329     sync_api::ReadNode autofill_profile_root_node(&trans);
330 
331     // Check for the presence of autofill profile root node.
332     if (!autofill_profile_root_node.InitByTagLookup(
333        browser_sync::kAutofillProfileTag)) {
334       SetAutofillMigrationState(syncable::NOT_MIGRATED);
335       return;
336     }
337 
338     // If our state is not determined then we should not have the autofill
339     // profile node.
340     DCHECK(false);
341 
342     // just set it as not migrated.
343     SetAutofillMigrationState(syncable::NOT_MIGRATED);
344     return;
345   }
346 }
347 
348 SyncBackendHost::PendingConfigureDataTypesState::
PendingConfigureDataTypesState()349 PendingConfigureDataTypesState() : deleted_type(false) {}
350 
351 SyncBackendHost::PendingConfigureDataTypesState::
~PendingConfigureDataTypesState()352 ~PendingConfigureDataTypesState() {}
353 
354 // static
355 SyncBackendHost::PendingConfigureDataTypesState*
MakePendingConfigModeState(const DataTypeController::TypeMap & data_type_controllers,const syncable::ModelTypeSet & types,CancelableTask * ready_task,ModelSafeRoutingInfo * routing_info)356     SyncBackendHost::MakePendingConfigModeState(
357         const DataTypeController::TypeMap& data_type_controllers,
358         const syncable::ModelTypeSet& types,
359         CancelableTask* ready_task,
360         ModelSafeRoutingInfo* routing_info) {
361   PendingConfigureDataTypesState* state = new PendingConfigureDataTypesState();
362   for (DataTypeController::TypeMap::const_iterator it =
363            data_type_controllers.begin();
364        it != data_type_controllers.end(); ++it) {
365     syncable::ModelType type = it->first;
366     // If a type is not specified, remove it from the routing_info.
367     if (types.count(type) == 0) {
368       state->deleted_type = true;
369       routing_info->erase(type);
370     } else {
371       // Add a newly specified data type as GROUP_PASSIVE into the
372       // routing_info, if it does not already exist.
373       if (routing_info->count(type) == 0) {
374         (*routing_info)[type] = GROUP_PASSIVE;
375         state->added_types.set(type);
376       }
377     }
378   }
379 
380   state->ready_task.reset(ready_task);
381   state->initial_types = types;
382   return state;
383 }
384 
ConfigureDataTypes(const DataTypeController::TypeMap & data_type_controllers,const syncable::ModelTypeSet & types,CancelableTask * ready_task)385 void SyncBackendHost::ConfigureDataTypes(
386     const DataTypeController::TypeMap& data_type_controllers,
387     const syncable::ModelTypeSet& types,
388     CancelableTask* ready_task) {
389   // Only one configure is allowed at a time.
390   DCHECK(!pending_config_mode_state_.get());
391   DCHECK(!pending_download_state_.get());
392   DCHECK(syncapi_initialized_);
393 
394   if (types.count(syncable::AUTOFILL_PROFILE) != 0) {
395     ConfigureAutofillMigration();
396   }
397 
398   {
399     base::AutoLock lock(registrar_lock_);
400     pending_config_mode_state_.reset(
401         MakePendingConfigModeState(data_type_controllers, types, ready_task,
402                                    &registrar_.routing_info));
403   }
404 
405   StartConfiguration(NewCallback(core_.get(),
406       &SyncBackendHost::Core::FinishConfigureDataTypes));
407 }
408 
StartConfiguration(Callback0::Type * callback)409 void SyncBackendHost::StartConfiguration(Callback0::Type* callback) {
410   // Put syncer in the config mode. DTM will put us in normal mode once it is.
411   // done. This is to ensure we dont do a normal sync when we are doing model
412   // association.
413   core_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
414     core_.get(),&SyncBackendHost::Core::DoStartConfiguration, callback));
415 }
416 
FinishConfigureDataTypesOnFrontendLoop()417 void SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop() {
418   DCHECK_EQ(MessageLoop::current(), frontend_loop_);
419   // Nudge the syncer. This is necessary for both datatype addition/deletion.
420   //
421   // Deletions need a nudge in order to ensure the deletion occurs in a timely
422   // manner (see issue 56416).
423   //
424   // In the case of additions, on the next sync cycle, the syncer should
425   // notice that the routing info has changed and start the process of
426   // downloading updates for newly added data types.  Once this is
427   // complete, the configure_state_.ready_task_ is run via an
428   // OnInitializationComplete notification.
429 
430   if (pending_config_mode_state_->deleted_type) {
431     core_thread_.message_loop()->PostTask(FROM_HERE,
432         NewRunnableMethod(core_.get(),
433         &SyncBackendHost::Core::DeferNudgeForCleanup));
434   }
435 
436   if (pending_config_mode_state_->added_types.none() &&
437       !core_->syncapi()->InitialSyncEndedForAllEnabledTypes()) {
438     LOG(WARNING) << "No new types, but initial sync not finished."
439                  << "Possible sync db corruption / removal.";
440     // TODO(tim): Log / UMA / count this somehow?
441     // TODO(tim): If no added types, we could (should?) config only for
442     // types that are needed... but this is a rare corruption edge case or
443     // implies the user mucked around with their syncdb, so for now do all.
444     pending_config_mode_state_->added_types =
445         syncable::ModelTypeBitSetFromSet(
446             pending_config_mode_state_->initial_types);
447   }
448 
449   // If we've added types, we always want to request a nudge/config (even if
450   // the initial sync is ended), in case we could not decrypt the data.
451   if (pending_config_mode_state_->added_types.none()) {
452     // No new types - just notify the caller that the types are available.
453     pending_config_mode_state_->ready_task->Run();
454   } else {
455     pending_download_state_.reset(pending_config_mode_state_.release());
456 
457     syncable::ModelTypeBitSet types_copy(pending_download_state_->added_types);
458     if (IsNigoriEnabled())
459       types_copy.set(syncable::NIGORI);
460     core_thread_.message_loop()->PostTask(FROM_HERE,
461          NewRunnableMethod(core_.get(),
462                            &SyncBackendHost::Core::DoRequestConfig,
463                            types_copy));
464   }
465 
466   pending_config_mode_state_.reset();
467 
468   // Notify the SyncManager about the new types.
469   core_thread_.message_loop()->PostTask(FROM_HERE,
470       NewRunnableMethod(core_.get(),
471                         &SyncBackendHost::Core::DoUpdateEnabledTypes));
472 }
473 
EncryptDataTypes(const syncable::ModelTypeSet & encrypted_types)474 void SyncBackendHost::EncryptDataTypes(
475     const syncable::ModelTypeSet& encrypted_types) {
476   core_thread_.message_loop()->PostTask(FROM_HERE,
477      NewRunnableMethod(core_.get(),
478                        &SyncBackendHost::Core::DoEncryptDataTypes,
479                        encrypted_types));
480 }
481 
RequestNudge(const tracked_objects::Location & location)482 void SyncBackendHost::RequestNudge(const tracked_objects::Location& location) {
483   core_thread_.message_loop()->PostTask(FROM_HERE,
484       NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoRequestNudge,
485                         location));
486 }
487 
ActivateDataType(DataTypeController * data_type_controller,ChangeProcessor * change_processor)488 void SyncBackendHost::ActivateDataType(
489     DataTypeController* data_type_controller,
490     ChangeProcessor* change_processor) {
491   base::AutoLock lock(registrar_lock_);
492 
493   // Ensure that the given data type is in the PASSIVE group.
494   browser_sync::ModelSafeRoutingInfo::iterator i =
495       registrar_.routing_info.find(data_type_controller->type());
496   DCHECK(i != registrar_.routing_info.end());
497   DCHECK((*i).second == GROUP_PASSIVE);
498   syncable::ModelType type = data_type_controller->type();
499   // Change the data type's routing info to its group.
500   registrar_.routing_info[type] = data_type_controller->model_safe_group();
501 
502   // Add the data type's change processor to the list of change
503   // processors so it can receive updates.
504   DCHECK_EQ(processors_.count(type), 0U);
505   processors_[type] = change_processor;
506 }
507 
DeactivateDataType(DataTypeController * data_type_controller,ChangeProcessor * change_processor)508 void SyncBackendHost::DeactivateDataType(
509     DataTypeController* data_type_controller,
510     ChangeProcessor* change_processor) {
511   base::AutoLock lock(registrar_lock_);
512   registrar_.routing_info.erase(data_type_controller->type());
513 
514   std::map<syncable::ModelType, ChangeProcessor*>::size_type erased =
515       processors_.erase(data_type_controller->type());
516   DCHECK_EQ(erased, 1U);
517 }
518 
RequestClearServerData()519 bool SyncBackendHost::RequestClearServerData() {
520   core_thread_.message_loop()->PostTask(FROM_HERE,
521      NewRunnableMethod(core_.get(),
522      &SyncBackendHost::Core::DoRequestClearServerData));
523   return true;
524 }
525 
~Core()526 SyncBackendHost::Core::~Core() {
527 }
528 
NotifyPassphraseRequired(bool for_decryption)529 void SyncBackendHost::Core::NotifyPassphraseRequired(bool for_decryption) {
530   if (!host_ || !host_->frontend_)
531     return;
532 
533   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
534 
535   if (processing_passphrase_) {
536     VLOG(1) << "Core received OnPassphraseRequired while processing a "
537             << "passphrase. Silently dropping.";
538     return;
539   }
540   host_->frontend_->OnPassphraseRequired(for_decryption);
541 }
542 
NotifyPassphraseFailed()543 void SyncBackendHost::Core::NotifyPassphraseFailed() {
544   if (!host_ || !host_->frontend_)
545     return;
546 
547   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
548 
549   // When a passphrase fails, we just unset our waiting flag and trigger a
550   // OnPassphraseRequired(true).
551   processing_passphrase_ = false;
552   host_->frontend_->OnPassphraseRequired(true);
553 }
554 
NotifyPassphraseAccepted(const std::string & bootstrap_token)555 void SyncBackendHost::Core::NotifyPassphraseAccepted(
556     const std::string& bootstrap_token) {
557   if (!host_ || !host_->frontend_)
558     return;
559 
560   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
561 
562   processing_passphrase_ = false;
563   host_->PersistEncryptionBootstrapToken(bootstrap_token);
564   host_->frontend_->OnPassphraseAccepted();
565 }
566 
NotifyUpdatedToken(const std::string & token)567 void SyncBackendHost::Core::NotifyUpdatedToken(const std::string& token) {
568   if (!host_)
569     return;
570   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
571   TokenAvailableDetails details(GaiaConstants::kSyncService, token);
572   NotificationService::current()->Notify(
573       NotificationType::TOKEN_UPDATED,
574       NotificationService::AllSources(),
575       Details<const TokenAvailableDetails>(&details));
576 }
577 
NotifyEncryptionComplete(const syncable::ModelTypeSet & encrypted_types)578 void SyncBackendHost::Core::NotifyEncryptionComplete(
579     const syncable::ModelTypeSet& encrypted_types) {
580   if (!host_)
581     return;
582   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
583   host_->frontend_->OnEncryptionComplete(encrypted_types);
584 }
585 
FinishConfigureDataTypes()586 void SyncBackendHost::Core::FinishConfigureDataTypes() {
587   host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
588       &SyncBackendHost::Core::FinishConfigureDataTypesOnFrontendLoop));
589 }
590 
FinishConfigureDataTypesOnFrontendLoop()591 void SyncBackendHost::Core::FinishConfigureDataTypesOnFrontendLoop() {
592   host_->FinishConfigureDataTypesOnFrontendLoop();
593 }
594 
595 
CreateSyncNotifier(const scoped_refptr<net::URLRequestContextGetter> & request_context_getter)596 void SyncBackendHost::Core::CreateSyncNotifier(
597     const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) {
598   const std::string& client_info = webkit_glue::GetUserAgent(GURL());
599   SyncNotifierFactory sync_notifier_factory(client_info);
600   sync_notifier_.reset(sync_notifier_factory.CreateSyncNotifier(
601       *CommandLine::ForCurrentProcess(),
602       request_context_getter));
603 }
604 
DoInitializeOptions(const GURL & service_url,sync_api::HttpPostProviderFactory * http_bridge_factory,const sync_api::SyncCredentials & credentials,bool delete_sync_data_folder,const std::string & restored_key_for_bootstrapping,bool setup_for_test_mode)605 SyncBackendHost::Core::DoInitializeOptions::DoInitializeOptions(
606     const GURL& service_url,
607     sync_api::HttpPostProviderFactory* http_bridge_factory,
608     const sync_api::SyncCredentials& credentials,
609     bool delete_sync_data_folder,
610     const std::string& restored_key_for_bootstrapping,
611     bool setup_for_test_mode)
612     : service_url(service_url),
613       http_bridge_factory(http_bridge_factory),
614       credentials(credentials),
615       delete_sync_data_folder(delete_sync_data_folder),
616       restored_key_for_bootstrapping(restored_key_for_bootstrapping),
617       setup_for_test_mode(setup_for_test_mode) {
618 }
619 
~DoInitializeOptions()620 SyncBackendHost::Core::DoInitializeOptions::~DoInitializeOptions() {}
621 
GetUserShare() const622 sync_api::UserShare* SyncBackendHost::GetUserShare() const {
623   DCHECK(syncapi_initialized_);
624   return core_->syncapi()->GetUserShare();
625 }
626 
GetDetailedStatus()627 SyncBackendHost::Status SyncBackendHost::GetDetailedStatus() {
628   DCHECK(syncapi_initialized_);
629   return core_->syncapi()->GetDetailedStatus();
630 }
631 
GetStatusSummary()632 SyncBackendHost::StatusSummary SyncBackendHost::GetStatusSummary() {
633   DCHECK(syncapi_initialized_);
634   return core_->syncapi()->GetStatusSummary();
635 }
636 
GetAuthenticatedUsername() const637 string16 SyncBackendHost::GetAuthenticatedUsername() const {
638   DCHECK(syncapi_initialized_);
639   return UTF8ToUTF16(core_->syncapi()->GetAuthenticatedUsername());
640 }
641 
GetAuthError() const642 const GoogleServiceAuthError& SyncBackendHost::GetAuthError() const {
643   return last_auth_error_;
644 }
645 
GetLastSessionSnapshot() const646 const SyncSessionSnapshot* SyncBackendHost::GetLastSessionSnapshot() const {
647   return last_snapshot_.get();
648 }
649 
GetWorkers(std::vector<ModelSafeWorker * > * out)650 void SyncBackendHost::GetWorkers(std::vector<ModelSafeWorker*>* out) {
651   base::AutoLock lock(registrar_lock_);
652   out->clear();
653   for (WorkerMap::const_iterator it = registrar_.workers.begin();
654        it != registrar_.workers.end(); ++it) {
655     out->push_back((*it).second);
656   }
657 }
658 
GetModelSafeRoutingInfo(ModelSafeRoutingInfo * out)659 void SyncBackendHost::GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
660   base::AutoLock lock(registrar_lock_);
661   ModelSafeRoutingInfo copy(registrar_.routing_info);
662   out->swap(copy);
663 }
664 
HasUnsyncedItems() const665 bool SyncBackendHost::HasUnsyncedItems() const {
666   DCHECK(syncapi_initialized_);
667   return core_->syncapi()->HasUnsyncedItems();
668 }
669 
Core(SyncBackendHost * backend)670 SyncBackendHost::Core::Core(SyncBackendHost* backend)
671     : host_(backend),
672       syncapi_(new sync_api::SyncManager()),
673       sync_manager_observer_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
674       parent_router_(NULL),
675       processing_passphrase_(false),
676       deferred_nudge_for_cleanup_requested_(false) {
677 }
678 
679 // Helper to construct a user agent string (ASCII) suitable for use by
680 // the syncapi for any HTTP communication. This string is used by the sync
681 // backend for classifying client types when calculating statistics.
MakeUserAgentForSyncapi()682 std::string MakeUserAgentForSyncapi() {
683   std::string user_agent;
684   user_agent = "Chrome ";
685 #if defined(OS_WIN)
686   user_agent += "WIN ";
687 #elif defined(OS_LINUX)
688   user_agent += "LINUX ";
689 #elif defined(OS_FREEBSD)
690   user_agent += "FREEBSD ";
691 #elif defined(OS_OPENBSD)
692   user_agent += "OPENBSD ";
693 #elif defined(OS_MACOSX)
694   user_agent += "MAC ";
695 #endif
696   chrome::VersionInfo version_info;
697   if (!version_info.is_valid()) {
698     DLOG(ERROR) << "Unable to create chrome::VersionInfo object";
699     return user_agent;
700   }
701 
702   user_agent += version_info.Version();
703   user_agent += " (" + version_info.LastChange() + ")";
704   if (!version_info.IsOfficialBuild())
705     user_agent += "-devel";
706   return user_agent;
707 }
708 
DoInitialize(const DoInitializeOptions & options)709 void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
710   DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
711   processing_passphrase_ = false;
712 
713   // Blow away the partial or corrupt sync data folder before doing any more
714   // initialization, if necessary.
715   if (options.delete_sync_data_folder) {
716     DeleteSyncDataFolder();
717   }
718 
719   // Make sure that the directory exists before initializing the backend.
720   // If it already exists, this will do no harm.
721   bool success = file_util::CreateDirectory(host_->sync_data_folder_path());
722   DCHECK(success);
723 
724   syncapi_->AddObserver(this);
725   const FilePath& path_str = host_->sync_data_folder_path();
726   success = syncapi_->Init(
727       path_str,
728       (options.service_url.host() + options.service_url.path()).c_str(),
729       options.service_url.EffectiveIntPort(),
730       options.service_url.SchemeIsSecure(),
731       options.http_bridge_factory,
732       host_,  // ModelSafeWorkerRegistrar.
733       MakeUserAgentForSyncapi().c_str(),
734       options.credentials,
735       sync_notifier_.get(),
736       options.restored_key_for_bootstrapping,
737       options.setup_for_test_mode);
738   DCHECK(success) << "Syncapi initialization failed!";
739 }
740 
DoUpdateCredentials(const SyncCredentials & credentials)741 void SyncBackendHost::Core::DoUpdateCredentials(
742     const SyncCredentials& credentials) {
743   DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
744   syncapi_->UpdateCredentials(credentials);
745 }
746 
DoUpdateEnabledTypes()747 void SyncBackendHost::Core::DoUpdateEnabledTypes() {
748   DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
749   syncapi_->UpdateEnabledTypes();
750 }
751 
DoStartSyncing()752 void SyncBackendHost::Core::DoStartSyncing() {
753   DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
754   syncapi_->StartSyncing();
755   if (deferred_nudge_for_cleanup_requested_)
756     syncapi_->RequestNudge(FROM_HERE);
757   deferred_nudge_for_cleanup_requested_ = false;
758 }
759 
DoSetPassphrase(const std::string & passphrase,bool is_explicit)760 void SyncBackendHost::Core::DoSetPassphrase(const std::string& passphrase,
761                                             bool is_explicit) {
762   DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
763   syncapi_->SetPassphrase(passphrase, is_explicit);
764 }
765 
processing_passphrase() const766 bool SyncBackendHost::Core::processing_passphrase() const {
767   DCHECK(MessageLoop::current() == host_->frontend_loop_);
768   return processing_passphrase_;
769 }
770 
set_processing_passphrase()771 void SyncBackendHost::Core::set_processing_passphrase() {
772   DCHECK(MessageLoop::current() == host_->frontend_loop_);
773   processing_passphrase_ = true;
774 }
775 
DoEncryptDataTypes(const syncable::ModelTypeSet & encrypted_types)776 void SyncBackendHost::Core::DoEncryptDataTypes(
777     const syncable::ModelTypeSet& encrypted_types) {
778   DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
779   syncapi_->EncryptDataTypes(encrypted_types);
780 }
781 
DoRequestConfig(const syncable::ModelTypeBitSet & added_types)782 void SyncBackendHost::Core::DoRequestConfig(
783     const syncable::ModelTypeBitSet& added_types) {
784   syncapi_->RequestConfig(added_types);
785 }
786 
DoStartConfiguration(Callback0::Type * callback)787 void SyncBackendHost::Core::DoStartConfiguration(Callback0::Type* callback) {
788   syncapi_->StartConfigurationMode(callback);
789 }
790 
ui_worker()791 UIModelWorker* SyncBackendHost::ui_worker() {
792   ModelSafeWorker* w = registrar_.workers[GROUP_UI];
793   if (w == NULL)
794     return NULL;
795   if (w->GetModelSafeGroup() != GROUP_UI)
796     NOTREACHED();
797   return static_cast<UIModelWorker*>(w);
798 }
799 
DoShutdown(bool sync_disabled)800 void SyncBackendHost::Core::DoShutdown(bool sync_disabled) {
801   DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
802 
803   save_changes_timer_.Stop();
804   syncapi_->Shutdown();  // Stops the SyncerThread.
805   syncapi_->RemoveObserver(this);
806   DisconnectChildJsEventRouter();
807   host_->ui_worker()->OnSyncerShutdownComplete();
808 
809   if (sync_disabled)
810     DeleteSyncDataFolder();
811 
812   host_ = NULL;
813 }
814 
GetProcessor(syncable::ModelType model_type)815 ChangeProcessor* SyncBackendHost::Core::GetProcessor(
816     syncable::ModelType model_type) {
817   std::map<syncable::ModelType, ChangeProcessor*>::const_iterator it =
818       host_->processors_.find(model_type);
819 
820   // Until model association happens for a datatype, it will not appear in
821   // the processors list.  During this time, it is OK to drop changes on
822   // the floor (since model association has not happened yet).  When the
823   // data type is activated, model association takes place then the change
824   // processor is added to the processors_ list.  This all happens on
825   // the UI thread so we will never drop any changes after model
826   // association.
827   if (it == host_->processors_.end())
828     return NULL;
829 
830   if (!IsCurrentThreadSafeForModel(model_type)) {
831     NOTREACHED() << "Changes applied on wrong thread.";
832     return NULL;
833   }
834 
835   // Now that we're sure we're on the correct thread, we can access the
836   // ChangeProcessor.
837   ChangeProcessor* processor = it->second;
838 
839   // Ensure the change processor is willing to accept changes.
840   if (!processor->IsRunning())
841     return NULL;
842 
843   return processor;
844 }
845 
OnChangesApplied(syncable::ModelType model_type,const sync_api::BaseTransaction * trans,const sync_api::SyncManager::ChangeRecord * changes,int change_count)846 void SyncBackendHost::Core::OnChangesApplied(
847     syncable::ModelType model_type,
848     const sync_api::BaseTransaction* trans,
849     const sync_api::SyncManager::ChangeRecord* changes,
850     int change_count) {
851   if (!host_ || !host_->frontend_) {
852     DCHECK(false) << "OnChangesApplied called after Shutdown?";
853     return;
854   }
855   ChangeProcessor* processor = GetProcessor(model_type);
856   if (!processor)
857     return;
858 
859   processor->ApplyChangesFromSyncModel(trans, changes, change_count);
860 }
861 
OnChangesComplete(syncable::ModelType model_type)862 void SyncBackendHost::Core::OnChangesComplete(
863     syncable::ModelType model_type) {
864   if (!host_ || !host_->frontend_) {
865     DCHECK(false) << "OnChangesComplete called after Shutdown?";
866     return;
867   }
868 
869   ChangeProcessor* processor = GetProcessor(model_type);
870   if (!processor)
871     return;
872 
873   // This call just notifies the processor that it can commit, it already
874   // buffered any changes it plans to makes so needs no further information.
875   processor->CommitChangesFromSyncModel();
876 }
877 
878 
OnSyncCycleCompleted(const SyncSessionSnapshot * snapshot)879 void SyncBackendHost::Core::OnSyncCycleCompleted(
880     const SyncSessionSnapshot* snapshot) {
881   host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
882       &Core::HandleSyncCycleCompletedOnFrontendLoop,
883       new SyncSessionSnapshot(*snapshot)));
884 }
885 
HandleSyncCycleCompletedOnFrontendLoop(SyncSessionSnapshot * snapshot)886 void SyncBackendHost::Core::HandleSyncCycleCompletedOnFrontendLoop(
887     SyncSessionSnapshot* snapshot) {
888   if (!host_ || !host_->frontend_)
889     return;
890   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
891 
892   host_->last_snapshot_.reset(snapshot);
893 
894   const syncable::ModelTypeSet& to_migrate =
895       snapshot->syncer_status.types_needing_local_migration;
896   if (!to_migrate.empty())
897     host_->frontend_->OnMigrationNeededForTypes(to_migrate);
898 
899   // If we are waiting for a configuration change, check here to see
900   // if this sync cycle has initialized all of the types we've been
901   // waiting for.
902   if (host_->pending_download_state_.get()) {
903     bool found_all_added = true;
904     for (syncable::ModelTypeSet::const_iterator it =
905              host_->pending_download_state_->initial_types.begin();
906          it != host_->pending_download_state_->initial_types.end();
907          ++it) {
908       if (host_->pending_download_state_->added_types.test(*it))
909         found_all_added &= snapshot->initial_sync_ended.test(*it);
910     }
911     if (!found_all_added) {
912       NOTREACHED() << "Update didn't return updates for all types requested.";
913     } else {
914       host_->pending_download_state_->ready_task->Run();
915     }
916     host_->pending_download_state_.reset();
917   }
918   host_->frontend_->OnSyncCycleCompleted();
919 }
920 
OnInitializationComplete()921 void SyncBackendHost::Core::OnInitializationComplete() {
922   if (!host_ || !host_->frontend_)
923     return;  // We may have been told to Shutdown before initialization
924              // completed.
925 
926   // We could be on some random sync backend thread, so MessageLoop::current()
927   // can definitely be null in here.
928   host_->frontend_loop_->PostTask(FROM_HERE,
929       NewRunnableMethod(this,
930                         &Core::HandleInitalizationCompletedOnFrontendLoop));
931 
932   // Initialization is complete, so we can schedule recurring SaveChanges.
933   host_->core_thread_.message_loop()->PostTask(FROM_HERE,
934       NewRunnableMethod(this, &Core::StartSavingChanges));
935 }
936 
HandleInitalizationCompletedOnFrontendLoop()937 void SyncBackendHost::Core::HandleInitalizationCompletedOnFrontendLoop() {
938   if (!host_)
939     return;
940   host_->HandleInitializationCompletedOnFrontendLoop();
941 }
942 
HandleInitializationCompletedOnFrontendLoop()943 void SyncBackendHost::HandleInitializationCompletedOnFrontendLoop() {
944   if (!frontend_)
945     return;
946   syncapi_initialized_ = true;
947   frontend_->OnBackendInitialized();
948 }
949 
IsCurrentThreadSafeForModel(syncable::ModelType model_type)950 bool SyncBackendHost::Core::IsCurrentThreadSafeForModel(
951     syncable::ModelType model_type) {
952   base::AutoLock lock(host_->registrar_lock_);
953 
954   browser_sync::ModelSafeRoutingInfo::const_iterator routing_it =
955       host_->registrar_.routing_info.find(model_type);
956   if (routing_it == host_->registrar_.routing_info.end())
957     return false;
958   browser_sync::ModelSafeGroup group = routing_it->second;
959   WorkerMap::const_iterator worker_it = host_->registrar_.workers.find(group);
960   if (worker_it == host_->registrar_.workers.end())
961     return false;
962   ModelSafeWorker* worker = worker_it->second;
963   return worker->CurrentThreadIsWorkThread();
964 }
965 
OnAuthError(const AuthError & auth_error)966 void SyncBackendHost::Core::OnAuthError(const AuthError& auth_error) {
967   // Post to our core loop so we can modify state. Could be on another thread.
968   host_->frontend_loop_->PostTask(FROM_HERE,
969       NewRunnableMethod(this, &Core::HandleAuthErrorEventOnFrontendLoop,
970       auth_error));
971 }
972 
OnPassphraseRequired(bool for_decryption)973 void SyncBackendHost::Core::OnPassphraseRequired(bool for_decryption) {
974   host_->frontend_loop_->PostTask(FROM_HERE,
975       NewRunnableMethod(this, &Core::NotifyPassphraseRequired, for_decryption));
976 }
977 
OnPassphraseFailed()978 void SyncBackendHost::Core::OnPassphraseFailed() {
979   host_->frontend_loop_->PostTask(FROM_HERE,
980       NewRunnableMethod(this, &Core::NotifyPassphraseFailed));
981 }
982 
OnPassphraseAccepted(const std::string & bootstrap_token)983 void SyncBackendHost::Core::OnPassphraseAccepted(
984     const std::string& bootstrap_token) {
985   host_->frontend_loop_->PostTask(FROM_HERE,
986       NewRunnableMethod(this, &Core::NotifyPassphraseAccepted,
987           bootstrap_token));
988 }
989 
OnStopSyncingPermanently()990 void SyncBackendHost::Core::OnStopSyncingPermanently() {
991   host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
992       &Core::HandleStopSyncingPermanentlyOnFrontendLoop));
993 }
994 
OnUpdatedToken(const std::string & token)995 void SyncBackendHost::Core::OnUpdatedToken(const std::string& token) {
996   host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
997       &Core::NotifyUpdatedToken, token));
998 }
999 
OnClearServerDataSucceeded()1000 void SyncBackendHost::Core::OnClearServerDataSucceeded() {
1001   host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
1002       &Core::HandleClearServerDataSucceededOnFrontendLoop));
1003 }
1004 
OnClearServerDataFailed()1005 void SyncBackendHost::Core::OnClearServerDataFailed() {
1006   host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
1007       &Core::HandleClearServerDataFailedOnFrontendLoop));
1008 }
1009 
OnEncryptionComplete(const syncable::ModelTypeSet & encrypted_types)1010 void SyncBackendHost::Core::OnEncryptionComplete(
1011     const syncable::ModelTypeSet& encrypted_types) {
1012   host_->frontend_loop_->PostTask(
1013       FROM_HERE,
1014       NewRunnableMethod(this, &Core::NotifyEncryptionComplete,
1015                         encrypted_types));
1016 }
1017 
RouteJsEvent(const std::string & name,const JsArgList & args,const JsEventHandler * target)1018 void SyncBackendHost::Core::RouteJsEvent(
1019     const std::string& name, const JsArgList& args,
1020     const JsEventHandler* target) {
1021   host_->frontend_loop_->PostTask(
1022       FROM_HERE, NewRunnableMethod(
1023           this, &Core::RouteJsEventOnFrontendLoop, name, args, target));
1024 }
1025 
HandleStopSyncingPermanentlyOnFrontendLoop()1026 void SyncBackendHost::Core::HandleStopSyncingPermanentlyOnFrontendLoop() {
1027   if (!host_ || !host_->frontend_)
1028     return;
1029   host_->frontend_->OnStopSyncingPermanently();
1030 }
1031 
HandleClearServerDataSucceededOnFrontendLoop()1032 void SyncBackendHost::Core::HandleClearServerDataSucceededOnFrontendLoop() {
1033   if (!host_ || !host_->frontend_)
1034     return;
1035   host_->frontend_->OnClearServerDataSucceeded();
1036 }
1037 
HandleClearServerDataFailedOnFrontendLoop()1038 void SyncBackendHost::Core::HandleClearServerDataFailedOnFrontendLoop() {
1039   if (!host_ || !host_->frontend_)
1040     return;
1041   host_->frontend_->OnClearServerDataFailed();
1042 }
1043 
HandleAuthErrorEventOnFrontendLoop(const GoogleServiceAuthError & new_auth_error)1044 void SyncBackendHost::Core::HandleAuthErrorEventOnFrontendLoop(
1045     const GoogleServiceAuthError& new_auth_error) {
1046   if (!host_ || !host_->frontend_)
1047     return;
1048 
1049   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
1050 
1051   host_->last_auth_error_ = new_auth_error;
1052   host_->frontend_->OnAuthError();
1053 }
1054 
RouteJsEventOnFrontendLoop(const std::string & name,const JsArgList & args,const JsEventHandler * target)1055 void SyncBackendHost::Core::RouteJsEventOnFrontendLoop(
1056     const std::string& name, const JsArgList& args,
1057     const JsEventHandler* target) {
1058   if (!host_ || !parent_router_)
1059     return;
1060 
1061   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
1062 
1063   parent_router_->RouteJsEvent(name, args, target);
1064 }
1065 
StartSavingChanges()1066 void SyncBackendHost::Core::StartSavingChanges() {
1067   save_changes_timer_.Start(
1068       base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds),
1069       this, &Core::SaveChanges);
1070 }
1071 
DoRequestNudge(const tracked_objects::Location & nudge_location)1072 void SyncBackendHost::Core::DoRequestNudge(
1073     const tracked_objects::Location& nudge_location) {
1074   syncapi_->RequestNudge(nudge_location);
1075 }
1076 
DoRequestClearServerData()1077 void SyncBackendHost::Core::DoRequestClearServerData() {
1078   syncapi_->RequestClearServerData();
1079 }
1080 
SaveChanges()1081 void SyncBackendHost::Core::SaveChanges() {
1082   syncapi_->SaveChanges();
1083 }
1084 
DeleteSyncDataFolder()1085 void SyncBackendHost::Core::DeleteSyncDataFolder() {
1086   if (file_util::DirectoryExists(host_->sync_data_folder_path())) {
1087     if (!file_util::Delete(host_->sync_data_folder_path(), true))
1088       LOG(DFATAL) << "Could not delete the Sync Data folder.";
1089   }
1090 }
1091 
SetParentJsEventRouter(JsEventRouter * router)1092 void SyncBackendHost::Core::SetParentJsEventRouter(JsEventRouter* router) {
1093   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
1094   DCHECK(router);
1095   parent_router_ = router;
1096   MessageLoop* core_message_loop = host_->core_thread_.message_loop();
1097   CHECK(core_message_loop);
1098   core_message_loop->PostTask(
1099       FROM_HERE,
1100       NewRunnableMethod(this,
1101                         &SyncBackendHost::Core::ConnectChildJsEventRouter));
1102 }
1103 
RemoveParentJsEventRouter()1104 void SyncBackendHost::Core::RemoveParentJsEventRouter() {
1105   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
1106   parent_router_ = NULL;
1107   MessageLoop* core_message_loop = host_->core_thread_.message_loop();
1108   CHECK(core_message_loop);
1109   core_message_loop->PostTask(
1110       FROM_HERE,
1111       NewRunnableMethod(this,
1112                         &SyncBackendHost::Core::DisconnectChildJsEventRouter));
1113 }
1114 
GetParentJsEventRouter() const1115 const JsEventRouter* SyncBackendHost::Core::GetParentJsEventRouter() const {
1116   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
1117   return parent_router_;
1118 }
1119 
ProcessMessage(const std::string & name,const JsArgList & args,const JsEventHandler * sender)1120 void SyncBackendHost::Core::ProcessMessage(
1121     const std::string& name, const JsArgList& args,
1122     const JsEventHandler* sender) {
1123   DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
1124   MessageLoop* core_message_loop = host_->core_thread_.message_loop();
1125   CHECK(core_message_loop);
1126   core_message_loop->PostTask(
1127       FROM_HERE,
1128       NewRunnableMethod(this,
1129                         &SyncBackendHost::Core::DoProcessMessage,
1130                         name, args, sender));
1131 }
1132 
ConnectChildJsEventRouter()1133 void SyncBackendHost::Core::ConnectChildJsEventRouter() {
1134   DCHECK_EQ(MessageLoop::current(), host_->core_thread_.message_loop());
1135   // We need this check since AddObserver() can be called at most once
1136   // for a given observer.
1137   if (!syncapi_->GetJsBackend()->GetParentJsEventRouter()) {
1138     syncapi_->GetJsBackend()->SetParentJsEventRouter(this);
1139     syncapi_->AddObserver(&sync_manager_observer_);
1140   }
1141 }
1142 
DisconnectChildJsEventRouter()1143 void SyncBackendHost::Core::DisconnectChildJsEventRouter() {
1144   DCHECK_EQ(MessageLoop::current(), host_->core_thread_.message_loop());
1145   syncapi_->GetJsBackend()->RemoveParentJsEventRouter();
1146   syncapi_->RemoveObserver(&sync_manager_observer_);
1147 }
1148 
DoProcessMessage(const std::string & name,const JsArgList & args,const JsEventHandler * sender)1149 void SyncBackendHost::Core::DoProcessMessage(
1150     const std::string& name, const JsArgList& args,
1151     const JsEventHandler* sender) {
1152   DCHECK_EQ(MessageLoop::current(), host_->core_thread_.message_loop());
1153   syncapi_->GetJsBackend()->ProcessMessage(name, args, sender);
1154 }
1155 
DeferNudgeForCleanup()1156 void SyncBackendHost::Core::DeferNudgeForCleanup() {
1157   DCHECK_EQ(MessageLoop::current(), host_->core_thread_.message_loop());
1158   deferred_nudge_for_cleanup_requested_ = true;
1159 }
1160 
1161 }  // namespace browser_sync
1162