| Index: chrome/browser/sync/glue/sync_backend_host.cc
|
| ===================================================================
|
| --- chrome/browser/sync/glue/sync_backend_host.cc (revision 0)
|
| +++ chrome/browser/sync/glue/sync_backend_host.cc (revision 0)
|
| @@ -0,0 +1,308 @@
|
| +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#ifdef CHROME_PERSONALIZATION
|
| +
|
| +#include "base/file_version_info.h"
|
| +#include "base/file_util.h"
|
| +#include "base/string_util.h"
|
| +#include "chrome/browser/sync/glue/sync_backend_host.h"
|
| +#include "chrome/browser/sync/glue/http_bridge.h"
|
| +#include "chrome/browser/sync/glue/bookmark_model_worker.h"
|
| +#include "webkit/glue/webkit_glue.h"
|
| +
|
| +static const char kSwitchSyncServiceURL[] = "sync-url";
|
| +static const char kSwitchSyncServicePort[] = "sync-port";
|
| +static const int kSaveChangesIntervalSeconds = 10;
|
| +static const char kGaiaServiceId[] = "chromiumsync";
|
| +static const char kGaiaSourceForChrome[] = "ChromiumBrowser";
|
| +static const FilePath::CharType kSyncDataFolderName[] =
|
| + FILE_PATH_LITERAL("Sync Data");
|
| +
|
| +namespace browser_sync {
|
| +
|
| +SyncBackendHost::SyncBackendHost(SyncFrontend* frontend,
|
| + const FilePath& profile_path)
|
| + : core_thread_("Chrome_SyncCoreThread"),
|
| + frontend_loop_(MessageLoop::current()),
|
| + bookmark_model_worker_(NULL),
|
| + frontend_(frontend),
|
| + sync_data_folder_path_(profile_path.Append(kSyncDataFolderName)),
|
| + last_auth_error_(AUTH_ERROR_NONE) {
|
| + core_ = new Core(this);
|
| +}
|
| +
|
| +SyncBackendHost::~SyncBackendHost() {
|
| + DCHECK(!core_ && !frontend_) << "Must call Shutdown before destructor.";
|
| +}
|
| +
|
| +void SyncBackendHost::Initialize(const GURL& sync_service_url) {
|
| + if (!core_thread_.Start())
|
| + return;
|
| +
|
| + bookmark_model_worker_ = new BookmarkModelWorker(frontend_loop_);
|
| + core_thread_.message_loop()->PostTask(FROM_HERE,
|
| + NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize,
|
| + sync_service_url, bookmark_model_worker_, true));
|
| +}
|
| +
|
| +void SyncBackendHost::Authenticate(const std::string& username,
|
| + const std::string& password) {
|
| + core_thread_.message_loop()->PostTask(FROM_HERE,
|
| + NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoAuthenticate,
|
| + username, password));
|
| +}
|
| +
|
| +void SyncBackendHost::Shutdown(bool sync_disabled) {
|
| + // Thread shutdown should occur in the following order:
|
| + // - SyncerThread
|
| + // - CoreThread
|
| + // - UI Thread (stops some time after we return from this call).
|
| + core_thread_.message_loop()->PostTask(FROM_HERE,
|
| + NewRunnableMethod(core_.get(),
|
| + &SyncBackendHost::Core::DoShutdown,
|
| + sync_disabled));
|
| +
|
| + // Before joining the core_thread_, we wait for the BookmarkModelWorker to
|
| + // give us the green light that it is not depending on the frontend_loop_ to
|
| + // process any more tasks. Stop() blocks until this termination condition
|
| + // is true.
|
| + bookmark_model_worker_->Stop();
|
| +
|
| + // Stop will return once the thread exits, which will be after DoShutdown
|
| + // runs. DoShutdown needs to run from core_thread_ because the sync backend
|
| + // requires any thread that opened sqlite handles to relinquish them
|
| + // personally. We need to join threads, because otherwise the main Chrome
|
| + // thread (ui loop) can exit before DoShutdown finishes, at which point
|
| + // virtually anything the sync backend does (or the post-back to
|
| + // frontend_loop_ by our Core) will epically fail because the CRT won't be
|
| + // initialized. For now this only ever happens at sync-enabled-Chrome exit,
|
| + // meaning bug 1482548 applies to prolonged "waiting" that may occur in
|
| + // DoShutdown.
|
| + core_thread_.Stop();
|
| +
|
| + bookmark_model_worker_ = NULL;
|
| + frontend_ = NULL;
|
| + core_ = NULL; // Releases reference to core_.
|
| +}
|
| +
|
| +void SyncBackendHost::Core::NotifyFrontend(FrontendNotification notification) {
|
| + if (!host_ || !host_->frontend_) {
|
| + return; // This can happen in testing because the UI loop processes tasks
|
| + // after an instance of SyncBackendHost was destroyed. In real
|
| + // life this doesn't happen.
|
| + }
|
| + switch (notification) {
|
| + case INITIALIZED:
|
| + host_->frontend_->OnBackendInitialized();
|
| + return;
|
| + case SYNC_CYCLE_COMPLETED:
|
| + host_->frontend_->OnSyncCycleCompleted();
|
| + return;
|
| + }
|
| +}
|
| +
|
| +SyncBackendHost::UserShareHandle SyncBackendHost::GetUserShareHandle() const {
|
| + return core_->syncapi()->GetUserShare();
|
| +}
|
| +
|
| +SyncBackendHost::Status SyncBackendHost::GetDetailedStatus() {
|
| + return core_->syncapi()->GetDetailedStatus();
|
| +}
|
| +
|
| +SyncBackendHost::StatusSummary SyncBackendHost::GetStatusSummary() {
|
| + return core_->syncapi()->GetStatusSummary();
|
| +}
|
| +
|
| +string16 SyncBackendHost::GetAuthenticatedUsername() const {
|
| + return UTF8ToUTF16(core_->syncapi()->GetAuthenticatedUsername());
|
| +}
|
| +
|
| +AuthErrorState SyncBackendHost::GetAuthErrorState() const {
|
| + return last_auth_error_;
|
| +}
|
| +
|
| +SyncBackendHost::Core::Core(SyncBackendHost* backend)
|
| + : host_(backend),
|
| + syncapi_(new sync_api::SyncManager()) {
|
| +}
|
| +
|
| +// Helper to construct a user agent string (ASCII) suitable for use by
|
| +// the syncapi for any HTTP communication. This string is used by the sync
|
| +// backend for classifying client types when calculating statistics.
|
| +std::string MakeUserAgentForSyncapi() {
|
| + std::string user_agent;
|
| + user_agent = "Chrome ";
|
| +#if defined(OS_WIN)
|
| + user_agent += "WIN ";
|
| +#elif defined(OS_LINUX)
|
| + user_agent += "LINUX ";
|
| +#elif defined(OS_MACOSX)
|
| + user_agent += "MAC ";
|
| +#endif
|
| + scoped_ptr<FileVersionInfo> version_info(
|
| + FileVersionInfo::CreateFileVersionInfoForCurrentModule());
|
| + if (version_info == NULL) {
|
| + DLOG(ERROR) << "Unable to create FileVersionInfo object";
|
| + return user_agent;
|
| + }
|
| +
|
| + user_agent += WideToASCII(version_info->product_version());
|
| + user_agent += " (" + WideToASCII(version_info->last_change()) + ")";
|
| + if (!version_info->is_official_build())
|
| + user_agent += "-devel";
|
| + return user_agent;
|
| +}
|
| +
|
| +void SyncBackendHost::Core::DoInitialize(
|
| + const GURL& service_url,
|
| + BookmarkModelWorker* bookmark_model_worker,
|
| + bool attempt_last_user_authentication) {
|
| + DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
|
| +
|
| + // Make sure that the directory exists before initializing the backend.
|
| + // If it already exists, this will do no harm.
|
| + bool success = file_util::CreateDirectory(host_->sync_data_folder_path());
|
| + DCHECK(success);
|
| +
|
| + syncapi_->SetObserver(this);
|
| + string16 path_str;
|
| +#if defined (OS_WIN)
|
| + path_str = host_->sync_data_folder_path().value();
|
| +#elif (defined(OS_LINUX) || defined(OS_MACOSX))
|
| + path_str = UTF8ToUTF16(sync_data_folder_path().value());
|
| +#endif
|
| + success = syncapi_->Init(path_str.c_str(),
|
| + (service_url.host() + service_url.path()).c_str(),
|
| + service_url.EffectiveIntPort(),
|
| + kGaiaServiceId,
|
| + kGaiaSourceForChrome,
|
| + service_url.SchemeIsSecure(),
|
| + new HttpBridgeFactory(),
|
| + new HttpBridgeFactory(),
|
| + bookmark_model_worker,
|
| + attempt_last_user_authentication,
|
| + MakeUserAgentForSyncapi().c_str());
|
| + DCHECK(success) << "Syncapi initialization failed!";
|
| +}
|
| +
|
| +void SyncBackendHost::Core::DoAuthenticate(const std::string& username,
|
| + const std::string& password) {
|
| + DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
|
| + syncapi_->Authenticate(username.c_str(), password.c_str());
|
| +}
|
| +
|
| +void SyncBackendHost::Core::DoShutdown(bool sync_disabled) {
|
| + DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
|
| +
|
| + save_changes_timer_.Stop();
|
| + syncapi_->Shutdown(); // Stops the SyncerThread.
|
| + syncapi_->RemoveObserver();
|
| + host_->bookmark_model_worker_->OnSyncerShutdownComplete();
|
| +
|
| + if (sync_disabled &&
|
| + file_util::DirectoryExists(host_->sync_data_folder_path())) {
|
| + // Delete the sync data folder to cleanup backend data.
|
| + bool success = file_util::Delete(host_->sync_data_folder_path(), true);
|
| + DCHECK(success);
|
| + }
|
| +
|
| + host_ = NULL;
|
| +}
|
| +
|
| +static AuthErrorState AuthProblemToAuthError(
|
| + const sync_api::SyncManager::AuthProblem& auth_problem) {
|
| + switch (auth_problem) {
|
| + case sync_api::SyncManager::AUTH_PROBLEM_NONE:
|
| + return AUTH_ERROR_NONE;
|
| + case sync_api::SyncManager::AUTH_PROBLEM_INVALID_GAIA_CREDENTIALS:
|
| + return AUTH_ERROR_INVALID_GAIA_CREDENTIALS;
|
| + case sync_api::SyncManager::AUTH_PROBLEM_CONNECTION_FAILED:
|
| + return AUTH_ERROR_CONNECTION_FAILED;
|
| + case sync_api::SyncManager::AUTH_PROBLEM_USER_NOT_SIGNED_UP:
|
| + return AUTH_ERROR_USER_NOT_SIGNED_UP;
|
| + }
|
| +
|
| + NOTREACHED() << "Unknown AuthProblem.";
|
| + return AUTH_ERROR_NONE;
|
| +}
|
| +
|
| +void SyncBackendHost::Core::OnChangesApplied(
|
| + const sync_api::BaseTransaction* trans,
|
| + const sync_api::SyncManager::ChangeRecord* changes,
|
| + int change_count) {
|
| + if (!host_ || !host_->frontend_) {
|
| + DCHECK(false) << "OnChangesApplied called after Shutdown?";
|
| + return;
|
| + }
|
| +
|
| + // ChangesApplied is the one exception that should come over from the sync
|
| + // backend already on the service_loop_ thanks to our BookmarkModelWorker.
|
| + // SyncFrontend changes exclusively on the UI loop, because it updates
|
| + // the bookmark model. As such, we don't need to worry about changes that
|
| + // have been made to the bookmark model but not yet applied to the sync
|
| + // model -- such changes only happen on the UI loop, and there's no
|
| + // contention.
|
| + if (host_->frontend_loop_ != MessageLoop::current()) {
|
| + // TODO(ncarter): Bug 1480644. Make this a DCHECK once syncapi filters
|
| + // out all irrelevant changes.
|
| + DLOG(WARNING) << "Could not update bookmark model from non-UI thread";
|
| + return;
|
| + }
|
| + host_->frontend_->ApplyModelChanges(trans, changes, change_count);
|
| +}
|
| +
|
| +void SyncBackendHost::Core::OnSyncCycleCompleted() {
|
| + host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
|
| + &Core::NotifyFrontend, SYNC_CYCLE_COMPLETED));
|
| +}
|
| +
|
| +void SyncBackendHost::Core::OnInitializationComplete() {
|
| + if (!host_ || !host_->frontend_)
|
| + return; // We may have been told to Shutdown before initialization
|
| + // completed.
|
| +
|
| + // We could be on some random sync backend thread, so MessageLoop::current()
|
| + // can definitely be null in here.
|
| + host_->frontend_loop_->PostTask(FROM_HERE,
|
| + NewRunnableMethod(this, &Core::NotifyFrontend, INITIALIZED));
|
| +
|
| + // Initialization is complete, so we can schedule recurring SaveChanges.
|
| + host_->core_thread_.message_loop()->PostTask(FROM_HERE,
|
| + NewRunnableMethod(this, &Core::StartSavingChanges));
|
| +}
|
| +
|
| +void SyncBackendHost::Core::OnAuthProblem(
|
| + sync_api::SyncManager::AuthProblem auth_problem) {
|
| + // We could be on SyncEngine_AuthWatcherThread. Post to our core loop so
|
| + // we can modify state.
|
| + host_->frontend_loop_->PostTask(FROM_HERE,
|
| + NewRunnableMethod(this, &Core::HandleAuthErrorEventOnFrontendLoop,
|
| + AuthProblemToAuthError(auth_problem)));
|
| +}
|
| +
|
| +void SyncBackendHost::Core::HandleAuthErrorEventOnFrontendLoop(
|
| + AuthErrorState new_auth_error) {
|
| + if (!host_ || !host_->frontend_)
|
| + return;
|
| +
|
| + DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
|
| +
|
| + host_->last_auth_error_ = new_auth_error;
|
| + host_->frontend_->OnAuthError();
|
| +}
|
| +
|
| +void SyncBackendHost::Core::StartSavingChanges() {
|
| + save_changes_timer_.Start(
|
| + base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds),
|
| + this, &Core::SaveChanges);
|
| +}
|
| +
|
| +void SyncBackendHost::Core::SaveChanges() {
|
| + syncapi_->SaveChanges();
|
| +}
|
| +
|
| +} // namespace browser_sync
|
| +
|
| +#endif
|
|
|
| Property changes on: chrome\browser\sync\glue\sync_backend_host.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|