summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorzea@chromium.org <zea@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-18 23:28:43 +0000
committerzea@chromium.org <zea@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-18 23:28:43 +0000
commit4e70191dc2dd52cf2f85617e916592d638203c92 (patch)
tree2a87dfe339cf153c43f072902baac9432de55585 /chrome/browser
parent1be4c6fa13ecc5e68a4f576728e518ba2255bb9a (diff)
downloadchromium_src-4e70191dc2dd52cf2f85617e916592d638203c92.zip
chromium_src-4e70191dc2dd52cf2f85617e916592d638203c92.tar.gz
chromium_src-4e70191dc2dd52cf2f85617e916592d638203c92.tar.bz2
Reland r81454 (sync non-frontend datatype controllers) with longer timeouts.
Original codereview: http://codereview.chromium.org/6811003 BUG=77964 TEST=unit Review URL: http://codereview.chromium.org/6869016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@82028 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/profiles/profile_impl.cc1
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller.cc316
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller.h100
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc5
-rw-r--r--chrome/browser/sync/glue/autofill_profile_data_type_controller.cc55
-rw-r--r--chrome/browser/sync/glue/autofill_profile_data_type_controller.h16
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller.cc2
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller.h2
-rw-r--r--chrome/browser/sync/glue/frontend_data_type_controller.cc58
-rw-r--r--chrome/browser/sync/glue/frontend_data_type_controller.h29
-rw-r--r--chrome/browser/sync/glue/frontend_data_type_controller_mock.h8
-rw-r--r--chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc20
-rw-r--r--chrome/browser/sync/glue/non_frontend_data_type_controller.cc279
-rw-r--r--chrome/browser/sync/glue/non_frontend_data_type_controller.h165
-rw-r--r--chrome/browser/sync/glue/non_frontend_data_type_controller_mock.cc13
-rw-r--r--chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h56
-rw-r--r--chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc397
-rw-r--r--chrome/browser/sync/glue/password_data_type_controller.cc217
-rw-r--r--chrome/browser/sync/glue/password_data_type_controller.h73
-rw-r--r--chrome/browser/sync/glue/typed_url_data_type_controller.cc263
-rw-r--r--chrome/browser/sync/glue/typed_url_data_type_controller.h83
-rw-r--r--chrome/browser/sync/profile_sync_factory.h11
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.cc14
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.h4
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl_unittest.cc2
-rw-r--r--chrome/browser/sync/profile_sync_factory_mock.h1
-rw-r--r--chrome/browser/sync/profile_sync_service_autofill_unittest.cc9
-rw-r--r--chrome/browser/sync/profile_sync_service_password_unittest.cc5
-rw-r--r--chrome/browser/sync/profile_sync_service_typed_url_unittest.cc5
29 files changed, 1311 insertions, 898 deletions
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 8ed41f2..b34fff7 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -1327,6 +1327,7 @@ void ProfileImpl::InitSyncService(const std::string& cros_user) {
new ProfileSyncFactoryImpl(this, CommandLine::ForCurrentProcess()));
sync_service_.reset(
profile_sync_factory_->CreateProfileSyncService(cros_user));
+ profile_sync_factory_->RegisterDataTypes(sync_service_.get());
sync_service_->Initialize();
}
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.cc b/chrome/browser/sync/glue/autofill_data_type_controller.cc
index fa5dde4..a4f0e66 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller.cc
+++ b/chrome/browser/sync/glue/autofill_data_type_controller.cc
@@ -4,165 +4,118 @@
#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
-#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/task.h"
-#include "base/time.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync/glue/autofill_change_processor.h"
-#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_service.h"
+#include "content/common/notification_source.h"
+#include "content/common/notification_type.h"
namespace browser_sync {
AutofillDataTypeController::AutofillDataTypeController(
ProfileSyncFactory* profile_sync_factory,
- Profile* profile,
- ProfileSyncService* sync_service)
- : profile_sync_factory_(profile_sync_factory),
- profile_(profile),
- sync_service_(sync_service),
- state_(NOT_RUNNING),
- personal_data_(NULL),
- abort_association_(false),
- abort_association_complete_(false, false),
- datatype_stopped_(false, false) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(profile_sync_factory);
- DCHECK(profile);
- DCHECK(sync_service);
+ Profile* profile)
+ : NonFrontendDataTypeController(profile_sync_factory,
+ profile),
+ personal_data_(NULL) {
}
AutofillDataTypeController::~AutofillDataTypeController() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // TODO(zea): remove once crbug.com/61804 is resolved.
- CHECK_EQ(state_, NOT_RUNNING) << "AutofillDataTypeController destroyed "
- << "without being stopped.";
- CHECK(!change_processor_.get()) << "AutofillDataTypeController destroyed "
- << "while holding a change processor.";
}
-void AutofillDataTypeController::Start(StartCallback* start_callback) {
- VLOG(1) << "Starting autofill data controller.";
+bool AutofillDataTypeController::StartModels() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(start_callback);
- if (state() != NOT_RUNNING) {
- start_callback->Run(BUSY, FROM_HERE);
- delete start_callback;
- return;
- }
-
- start_callback_.reset(start_callback);
- abort_association_ = false;
-
+ DCHECK_EQ(state(), MODEL_STARTING);
// Waiting for the personal data is subtle: we do this as the PDM resets
// its cache of unique IDs once it gets loaded. If we were to proceed with
// association, the local ids in the mappings would wind up colliding.
- personal_data_ = profile_->GetPersonalDataManager();
+ personal_data_ = profile()->GetPersonalDataManager();
if (!personal_data_->IsDataLoaded()) {
- set_state(MODEL_STARTING);
personal_data_->SetObserver(this);
- return;
+ return false;
}
- ContinueStartAfterPersonalDataLoaded();
-}
-
-void AutofillDataTypeController::ContinueStartAfterPersonalDataLoaded() {
- web_data_service_ = profile_->GetWebDataService(Profile::IMPLICIT_ACCESS);
+ web_data_service_ = profile()->GetWebDataService(Profile::IMPLICIT_ACCESS);
if (web_data_service_.get() && web_data_service_->IsDatabaseLoaded()) {
- set_state(ASSOCIATING);
- BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
- NewRunnableMethod(
- this,
- &AutofillDataTypeController::StartImpl));
+ return true;
} else {
- set_state(MODEL_STARTING);
notification_registrar_.Add(this, NotificationType::WEB_DATABASE_LOADED,
NotificationService::AllSources());
+ return false;
}
}
void AutofillDataTypeController::OnPersonalDataLoaded() {
- DCHECK_EQ(state_, MODEL_STARTING);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), MODEL_STARTING);
personal_data_->RemoveObserver(this);
- ContinueStartAfterPersonalDataLoaded();
+ web_data_service_ = profile()->GetWebDataService(Profile::IMPLICIT_ACCESS);
+ if (web_data_service_.get() && web_data_service_->IsDatabaseLoaded()) {
+ set_state(ASSOCIATING);
+ if (!StartAssociationAsync()) {
+ StartDoneImpl(ASSOCIATION_FAILED, NOT_RUNNING, FROM_HERE);
+ }
+ } else {
+ notification_registrar_.Add(this, NotificationType::WEB_DATABASE_LOADED,
+ NotificationService::AllSources());
+ }
}
void AutofillDataTypeController::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- VLOG(1) << "Web database loaded observed.";
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), MODEL_STARTING);
notification_registrar_.RemoveAll();
set_state(ASSOCIATING);
- BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
- NewRunnableMethod(
- this,
- &AutofillDataTypeController::StartImpl));
+ if (!StartAssociationAsync()) {
+ StartDoneImpl(ASSOCIATION_FAILED, NOT_RUNNING, FROM_HERE);
+ }
}
-// TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of
-// distinguishing chrome shutdown from sync shutdown, we should be able to avoid
-// this (http://crbug.com/55662). Further, all this functionality should be
-// abstracted to a higher layer, where we could ensure all datatypes are doing
-// the same thing (http://crbug.com/76232).
-void AutofillDataTypeController::Stop() {
- VLOG(1) << "Stopping autofill data type controller.";
+bool AutofillDataTypeController::StartAssociationAsync() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), ASSOCIATING);
+ return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &AutofillDataTypeController::StartAssociation));
+}
- // If Stop() is called while Start() is waiting for association to
- // complete, we need to abort the association and wait for the DB
- // thread to finish the StartImpl() task.
- if (state_ == ASSOCIATING) {
- {
- base::AutoLock lock(abort_association_lock_);
- abort_association_ = true;
- if (model_associator_.get())
- model_associator_->AbortAssociation();
- }
- // Wait for the model association to abort.
- abort_association_complete_.Wait();
- StartDoneImpl(ABORTED, STOPPING, FROM_HERE);
- }
-
- // If Stop() is called while Start() is waiting for the personal
- // data manager or web data service to load, abort the start.
- if (state_ == MODEL_STARTING)
- StartDoneImpl(ABORTED, STOPPING, FROM_HERE);
-
- DCHECK(!start_callback_.get());
-
- // Deactivate the change processor on the UI thread. We dont want to listen
- // for any more changes or process them from server.
+void AutofillDataTypeController::CreateSyncComponents() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ DCHECK_EQ(state(), ASSOCIATING);
+ ProfileSyncFactory::SyncComponents sync_components =
+ profile_sync_factory()->
+ CreateAutofillSyncComponents(
+ profile_sync_service(),
+ web_data_service_->GetDatabase(),
+ personal_data_,
+ this);
+ set_model_associator(sync_components.model_associator);
+ set_change_processor(sync_components.change_processor);
+}
+
+void AutofillDataTypeController::StopModels() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(state() == STOPPING || state() == NOT_RUNNING);
notification_registrar_.RemoveAll();
personal_data_->RemoveObserver(this);
- if (change_processor_ != NULL && change_processor_->IsRunning())
- sync_service_->DeactivateDataType(this, change_processor_.get());
-
- set_state(NOT_RUNNING);
- if (BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
- NewRunnableMethod(
- this,
- &AutofillDataTypeController::StopImpl))) {
- // We need to ensure the data type has fully stoppped before continuing. In
- // particular, during shutdown we may attempt to destroy the
- // profile_sync_service before we've removed its observers (BUG 61804).
- datatype_stopped_.Wait();
- } else if (change_processor_.get()) {
- // TODO(zea): remove once crbug.com/61804 is resolved.
- LOG(FATAL) << "AutofillDataTypeController::Stop() called after DB thread"
- << " killed.";
- }
- CHECK(!change_processor_.get()) << "AutofillChangeProcessor not released.";
}
-bool AutofillDataTypeController::enabled() {
- return true;
+bool AutofillDataTypeController::StopAssociationAsync() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), STOPPING);
+ return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &AutofillDataTypeController::StopAssociation));
}
syncable::ModelType AutofillDataTypeController::type() const {
@@ -174,150 +127,31 @@ browser_sync::ModelSafeGroup AutofillDataTypeController::model_safe_group()
return browser_sync::GROUP_DB;
}
-std::string AutofillDataTypeController::name() const {
- // For logging only.
- return "autofill";
-}
-
-DataTypeController::State AutofillDataTypeController::state() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return state_;
-}
-
-ProfileSyncFactory::SyncComponents
- AutofillDataTypeController::CreateSyncComponents(
- ProfileSyncService* profile_sync_service,
- WebDatabase* web_database,
- PersonalDataManager* personal_data,
- browser_sync::UnrecoverableErrorHandler* error_handler) {
- return profile_sync_factory_->CreateAutofillSyncComponents(
- profile_sync_service,
- web_database,
- personal_data,
- this);
-}
-
-void AutofillDataTypeController::StartImpl() {
- VLOG(1) << "Autofill data type controller StartImpl called.";
+void AutofillDataTypeController::RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
- // No additional services need to be started before we can proceed
- // with model association.
- {
- base::AutoLock lock(abort_association_lock_);
- if (abort_association_) {
- abort_association_complete_.Signal();
- return;
- }
- ProfileSyncFactory::SyncComponents sync_components =
- CreateSyncComponents(
- sync_service_,
- web_data_service_->GetDatabase(),
- profile_->GetPersonalDataManager(),
- this);
- model_associator_.reset(sync_components.model_associator);
- change_processor_.reset(sync_components.change_processor);
- }
-
- if (!model_associator_->CryptoReadyIfNecessary()) {
- StartFailed(NEEDS_CRYPTO);
- return;
- }
-
- bool sync_has_nodes = false;
- if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
- StartFailed(UNRECOVERABLE_ERROR);
- return;
- }
-
- base::TimeTicks start_time = base::TimeTicks::Now();
- bool merge_success = model_associator_->AssociateModels();
- UMA_HISTOGRAM_TIMES("Sync.AutofillAssociationTime",
- base::TimeTicks::Now() - start_time);
- VLOG(1) << "Autofill association time: " <<
- (base::TimeTicks::Now() - start_time).InSeconds();
- if (!merge_success) {
- StartFailed(ASSOCIATION_FAILED);
- return;
- }
-
- sync_service_->ActivateDataType(this, change_processor_.get());
- StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING);
+ UMA_HISTOGRAM_COUNTS("Sync.AutofillRunFailures", 1);
}
-void AutofillDataTypeController::StartDone(
- DataTypeController::StartResult result,
- DataTypeController::State new_state) {
- VLOG(1) << "Autofill data type controller StartDone called.";
+void AutofillDataTypeController::RecordAssociationTime(base::TimeDelta time) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
-
- abort_association_complete_.Signal();
- base::AutoLock lock(abort_association_lock_);
- if (!abort_association_) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this,
- &AutofillDataTypeController::StartDoneImpl,
- result,
- new_state,
- FROM_HERE));
- }
+ UMA_HISTOGRAM_TIMES("Sync.AutofillAssociationTime", time);
}
-void AutofillDataTypeController::StartDoneImpl(
- DataTypeController::StartResult result,
- DataTypeController::State new_state,
- const tracked_objects::Location& location) {
- VLOG(1) << "Autofill data type controller StartDoneImpl called.";
+void AutofillDataTypeController::RecordStartFailure(StartResult result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- set_state(new_state);
- start_callback_->Run(result, location);
- start_callback_.reset();
-
- if (result == UNRECOVERABLE_ERROR || result == ASSOCIATION_FAILED) {
- UMA_HISTOGRAM_ENUMERATION("Sync.AutofillStartFailures",
- result,
- MAX_START_RESULT);
- }
+ UMA_HISTOGRAM_ENUMERATION("Sync.AutofillStartFailures",
+ result,
+ MAX_START_RESULT);
}
-void AutofillDataTypeController::StopImpl() {
- VLOG(1) << "Autofill data type controller StopImpl called.";
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
-
- if (model_associator_ != NULL)
- model_associator_->DisassociateModels();
-
- change_processor_.reset();
- model_associator_.reset();
-
- datatype_stopped_.Signal();
+PersonalDataManager* AutofillDataTypeController::personal_data() const {
+ return personal_data_;
}
-void AutofillDataTypeController::StartFailed(StartResult result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
- change_processor_.reset();
- model_associator_.reset();
- StartDone(result, NOT_RUNNING);
-}
-
-void AutofillDataTypeController::OnUnrecoverableError(
- const tracked_objects::Location& from_here,
- const std::string& message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this,
- &AutofillDataTypeController::OnUnrecoverableErrorImpl,
- from_here, message));
- UMA_HISTOGRAM_COUNTS("Sync.AutofillRunFailures", 1);
-}
-
-void AutofillDataTypeController::OnUnrecoverableErrorImpl(
- const tracked_objects::Location& from_here,
- const std::string& message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- sync_service_->OnUnrecoverableError(from_here, message);
+WebDataService* AutofillDataTypeController::web_data_service() const {
+ return web_data_service_;
}
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.h b/chrome/browser/sync/glue/autofill_data_type_controller.h
index 8df5fb8..ee58113 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller.h
+++ b/chrome/browser/sync/glue/autofill_data_type_controller.h
@@ -8,53 +8,31 @@
#include <string>
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/waitable_event.h"
+#include "base/memory/ref_counted.h"
#include "chrome/browser/autofill/personal_data_manager.h"
-#include "chrome/browser/sync/profile_sync_factory.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/glue/data_type_controller.h"
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
-class Profile;
-class ProfileSyncFactory;
-class ProfileSyncService;
+class NotificationDetails;
+class NotificationType;
+class NotificationSource;
namespace browser_sync {
-class AssociatorInterface;
-class ChangeProcessor;
-
// A class that manages the startup and shutdown of autofill sync.
-class AutofillDataTypeController : public DataTypeController,
+class AutofillDataTypeController : public NonFrontendDataTypeController,
public NotificationObserver,
public PersonalDataManager::Observer {
public:
- AutofillDataTypeController(
- ProfileSyncFactory* profile_sync_factory,
- Profile* profile,
- ProfileSyncService* sync_service);
+ AutofillDataTypeController(ProfileSyncFactory* profile_sync_factory,
+ Profile* profile);
virtual ~AutofillDataTypeController();
- // DataTypeController implementation
- virtual void Start(StartCallback* start_callback);
-
- virtual void Stop();
-
- virtual bool enabled();
-
+ // NonFrontendDataTypeController implementation
virtual syncable::ModelType type() const;
-
virtual browser_sync::ModelSafeGroup model_safe_group() const;
- virtual std::string name() const;
-
- virtual State state() const;
-
- // UnrecoverableHandler implementation
- virtual void OnUnrecoverableError(const tracked_objects::Location& from_here,
- const std::string& message);
-
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
const NotificationSource& source,
@@ -64,52 +42,26 @@ class AutofillDataTypeController : public DataTypeController,
virtual void OnPersonalDataLoaded();
protected:
- virtual ProfileSyncFactory::SyncComponents CreateSyncComponents(
- ProfileSyncService* profile_sync_service,
- WebDatabase* web_database,
- PersonalDataManager* personal_data,
- browser_sync::UnrecoverableErrorHandler* error_handler);
- ProfileSyncFactory* profile_sync_factory_;
-
+ // NonFrontendDataTypeController interface.
+ virtual bool StartModels();
+ virtual bool StartAssociationAsync();
+ virtual void CreateSyncComponents();
+ virtual void StopModels();
+ virtual bool StopAssociationAsync();
+ virtual void RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message);
+ virtual void RecordAssociationTime(base::TimeDelta time);
+ virtual void RecordStartFailure(StartResult result);
+
+ // Getters and setters
+ PersonalDataManager* personal_data() const;
+ WebDataService* web_data_service() const;
private:
- void StartImpl();
- void StartDone(StartResult result, State state);
- void StartDoneImpl(StartResult result, State state,
- const tracked_objects::Location& location);
- void StopImpl();
- void StartFailed(StartResult result);
- void OnUnrecoverableErrorImpl(const tracked_objects::Location& from_here,
- const std::string& message);
-
- // Second-half of "Start" implementation, called once personal data has
- // loaded.
- void ContinueStartAfterPersonalDataLoaded();
-
- void set_state(State state) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- state_ = state;
- }
-
- Profile* profile_;
- ProfileSyncService* sync_service_;
- State state_;
-
PersonalDataManager* personal_data_;
scoped_refptr<WebDataService> web_data_service_;
- scoped_ptr<AssociatorInterface> model_associator_;
- scoped_ptr<ChangeProcessor> change_processor_;
- scoped_ptr<StartCallback> start_callback_;
-
NotificationRegistrar notification_registrar_;
- base::Lock abort_association_lock_;
- bool abort_association_;
- base::WaitableEvent abort_association_complete_;
-
- // Barrier to ensure that the datatype has been stopped on the DB thread
- // from the UI thread.
- base::WaitableEvent datatype_stopped_;
-
DISALLOW_COPY_AND_ASSIGN(AutofillDataTypeController);
};
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
index 01deb74..a4e854e 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
@@ -87,13 +87,14 @@ class AutofillDataTypeControllerTest : public testing::Test {
db_thread_(BrowserThread::DB) {}
virtual void SetUp() {
+ EXPECT_CALL(profile_, GetProfileSyncService()).WillRepeatedly(
+ Return(&service_));
db_thread_.Start();
web_data_service_ = new WebDataServiceFake(true);
personal_data_manager_ = new PersonalDataManagerMock();
autofill_dtc_ =
new AutofillDataTypeController(&profile_sync_factory_,
- &profile_,
- &service_);
+ &profile_);
}
virtual void TearDown() {
diff --git a/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc b/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc
index 2203197..7ea3959 100644
--- a/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc
+++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc
@@ -4,18 +4,17 @@
#include "chrome/browser/sync/glue/autofill_profile_data_type_controller.h"
-#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
+#include "base/metrics/histogram.h"
#include "chrome/browser/sync/profile_sync_factory.h"
namespace browser_sync {
AutofillProfileDataTypeController::AutofillProfileDataTypeController(
ProfileSyncFactory* profile_sync_factory,
- Profile* profile,
- ProfileSyncService* sync_service) : AutofillDataTypeController(
- profile_sync_factory,
- profile,
- sync_service) {}
+ Profile* profile)
+ : AutofillDataTypeController(
+ profile_sync_factory,
+ profile) {}
AutofillProfileDataTypeController::~AutofillProfileDataTypeController() {}
@@ -23,22 +22,38 @@ syncable::ModelType AutofillProfileDataTypeController::type() const {
return syncable::AUTOFILL_PROFILE;
}
-std::string AutofillProfileDataTypeController::name() const {
- // For logging only.
- return "autofill_profile";
+void AutofillProfileDataTypeController::CreateSyncComponents() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ ProfileSyncFactory::SyncComponents sync_components =
+ profile_sync_factory()->
+ CreateAutofillProfileSyncComponents(
+ profile_sync_service(),
+ web_data_service()->GetDatabase(),
+ personal_data(),
+ this);
+ set_model_associator(sync_components.model_associator);
+ set_change_processor(sync_components.change_processor);
}
-ProfileSyncFactory::SyncComponents
- AutofillProfileDataTypeController::CreateSyncComponents(
- ProfileSyncService* profile_sync_service,
- WebDatabase* web_database,
- PersonalDataManager* personal_data,
- browser_sync::UnrecoverableErrorHandler* error_handler) {
- return profile_sync_factory_->CreateAutofillProfileSyncComponents(
- profile_sync_service,
- web_database,
- personal_data,
- this);
+void AutofillProfileDataTypeController::RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ UMA_HISTOGRAM_COUNTS("Sync.AutofillProfileRunFailures", 1);
}
+
+void AutofillProfileDataTypeController::RecordAssociationTime(
+ base::TimeDelta time) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ UMA_HISTOGRAM_TIMES("Sync.AutofillProfileAssociationTime", time);
+}
+
+void AutofillProfileDataTypeController::RecordStartFailure(StartResult result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ UMA_HISTOGRAM_ENUMERATION("Sync.AutofillProfileStartFailures",
+ result,
+ MAX_START_RESULT);
+}
+
} // namepsace browser_sync
diff --git a/chrome/browser/sync/glue/autofill_profile_data_type_controller.h b/chrome/browser/sync/glue/autofill_profile_data_type_controller.h
index d97a904..64f0f49 100644
--- a/chrome/browser/sync/glue/autofill_profile_data_type_controller.h
+++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.h
@@ -15,20 +15,18 @@ class AutofillProfileDataTypeController : public AutofillDataTypeController {
public:
AutofillProfileDataTypeController(
ProfileSyncFactory* profile_sync_factory,
- Profile* profile,
- ProfileSyncService* sync_service);
+ Profile* profile);
virtual ~AutofillProfileDataTypeController();
virtual syncable::ModelType type() const;
- virtual std::string name() const;
-
protected:
- virtual ProfileSyncFactory::SyncComponents CreateSyncComponents(
- ProfileSyncService* profile_sync_service,
- WebDatabase* web_database,
- PersonalDataManager* personal_data,
- browser_sync::UnrecoverableErrorHandler* error_handler);
+ virtual void CreateSyncComponents();
+ virtual void RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message);
+ virtual void RecordAssociationTime(base::TimeDelta time);
+ virtual void RecordStartFailure(StartResult result);
};
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.cc b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
index 8cd3d5b..4415240 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller.cc
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
@@ -43,7 +43,7 @@ bool BookmarkDataTypeController::StartModels() {
}
// Cleanup for our extra registrar usage.
-void BookmarkDataTypeController::CleanupState() {
+void BookmarkDataTypeController::CleanUpState() {
registrar_.RemoveAll();
}
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.h b/chrome/browser/sync/glue/bookmark_data_type_controller.h
index 8741e84..2655056 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller.h
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.h
@@ -39,7 +39,7 @@ class BookmarkDataTypeController : public FrontendDataTypeController,
private:
// FrontendDataTypeController interface.
virtual bool StartModels();
- virtual void CleanupState();
+ virtual void CleanUpState();
virtual void CreateSyncComponents();
virtual void RecordUnrecoverableError(
const tracked_objects::Location& from_here,
diff --git a/chrome/browser/sync/glue/frontend_data_type_controller.cc b/chrome/browser/sync/glue/frontend_data_type_controller.cc
index 5e324f9..edec12c 100644
--- a/chrome/browser/sync/glue/frontend_data_type_controller.cc
+++ b/chrome/browser/sync/glue/frontend_data_type_controller.cc
@@ -103,15 +103,46 @@ bool FrontendDataTypeController::Associate() {
return true;
}
+void FrontendDataTypeController::StartFailed(StartResult result,
+ const tracked_objects::Location& location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ CleanUpState();
+ model_associator_.reset();
+ change_processor_.reset();
+ state_ = NOT_RUNNING;
+ RecordStartFailure(result);
+
+ // We have to release the callback before we call it, since it's possible
+ // invoking the callback will trigger a call to STOP(), which will get
+ // confused by the non-NULL start_callback_.
+ scoped_ptr<StartCallback> callback(start_callback_.release());
+ callback->Run(result, location);
+}
+
+void FrontendDataTypeController::FinishStart(StartResult result,
+ const tracked_objects::Location& location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // We have to release the callback before we call it, since it's possible
+ // invoking the callback will trigger a call to STOP(), which will get
+ // confused by the non-NULL start_callback_.
+ scoped_ptr<StartCallback> callback(start_callback_.release());
+ callback->Run(result, location);
+}
+
void FrontendDataTypeController::Stop() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// If Stop() is called while Start() is waiting for the datatype model to
// load, abort the start.
- if (state_ == MODEL_STARTING)
- FinishStart(ABORTED, FROM_HERE);
+ if (state_ == MODEL_STARTING) {
+ StartFailed(ABORTED, FROM_HERE);
+ // We can just return here since we haven't performed association if we're
+ // still in MODEL_STARTING.
+ return;
+ }
DCHECK(!start_callback_.get());
- CleanupState();
+ CleanUpState();
if (change_processor_ != NULL)
sync_service_->DeactivateDataType(this, change_processor_.get());
@@ -125,7 +156,7 @@ void FrontendDataTypeController::Stop() {
state_ = NOT_RUNNING;
}
-void FrontendDataTypeController::CleanupState() {
+void FrontendDataTypeController::CleanUpState() {
// Do nothing by default.
}
@@ -150,23 +181,4 @@ void FrontendDataTypeController::OnUnrecoverableError(
sync_service_->OnUnrecoverableError(from_here, message);
}
-void FrontendDataTypeController::FinishStart(StartResult result,
- const tracked_objects::Location& location) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- start_callback_->Run(result, location);
- start_callback_.reset();
-}
-
-void FrontendDataTypeController::StartFailed(StartResult result,
- const tracked_objects::Location& location) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- CleanupState();
- model_associator_.reset();
- change_processor_.reset();
- state_ = NOT_RUNNING;
- start_callback_->Run(result, location);
- start_callback_.reset();
- RecordStartFailure(result);
-}
-
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/frontend_data_type_controller.h b/chrome/browser/sync/glue/frontend_data_type_controller.h
index d228bb9..6a2d863 100644
--- a/chrome/browser/sync/glue/frontend_data_type_controller.h
+++ b/chrome/browser/sync/glue/frontend_data_type_controller.h
@@ -22,6 +22,8 @@ namespace browser_sync {
class AssociatorInterface;
class ChangeProcessor;
+// TODO(zea): have naming and style match NonFrontendDataTypeController.
+// TODO(zea): Rename frontend to UI (http://crbug.com/78833).
// Implementation for datatypes that reside on the frontend thread
// (UI thread). This is the same thread we perform initialization on, so we
// don't have to worry about thread safety. The main start/stop funtionality is
@@ -44,15 +46,10 @@ class FrontendDataTypeController : public DataTypeController {
// DataTypeController interface.
virtual void Start(StartCallback* start_callback);
-
virtual void Stop();
-
virtual syncable::ModelType type() const = 0;
-
virtual browser_sync::ModelSafeGroup model_safe_group() const;
-
virtual std::string name() const;
-
virtual State state() const;
// UnrecoverableErrorHandler interface.
@@ -64,25 +61,33 @@ class FrontendDataTypeController : public DataTypeController {
// Kick off any dependent services that need to be running before we can
// associate models. The default implementation is a no-op.
+ // Return value:
+ // True - if models are ready and association can proceed.
+ // False - if models are not ready. Associate() should be called when the
+ // models are ready. Refer to Start(_) implementation.
virtual bool StartModels();
// Build sync components and associate models.
+ // Return value:
+ // True - if association was successful. FinishStart should have been
+ // invoked.
+ // False - if association failed. StartFailed should have been invoked.
virtual bool Associate();
+ // Datatype specific creation of sync components.
+ virtual void CreateSyncComponents() = 0;
+
// Perform any DataType controller specific state cleanup before stopping
// the datatype controller. The default implementation is a no-op.
- virtual void CleanupState();
-
- // Helper method to run the stashed start callback with a given result.
- virtual void FinishStart(StartResult result,
- const tracked_objects::Location& from_here);
+ virtual void CleanUpState();
// Cleans up state and calls callback when start fails.
virtual void StartFailed(StartResult result,
const tracked_objects::Location& from_here);
- // Datatype specific creation of sync components.
- virtual void CreateSyncComponents() = 0;
+ // Helper method to run the stashed start callback with a given result.
+ virtual void FinishStart(StartResult result,
+ const tracked_objects::Location& from_here);
// DataType specific histogram methods. Because histograms use static's, the
// specific datatype controllers must implement this themselves.
diff --git a/chrome/browser/sync/glue/frontend_data_type_controller_mock.h b/chrome/browser/sync/glue/frontend_data_type_controller_mock.h
index 0485b1f..a32f3f5 100644
--- a/chrome/browser/sync/glue/frontend_data_type_controller_mock.h
+++ b/chrome/browser/sync/glue/frontend_data_type_controller_mock.h
@@ -30,12 +30,12 @@ class FrontendDataTypeControllerMock : public FrontendDataTypeController {
// FrontendDataTypeController mocks.
MOCK_METHOD0(StartModels, bool());
MOCK_METHOD0(Associate, bool());
- MOCK_METHOD0(CleanupState, void());
- MOCK_METHOD2(FinishStart, void(StartResult result,
- const tracked_objects::Location& from_here));
+ MOCK_METHOD0(CreateSyncComponents, void());
MOCK_METHOD2(StartFailed, void(StartResult result,
const tracked_objects::Location& from_here));
- MOCK_METHOD0(CreateSyncComponents, void());
+ MOCK_METHOD2(FinishStart, void(StartResult result,
+ const tracked_objects::Location& from_here));
+ MOCK_METHOD0(CleanUpState, void());
MOCK_METHOD2(RecordUnrecoverableError, void(const tracked_objects::Location&,
const std::string&));
MOCK_METHOD1(RecordAssociationTime, void(base::TimeDelta time));
diff --git a/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc b/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc
index c0c2290..ee3f42f 100644
--- a/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc
@@ -63,8 +63,8 @@ class FrontendDataTypeControllerFake : public FrontendDataTypeController {
virtual bool StartModels() {
return mock_->StartModels();
}
- virtual void CleanupState() {
- mock_->CleanupState();
+ virtual void CleanUpState() {
+ mock_->CleanUpState();
}
virtual void RecordUnrecoverableError(
const tracked_objects::Location& from_here,
@@ -122,13 +122,13 @@ class FrontendDataTypeControllerTest : public testing::Test {
}
void SetStopExpectations() {
- EXPECT_CALL(*dtc_mock_, CleanupState());
+ EXPECT_CALL(*dtc_mock_, CleanUpState());
EXPECT_CALL(service_, DeactivateDataType(_, _));
EXPECT_CALL(*model_associator_, DisassociateModels());
}
void SetStartFailExpectations(DataTypeController::StartResult result) {
- EXPECT_CALL(*dtc_mock_, CleanupState());
+ EXPECT_CALL(*dtc_mock_, CleanUpState());
EXPECT_CALL(*dtc_mock_, RecordStartFailure(result));
EXPECT_CALL(start_callback_, Run(result,_));
}
@@ -169,6 +169,16 @@ TEST_F(FrontendDataTypeControllerTest, StartFirstRun) {
EXPECT_EQ(DataTypeController::RUNNING, frontend_dtc_->state());
}
+TEST_F(FrontendDataTypeControllerTest, AbortDuringStartModels) {
+ EXPECT_CALL(*dtc_mock_, StartModels()).WillOnce(Return(false));
+ SetStartFailExpectations(DataTypeController::ABORTED);
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state());
+ frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ EXPECT_EQ(DataTypeController::MODEL_STARTING, frontend_dtc_->state());
+ frontend_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state());
+}
+
TEST_F(FrontendDataTypeControllerTest, StartAssociationFailed) {
SetStartExpectations();
EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
@@ -215,7 +225,6 @@ TEST_F(FrontendDataTypeControllerTest, Stop) {
SetAssociateExpectations();
SetActivateExpectations(DataTypeController::OK);
SetStopExpectations();
-
EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state());
frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
EXPECT_EQ(DataTypeController::RUNNING, frontend_dtc_->state());
@@ -232,7 +241,6 @@ TEST_F(FrontendDataTypeControllerTest, OnUnrecoverableError) {
WillOnce(InvokeWithoutArgs(frontend_dtc_.get(),
&FrontendDataTypeController::Stop));
SetStopExpectations();
-
EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state());
frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
EXPECT_EQ(DataTypeController::RUNNING, frontend_dtc_->state());
diff --git a/chrome/browser/sync/glue/non_frontend_data_type_controller.cc b/chrome/browser/sync/glue/non_frontend_data_type_controller.cc
new file mode 100644
index 0000000..d26baef
--- /dev/null
+++ b/chrome/browser/sync/glue/non_frontend_data_type_controller.cc
@@ -0,0 +1,279 @@
+// Copyright (c) 2011 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.
+
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
+
+#include "base/logging.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/glue/model_associator.h"
+#include "chrome/browser/sync/profile_sync_factory.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/syncable/model_type.h"
+#include "content/browser/browser_thread.h"
+
+namespace browser_sync {
+
+NonFrontendDataTypeController::NonFrontendDataTypeController()
+ : profile_sync_factory_(NULL),
+ profile_(NULL),
+ profile_sync_service_(NULL),
+ abort_association_(false),
+ abort_association_complete_(false, false),
+ datatype_stopped_(false, false) {}
+
+NonFrontendDataTypeController::NonFrontendDataTypeController(
+ ProfileSyncFactory* profile_sync_factory,
+ Profile* profile)
+ : profile_sync_factory_(profile_sync_factory),
+ profile_(profile),
+ profile_sync_service_(profile->GetProfileSyncService()),
+ state_(NOT_RUNNING),
+ abort_association_(false),
+ abort_association_complete_(false, false),
+ datatype_stopped_(false, false) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(profile_sync_factory_);
+ DCHECK(profile_);
+ DCHECK(profile_sync_service_);
+}
+
+NonFrontendDataTypeController::~NonFrontendDataTypeController() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void NonFrontendDataTypeController::Start(StartCallback* start_callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(start_callback);
+ if (state_ != NOT_RUNNING) {
+ start_callback->Run(BUSY, FROM_HERE);
+ delete start_callback;
+ return;
+ }
+
+ start_callback_.reset(start_callback);
+ abort_association_ = false;
+
+ state_ = MODEL_STARTING;
+ if (!StartModels()) {
+ // If we are waiting for some external service to load before associating
+ // or we failed to start the models, we exit early. state_ will control
+ // what we perform next.
+ DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING);
+ return;
+ }
+
+ // Kick off association on the thread the datatype resides on.
+ state_ = ASSOCIATING;
+ if (!StartAssociationAsync()) {
+ StartDoneImpl(ASSOCIATION_FAILED, NOT_RUNNING, FROM_HERE);
+ }
+}
+
+bool NonFrontendDataTypeController::StartModels() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state_, MODEL_STARTING);
+ // By default, no additional services need to be started before we can proceed
+ // with model association, so do nothing.
+ return true;
+}
+
+void NonFrontendDataTypeController::StartAssociation() {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state_, ASSOCIATING);
+ {
+ base::AutoLock lock(abort_association_lock_);
+ if (abort_association_) {
+ abort_association_complete_.Signal();
+ return;
+ }
+ CreateSyncComponents();
+ }
+
+ if (!model_associator_->CryptoReadyIfNecessary()) {
+ StartFailed(NEEDS_CRYPTO, FROM_HERE);
+ return;
+ }
+
+ bool sync_has_nodes = false;
+ if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
+ StartFailed(UNRECOVERABLE_ERROR, FROM_HERE);
+ return;
+ }
+
+ base::TimeTicks start_time = base::TimeTicks::Now();
+ bool merge_success = model_associator_->AssociateModels();
+ RecordAssociationTime(base::TimeTicks::Now() - start_time);
+ if (!merge_success) {
+ StartFailed(ASSOCIATION_FAILED, FROM_HERE);
+ return;
+ }
+
+ profile_sync_service_->ActivateDataType(this, change_processor_.get());
+ StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING, FROM_HERE);
+}
+
+void NonFrontendDataTypeController::StartFailed(StartResult result,
+ const tracked_objects::Location& location) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ model_associator_.reset();
+ change_processor_.reset();
+ StartDone(result, NOT_RUNNING, location);
+}
+
+void NonFrontendDataTypeController::StartDone(
+ DataTypeController::StartResult result,
+ DataTypeController::State new_state,
+ const tracked_objects::Location& location) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ abort_association_complete_.Signal();
+ base::AutoLock lock(abort_association_lock_);
+ if (!abort_association_) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &NonFrontendDataTypeController::StartDoneImpl,
+ result,
+ new_state,
+ location));
+ }
+}
+
+void NonFrontendDataTypeController::StartDoneImpl(
+ DataTypeController::StartResult result,
+ DataTypeController::State new_state,
+ const tracked_objects::Location& location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ state_ = new_state;
+ if (state_ != RUNNING) {
+ // Start failed.
+ StopModels();
+ RecordStartFailure(result);
+ }
+
+ // We have to release the callback before we call it, since it's possible
+ // invoking the callback will trigger a call to STOP(), which will get
+ // confused by the non-NULL start_callback_.
+ scoped_ptr<StartCallback> callback(start_callback_.release());
+ callback->Run(result, location);
+}
+
+// TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of
+// distinguishing chrome shutdown from sync shutdown, we should be able to avoid
+// this (http://crbug.com/55662).
+void NonFrontendDataTypeController::Stop() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // If Stop() is called while Start() is waiting for association to
+ // complete, we need to abort the association and wait for the DB
+ // thread to finish the StartImpl() task.
+ if (state_ == ASSOCIATING) {
+ state_ = STOPPING;
+ {
+ base::AutoLock lock(abort_association_lock_);
+ abort_association_ = true;
+ if (model_associator_.get())
+ model_associator_->AbortAssociation();
+ }
+ // Wait for the model association to abort.
+ abort_association_complete_.Wait();
+ StartDoneImpl(ABORTED, STOPPING, FROM_HERE);
+ } else if (state_ == MODEL_STARTING) {
+ state_ = STOPPING;
+ // If Stop() is called while Start() is waiting for the models to start,
+ // abort the start. We don't need to continue on since it means we haven't
+ // kicked off the association, and once we call StopModels, we never will.
+ StartDoneImpl(ABORTED, NOT_RUNNING, FROM_HERE);
+ return;
+ } else {
+ state_ = STOPPING;
+
+ StopModels();
+ }
+ DCHECK(!start_callback_.get());
+
+ // Deactivate the change processor on the UI thread. We dont want to listen
+ // for any more changes or process them from server.
+ if (change_processor_ != NULL)
+ profile_sync_service_->DeactivateDataType(this, change_processor_.get());
+
+ if (StopAssociationAsync()) {
+ datatype_stopped_.Wait();
+ } else {
+ // We do DFATAL here because this will eventually lead to a failed CHECK
+ // when the change processor gets destroyed on the wrong thread.
+ LOG(DFATAL) << "Failed to destroy datatype " << name();
+ }
+ state_ = NOT_RUNNING;
+}
+
+void NonFrontendDataTypeController::StopModels() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(state_ == STOPPING || state_ == NOT_RUNNING);
+ // Do nothing by default.
+}
+
+void NonFrontendDataTypeController::StopAssociation() {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (model_associator_ != NULL)
+ model_associator_->DisassociateModels();
+ change_processor_.reset();
+ model_associator_.reset();
+ datatype_stopped_.Signal();
+}
+
+std::string NonFrontendDataTypeController::name() const {
+ // For logging only.
+ return syncable::ModelTypeToString(type());
+}
+
+DataTypeController::State NonFrontendDataTypeController::state() const {
+ return state_;
+}
+
+void NonFrontendDataTypeController::OnUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ RecordUnrecoverableError(from_here, message);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(this,
+ &NonFrontendDataTypeController::OnUnrecoverableErrorImpl, from_here,
+ message));
+}
+
+void NonFrontendDataTypeController::OnUnrecoverableErrorImpl(
+ const tracked_objects::Location& from_here,
+ const std::string& message) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ profile_sync_service_->OnUnrecoverableError(from_here, message);
+}
+
+ProfileSyncFactory* NonFrontendDataTypeController::profile_sync_factory()
+ const {
+ return profile_sync_factory_;
+}
+
+Profile* NonFrontendDataTypeController::profile() const {
+ return profile_;
+}
+
+ProfileSyncService* NonFrontendDataTypeController::profile_sync_service()
+ const {
+ return profile_sync_service_;
+}
+
+void NonFrontendDataTypeController::set_state(State state) {
+ state_ = state;
+}
+
+void NonFrontendDataTypeController::set_model_associator(
+ AssociatorInterface* associator) {
+ model_associator_.reset(associator);
+}
+
+void NonFrontendDataTypeController::set_change_processor(
+ ChangeProcessor* change_processor) {
+ change_processor_.reset(change_processor);
+}
+
+} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/non_frontend_data_type_controller.h b/chrome/browser/sync/glue/non_frontend_data_type_controller.h
new file mode 100644
index 0000000..c2f2ee0
--- /dev/null
+++ b/chrome/browser/sync/glue/non_frontend_data_type_controller.h
@@ -0,0 +1,165 @@
+// Copyright (c) 2011 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.
+
+#ifndef CHROME_BROWSER_SYNC_GLUE_NON_FRONTEND_DATA_TYPE_CONTROLLER_H__
+#define CHROME_BROWSER_SYNC_GLUE_NON_FRONTEND_DATA_TYPE_CONTROLLER_H__
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "chrome/browser/sync/glue/data_type_controller.h"
+
+class Profile;
+class ProfileSyncService;
+class ProfileSyncFactory;
+
+namespace base { class TimeDelta; }
+namespace browser_sync {
+
+class AssociatorInterface;
+class ChangeProcessor;
+
+// TODO(zea): Rename frontend to UI (http://crbug.com/78833).
+// Implementation for datatypes that do not reside on the frontend thread
+// (UI thread). This is the same thread we perform initialization
+// on, so we don't have to worry about thread safety. The main start/stop
+// funtionality is implemented by default. Derived classes must implement:
+// type()
+// model_safe_group()
+// StartAssociationAsync()
+// CreateSyncComponents()
+// StopAssociationAsync()
+// RecordUnrecoverableError(...)
+// RecordAssociationTime(...);
+// RecordStartFailure(...);
+class NonFrontendDataTypeController : public DataTypeController {
+ public:
+ NonFrontendDataTypeController(
+ ProfileSyncFactory* profile_sync_factory,
+ Profile* profile);
+ virtual ~NonFrontendDataTypeController();
+
+ // DataTypeController interface.
+ virtual void Start(StartCallback* start_callback);
+ virtual void Stop();
+ virtual syncable::ModelType type() const = 0;
+ virtual browser_sync::ModelSafeGroup model_safe_group() const = 0;
+ virtual std::string name() const;
+ virtual State state() const;
+
+ // UnrecoverableErrorHandler interface.
+ // Note: this is performed on the datatype's thread.
+ virtual void OnUnrecoverableError(const tracked_objects::Location& from_here,
+ const std::string& message);
+ protected:
+ // For testing only.
+ NonFrontendDataTypeController();
+
+ // Start any dependent services that need to be running before we can
+ // associate models. The default implementation is a no-op.
+ // Return value:
+ // True - if models are ready and association can proceed.
+ // False - if models are not ready. KickOffAssociation should be called
+ // when the models are ready. Refer to Start(_) implementation.
+ // Note: this is performed on the frontend (UI) thread.
+ virtual bool StartModels();
+
+ // Post the association task to the thread the datatype lives on.
+ // Note: this is performed on the frontend (UI) thread.
+ // Return value: True if task posted successfully, False otherwise.
+ virtual bool StartAssociationAsync() = 0;
+
+ // Build sync components and associate models.
+ // Note: this is performed on the datatype's thread.
+ virtual void StartAssociation();
+
+ // Datatype specific creation of sync components.
+ // Note: this is performed on the datatype's thread.
+ virtual void CreateSyncComponents() = 0;
+
+ // Start failed, make sure we record it, clean up state, and invoke the
+ // callback on the frontend thread.
+ // Note: this is performed on the datatype's thread.
+ virtual void StartFailed(StartResult result,
+ const tracked_objects::Location& location);
+
+ // Start up complete, update the state and invoke the callback.
+ // Note: this is performed on the datatype's thread.
+ virtual void StartDone(DataTypeController::StartResult result,
+ DataTypeController::State new_state,
+ const tracked_objects::Location& location);
+
+ // UI thread implementation of StartDone.
+ virtual void StartDoneImpl(DataTypeController::StartResult result,
+ DataTypeController::State new_state,
+ const tracked_objects::Location& location);
+
+ // Perform any DataType controller specific state cleanup before stopping
+ // the datatype controller. The default implementation is a no-op.
+ // Note: this is performed on the frontend (UI) thread.
+ virtual void StopModels();
+
+ // Post the StopAssociation task to the thread the datatype lives on.
+ // Note: this is performed on the frontend (UI) thread.
+ // Return value: True if task posted successfully, False otherwise.
+ virtual bool StopAssociationAsync() = 0;
+
+ // Disassociate the models and destroy the sync components.
+ // Note: this is performed on the datatype's thread.
+ virtual void StopAssociation();
+
+ // Implementation of OnUnrecoverableError that lives on UI thread.
+ virtual void OnUnrecoverableErrorImpl(
+ const tracked_objects::Location& from_here,
+ const std::string& message);
+
+ // DataType specific histogram methods. Because histograms use static's, the
+ // specific datatype controllers must implement this themselves.
+ // Important: calling them on other threads can lead to memory corruption!
+ // Record unrecoverable errors. Called on Datatype's thread.
+ virtual void RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message) = 0;
+ // Record association time. Called on Datatype's thread.
+ virtual void RecordAssociationTime(base::TimeDelta time) = 0;
+ // Record causes of start failure. Called on UI thread.
+ virtual void RecordStartFailure(StartResult result) = 0;
+
+ // Accessors and mutators used by derived classes.
+ ProfileSyncFactory* profile_sync_factory() const;
+ Profile* profile() const;
+ ProfileSyncService* profile_sync_service() const;
+ void set_state(State state);
+ void set_model_associator(AssociatorInterface* associator);
+ void set_change_processor(ChangeProcessor* change_processor);
+
+ private:
+ ProfileSyncFactory* const profile_sync_factory_;
+ Profile* const profile_;
+ ProfileSyncService* const profile_sync_service_;
+
+ State state_;
+
+ scoped_ptr<StartCallback> start_callback_;
+ scoped_ptr<AssociatorInterface> model_associator_;
+ scoped_ptr<ChangeProcessor> change_processor_;
+
+ // Locks/Barriers for aborting association early.
+ base::Lock abort_association_lock_;
+ bool abort_association_;
+ base::WaitableEvent abort_association_complete_;
+
+ // Barrier to ensure that the datatype has been stopped on the DB thread
+ // from the UI thread.
+ base::WaitableEvent datatype_stopped_;
+
+ DISALLOW_COPY_AND_ASSIGN(NonFrontendDataTypeController);
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_GLUE_NON_FRONTEND_DATA_TYPE_CONTROLLER_H__
diff --git a/chrome/browser/sync/glue/non_frontend_data_type_controller_mock.cc b/chrome/browser/sync/glue/non_frontend_data_type_controller_mock.cc
new file mode 100644
index 0000000..dfde595
--- /dev/null
+++ b/chrome/browser/sync/glue/non_frontend_data_type_controller_mock.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2011 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.
+
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h"
+
+namespace browser_sync {
+
+NonFrontendDataTypeControllerMock::NonFrontendDataTypeControllerMock() {}
+
+NonFrontendDataTypeControllerMock::~NonFrontendDataTypeControllerMock() {}
+
+} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h b/chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h
new file mode 100644
index 0000000..8e4316f
--- /dev/null
+++ b/chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2011 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.
+
+#ifndef CHROME_BROWSER_SYNC_GLUE_NON_FRONTEND_DATA_TYPE_CONTROLLER_MOCK_H__
+#define CHROME_BROWSER_SYNC_GLUE_NON_FRONTEND_DATA_TYPE_CONTROLLER_MOCK_H__
+#pragma once
+
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace browser_sync {
+
+class NonFrontendDataTypeControllerMock : public NonFrontendDataTypeController {
+ public:
+ NonFrontendDataTypeControllerMock();
+ virtual ~NonFrontendDataTypeControllerMock();
+
+ // DataTypeController mocks.
+ MOCK_METHOD1(Start, void(StartCallback* start_callback));
+ MOCK_METHOD0(Stop, void());
+ MOCK_METHOD0(enabled, bool());
+ MOCK_CONST_METHOD0(type, syncable::ModelType());
+ MOCK_CONST_METHOD0(name, std::string());
+ MOCK_CONST_METHOD0(model_safe_group, browser_sync::ModelSafeGroup());
+ MOCK_CONST_METHOD0(state, State());
+ MOCK_METHOD2(OnUnrecoverableError, void(const tracked_objects::Location&,
+ const std::string&));
+
+ // NonFrontendDataTypeController mocks.
+ MOCK_METHOD0(StartModels, bool());
+ MOCK_METHOD0(StartAssociationAsync, bool());
+ MOCK_METHOD0(StartAssociation, void());
+ MOCK_METHOD0(CreateSyncComponents, void());
+ MOCK_METHOD2(StartFailed, void(StartResult result,
+ const tracked_objects::Location& from_here));
+ MOCK_METHOD3(StartDone, void(DataTypeController::StartResult result,
+ DataTypeController::State new_state,
+ const tracked_objects::Location& location));
+ MOCK_METHOD3(StartDoneImpl, void(DataTypeController::StartResult result,
+ DataTypeController::State new_state,
+ const tracked_objects::Location& location));
+ MOCK_METHOD0(StopModels, void());
+ MOCK_METHOD0(StopAssociationAsync, bool());
+ MOCK_METHOD0(StopAssociation, void());
+ MOCK_METHOD2(OnUnrecoverableErrorImpl, void(const tracked_objects::Location&,
+ const std::string&));
+ MOCK_METHOD2(RecordUnrecoverableError, void(const tracked_objects::Location&,
+ const std::string&));
+ MOCK_METHOD1(RecordAssociationTime, void(base::TimeDelta time));
+ MOCK_METHOD1(RecordStartFailure, void(StartResult result));
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_GLUE_NON_FRONTEND_DATA_TYPE_CONTROLLER_MOCK_H__
diff --git a/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc b/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc
new file mode 100644
index 0000000..602e582
--- /dev/null
+++ b/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc
@@ -0,0 +1,397 @@
+// Copyright (c) 2011 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.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "base/test/test_timeouts.h"
+#include "base/tracked_objects.h"
+#include "base/synchronization/waitable_event.h"
+#include "chrome/browser/sync/engine/model_safe_worker.h"
+#include "chrome/browser/sync/glue/change_processor_mock.h"
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h"
+#include "chrome/browser/sync/glue/model_associator_mock.h"
+#include "chrome/browser/sync/profile_sync_factory_mock.h"
+#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/test/profile_mock.h"
+#include "content/browser/browser_thread.h"
+
+using base::WaitableEvent;
+using browser_sync::ChangeProcessorMock;
+using browser_sync::DataTypeController;
+using browser_sync::GROUP_DB;
+using browser_sync::NonFrontendDataTypeController;
+using browser_sync::NonFrontendDataTypeControllerMock;
+using browser_sync::ModelAssociatorMock;
+using testing::_;
+using testing::DoAll;
+using testing::InvokeWithoutArgs;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+class StartCallback {
+ public:
+ MOCK_METHOD2(Run, void(DataTypeController::StartResult result,
+ const tracked_objects::Location& from_here));
+};
+
+ACTION_P(WaitOnEvent, event) {
+ event->Wait();
+}
+
+ACTION_P(SignalEvent, event) {
+ event->Signal();
+}
+
+class NonFrontendDataTypeControllerFake : public NonFrontendDataTypeController {
+ public:
+ NonFrontendDataTypeControllerFake(
+ ProfileSyncFactory* profile_sync_factory,
+ Profile* profile,
+ NonFrontendDataTypeControllerMock* mock)
+ : NonFrontendDataTypeController(profile_sync_factory,
+ profile),
+ mock_(mock) {}
+
+ virtual syncable::ModelType type() const { return syncable::BOOKMARKS; }
+ virtual browser_sync::ModelSafeGroup model_safe_group() const {
+ return GROUP_DB;
+ }
+
+ private:
+ virtual void CreateSyncComponents() {
+ ProfileSyncFactory::SyncComponents sync_components =
+ profile_sync_factory()->
+ CreateBookmarkSyncComponents(profile_sync_service(), this);
+ set_model_associator(sync_components.model_associator);
+ set_change_processor(sync_components.change_processor);
+ }
+ virtual bool StartAssociationAsync() {
+ mock_->StartAssociationAsync();
+ return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &NonFrontendDataTypeControllerFake::StartAssociation));
+ }
+ virtual bool StopAssociationAsync() {
+ mock_->StopAssociationAsync();
+ return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &NonFrontendDataTypeControllerFake::StopAssociation));
+ }
+
+ // We mock the following methods because their default implementations do
+ // nothing, but we still want to make sure they're called appropriately.
+ virtual bool StartModels() {
+ return mock_->StartModels();
+ }
+ virtual void StopModels() {
+ mock_->StopModels();
+ }
+ virtual void RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message) {
+ mock_->RecordUnrecoverableError(from_here, message);
+ }
+ virtual void RecordAssociationTime(base::TimeDelta time) {
+ mock_->RecordAssociationTime(time);
+ }
+ virtual void RecordStartFailure(DataTypeController::StartResult result) {
+ mock_->RecordStartFailure(result);
+ }
+ private:
+ NonFrontendDataTypeControllerMock* mock_;
+};
+
+class NonFrontendDataTypeControllerTest : public testing::Test {
+ public:
+ NonFrontendDataTypeControllerTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_),
+ db_thread_(BrowserThread::DB),
+ model_associator_(NULL),
+ change_processor_(NULL),
+ signaled_(false) {}
+
+ virtual void SetUp() {
+ EXPECT_CALL(profile_, GetProfileSyncService()).WillRepeatedly(
+ Return(&service_));
+ db_thread_.Start();
+ profile_sync_factory_.reset(new ProfileSyncFactoryMock());
+
+ // Both of these are refcounted, so don't need to be released.
+ dtc_mock_ = new StrictMock<NonFrontendDataTypeControllerMock>();
+ non_frontend_dtc_ =
+ new NonFrontendDataTypeControllerFake(profile_sync_factory_.get(),
+ &profile_,
+ dtc_mock_.get());
+ }
+
+ virtual void TearDown() {
+ db_thread_.Stop();
+ }
+
+ protected:
+ void SetStartExpectations() {
+ EXPECT_CALL(*dtc_mock_, StartModels()).WillOnce(Return(true));
+ model_associator_ = new ModelAssociatorMock();
+ change_processor_ = new ChangeProcessorMock();
+ EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)).
+ WillOnce(Return(ProfileSyncFactory::SyncComponents(model_associator_,
+ change_processor_)));
+ }
+
+ void SetAssociateExpectations() {
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ }
+
+ void SetActivateExpectations(DataTypeController::StartResult result) {
+ EXPECT_CALL(service_, ActivateDataType(_, _));
+ EXPECT_CALL(start_callback_, Run(result,_));
+ }
+
+ void SetStopExpectations() {
+ EXPECT_CALL(*dtc_mock_, StopAssociationAsync());
+ EXPECT_CALL(*dtc_mock_, StopModels());
+ EXPECT_CALL(service_, DeactivateDataType(_, _));
+ EXPECT_CALL(*model_associator_, DisassociateModels());
+ }
+
+ void SetStartFailExpectations(DataTypeController::StartResult result) {
+ EXPECT_CALL(*dtc_mock_, StopModels());
+ EXPECT_CALL(*dtc_mock_, RecordStartFailure(result));
+ EXPECT_CALL(start_callback_, Run(result,_));
+ }
+
+ static void SignalDone(WaitableEvent* done, bool* signaled) {
+ done->Signal();
+ *signaled = true;
+ }
+
+ void WaitForDTC() {
+ WaitableEvent done(false, false);
+ signaled_ = false;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableFunction(&NonFrontendDataTypeControllerTest::SignalDone,
+ &done, &signaled_));
+ done.TimedWait(base::TimeDelta::FromMilliseconds(
+ TestTimeouts::action_max_timeout_ms()));
+ if (!signaled_) {
+ ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
+ }
+ signaled_ = false;
+ MessageLoop::current()->RunAllPending();
+ }
+
+ MessageLoopForUI message_loop_;
+ BrowserThread ui_thread_;
+ BrowserThread db_thread_;
+ scoped_refptr<NonFrontendDataTypeControllerFake> non_frontend_dtc_;
+ scoped_ptr<ProfileSyncFactoryMock> profile_sync_factory_;
+ scoped_refptr<NonFrontendDataTypeControllerMock> dtc_mock_;
+ ProfileMock profile_;
+ ProfileSyncServiceMock service_;
+ ModelAssociatorMock* model_associator_;
+ ChangeProcessorMock* change_processor_;
+ StartCallback start_callback_;
+ bool signaled_;
+};
+
+TEST_F(NonFrontendDataTypeControllerTest, StartOk) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ SetActivateExpectations(DataTypeController::OK);
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, StartFirstRun) {
+ SetStartExpectations();
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true)));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ SetActivateExpectations(DataTypeController::OK_FIRST_RUN);
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, AbortDuringStartModels) {
+ EXPECT_CALL(*dtc_mock_, StartModels()).WillOnce(Return(false));
+ SetStartFailExpectations(DataTypeController::ABORTED);
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::MODEL_STARTING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, StartAssociationFailed) {
+ SetStartExpectations();
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillOnce(Return(false));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
+ // Set up association to fail with an association failed error.
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest,
+ StartAssociationTriggersUnrecoverableError) {
+ SetStartExpectations();
+ SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
+ // Set up association to fail with an unrecoverable error.
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, StartAssociationCryptoNotReady) {
+ SetStartExpectations();
+ SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
+ // Set up association to fail with a NEEDS_CRYPTO error.
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillRepeatedly(Return(false));
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+// Trigger a Stop() call when we check if the model associator has user created
+// nodes.
+TEST_F(NonFrontendDataTypeControllerTest, AbortDuringAssociationInactive) {
+ WaitableEvent wait_for_db_thread_pause(false, false);
+ WaitableEvent pause_db_thread(false, false);
+
+ SetStartExpectations();
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(
+ SignalEvent(&wait_for_db_thread_pause),
+ WaitOnEvent(&pause_db_thread),
+ SetArgumentPointee<0>(true),
+ Return(true)));
+ EXPECT_CALL(*model_associator_, AbortAssociation()).WillOnce(
+ SignalEvent(&pause_db_thread));
+ EXPECT_CALL(*model_associator_, AssociateModels()).WillOnce(Return(true));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ EXPECT_CALL(service_, ActivateDataType(_, _));
+ EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED,_));
+ EXPECT_CALL(*dtc_mock_, RecordStartFailure(DataTypeController::ABORTED));
+ SetStopExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ wait_for_db_thread_pause.Wait();
+ non_frontend_dtc_->Stop();
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+// Same as above but abort during the Activate call.
+TEST_F(NonFrontendDataTypeControllerTest, AbortDuringAssociationActivated) {
+ WaitableEvent wait_for_db_thread_pause(false, false);
+ WaitableEvent pause_db_thread(false, false);
+
+ SetStartExpectations();
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(
+ SetArgumentPointee<0>(true),
+ Return(true)));
+ EXPECT_CALL(*model_associator_, AbortAssociation()).WillOnce(
+ SignalEvent(&pause_db_thread));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ EXPECT_CALL(service_, ActivateDataType(_, _)).WillOnce(DoAll(
+ SignalEvent(&wait_for_db_thread_pause),
+ WaitOnEvent(&pause_db_thread)));
+ EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED,_));
+ EXPECT_CALL(*dtc_mock_, RecordStartFailure(DataTypeController::ABORTED));
+ SetStopExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ wait_for_db_thread_pause.Wait();
+ non_frontend_dtc_->Stop();
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, Stop) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ SetActivateExpectations(DataTypeController::OK);
+ SetStopExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, OnUnrecoverableError) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ SetActivateExpectations(DataTypeController::OK);
+ EXPECT_CALL(*dtc_mock_, RecordUnrecoverableError(_, "Test"));
+ EXPECT_CALL(service_, OnUnrecoverableError(_,_)).WillOnce(
+ InvokeWithoutArgs(non_frontend_dtc_.get(),
+ &NonFrontendDataTypeController::Stop));
+ SetStopExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
+ // This should cause non_frontend_dtc_->Stop() to be called.
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(
+ non_frontend_dtc_.get(),
+ &NonFrontendDataTypeControllerFake::OnUnrecoverableError,
+ FROM_HERE,
+ std::string("Test")));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
diff --git a/chrome/browser/sync/glue/password_data_type_controller.cc b/chrome/browser/sync/glue/password_data_type_controller.cc
index 2589861..69b1d89 100644
--- a/chrome/browser/sync/glue/password_data_type_controller.cc
+++ b/chrome/browser/sync/glue/password_data_type_controller.cc
@@ -5,105 +5,66 @@
#include "chrome/browser/sync/glue/password_data_type_controller.h"
#include "base/metrics/histogram.h"
-#include "base/logging.h"
#include "base/task.h"
-#include "base/time.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync/glue/password_change_processor.h"
-#include "chrome/browser/sync/glue/password_model_associator.h"
-#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_factory.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/webdata/web_data_service.h"
#include "content/browser/browser_thread.h"
namespace browser_sync {
PasswordDataTypeController::PasswordDataTypeController(
ProfileSyncFactory* profile_sync_factory,
- Profile* profile,
- ProfileSyncService* sync_service)
- : profile_sync_factory_(profile_sync_factory),
- profile_(profile),
- sync_service_(sync_service),
- state_(NOT_RUNNING),
- abort_association_(false),
- abort_association_complete_(false, false),
- datatype_stopped_(false, false) {
- DCHECK(profile_sync_factory);
- DCHECK(profile);
- DCHECK(sync_service);
+ Profile* profile)
+ : NonFrontendDataTypeController(profile_sync_factory,
+ profile) {
}
PasswordDataTypeController::~PasswordDataTypeController() {
}
-void PasswordDataTypeController::Start(StartCallback* start_callback) {
+bool PasswordDataTypeController::StartModels() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(start_callback);
- if (state_ != NOT_RUNNING) {
- start_callback->Run(BUSY, FROM_HERE);
- delete start_callback;
- return;
- }
-
- password_store_ = profile_->GetPasswordStore(Profile::EXPLICIT_ACCESS);
+ DCHECK_EQ(state(), MODEL_STARTING);
+ password_store_ = profile()->GetPasswordStore(Profile::EXPLICIT_ACCESS);
if (!password_store_.get()) {
LOG(ERROR) << "PasswordStore not initialized, password datatype controller"
<< " aborting.";
- state_ = NOT_RUNNING;
- start_callback->Run(ABORTED, FROM_HERE);
- delete start_callback;
- return;
+ StartDoneImpl(ABORTED, NOT_RUNNING, FROM_HERE);
+ return false;
}
-
- start_callback_.reset(start_callback);
- abort_association_ = false;
- set_state(ASSOCIATING);
- password_store_->ScheduleTask(
- NewRunnableMethod(this, &PasswordDataTypeController::StartImpl));
+ return true;
}
-// TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of
-// distinguishing chrome shutdown from sync shutdown, we should be able to avoid
-// this (http://crbug.com/55662). Further, all this functionality should be
-// abstracted to a higher layer, where we could ensure all datatypes are doing
-// the same thing (http://crbug.com/76232).
-void PasswordDataTypeController::Stop() {
+bool PasswordDataTypeController::StartAssociationAsync() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // If Stop() is called while Start() is waiting for association to
- // complete, we need to abort the association and wait for the PASSWORD
- // thread to finish the StartImpl() task.
- if (state_ == ASSOCIATING) {
- {
- base::AutoLock lock(abort_association_lock_);
- abort_association_ = true;
- if (model_associator_.get())
- model_associator_->AbortAssociation();
- }
- // Wait for the model association to abort.
- abort_association_complete_.Wait();
- StartDoneImpl(ABORTED, STOPPING);
- }
-
- // If Stop() is called while Start() is waiting for another service to load,
- // abort the start.
- if (state_ == MODEL_STARTING)
- StartDoneImpl(ABORTED, STOPPING);
-
- DCHECK(!start_callback_.get());
-
- if (change_processor_ != NULL)
- sync_service_->DeactivateDataType(this, change_processor_.get());
-
- set_state(NOT_RUNNING);
+ DCHECK_EQ(state(), ASSOCIATING);
DCHECK(password_store_.get());
password_store_->ScheduleTask(
- NewRunnableMethod(this, &PasswordDataTypeController::StopImpl));
- datatype_stopped_.Wait();
+ NewRunnableMethod(this, &PasswordDataTypeController::StartAssociation));
+ return true;
+}
+
+void PasswordDataTypeController::CreateSyncComponents() {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), ASSOCIATING);
+ ProfileSyncFactory::SyncComponents sync_components =
+ profile_sync_factory()->CreatePasswordSyncComponents(
+ profile_sync_service(),
+ password_store_.get(),
+ this);
+ set_model_associator(sync_components.model_associator);
+ set_change_processor(sync_components.change_processor);
}
-bool PasswordDataTypeController::enabled() {
+bool PasswordDataTypeController::StopAssociationAsync() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), STOPPING);
+ DCHECK(password_store_.get());
+ password_store_->ScheduleTask(
+ NewRunnableMethod(this, &PasswordDataTypeController::StopAssociation));
return true;
}
@@ -116,111 +77,23 @@ browser_sync::ModelSafeGroup PasswordDataTypeController::model_safe_group()
return browser_sync::GROUP_PASSWORD;
}
-std::string PasswordDataTypeController::name() const {
- // For logging only.
- return "password";
-}
-
-DataTypeController::State PasswordDataTypeController::state() const {
- return state_;
-}
-
-void PasswordDataTypeController::StartImpl() {
- // No additional services need to be started before we can proceed
- // with model association.
- {
- base::AutoLock lock(abort_association_lock_);
- if (abort_association_) {
- abort_association_complete_.Signal();
- return;
- }
- ProfileSyncFactory::SyncComponents sync_components =
- profile_sync_factory_->CreatePasswordSyncComponents(
- sync_service_,
- password_store_.get(),
- this);
- model_associator_.reset(sync_components.model_associator);
- change_processor_.reset(sync_components.change_processor);
- }
-
- if (!model_associator_->CryptoReadyIfNecessary()) {
- StartFailed(NEEDS_CRYPTO);
- return;
- }
-
- bool sync_has_nodes = false;
- if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
- StartFailed(UNRECOVERABLE_ERROR);
- return;
- }
-
- base::TimeTicks start_time = base::TimeTicks::Now();
- bool merge_success = model_associator_->AssociateModels();
- UMA_HISTOGRAM_TIMES("Sync.PasswordAssociationTime",
- base::TimeTicks::Now() - start_time);
- if (!merge_success) {
- StartFailed(ASSOCIATION_FAILED);
- return;
- }
-
- sync_service_->ActivateDataType(this, change_processor_.get());
- StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING);
-}
-
-void PasswordDataTypeController::StartDone(
- DataTypeController::StartResult result,
- DataTypeController::State new_state) {
- abort_association_complete_.Signal();
- base::AutoLock lock(abort_association_lock_);
- if (!abort_association_) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this,
- &PasswordDataTypeController::StartDoneImpl,
- result,
- new_state));
- }
-}
-
-void PasswordDataTypeController::StartDoneImpl(
- DataTypeController::StartResult result,
- DataTypeController::State new_state) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- set_state(new_state);
- start_callback_->Run(result, FROM_HERE);
- start_callback_.reset();
-}
-
-void PasswordDataTypeController::StopImpl() {
- if (model_associator_ != NULL)
- model_associator_->DisassociateModels();
-
- change_processor_.reset();
- model_associator_.reset();
-
- datatype_stopped_.Signal();
-}
-
-void PasswordDataTypeController::StartFailed(StartResult result) {
- change_processor_.reset();
- model_associator_.reset();
- StartDone(result, NOT_RUNNING);
+void PasswordDataTypeController::RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ UMA_HISTOGRAM_COUNTS("Sync.PasswordRunFailures", 1);
}
-void PasswordDataTypeController::OnUnrecoverableError(
- const tracked_objects::Location& from_here, const std::string& message) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this,
- &PasswordDataTypeController::OnUnrecoverableErrorImpl,
- from_here, message));
+void PasswordDataTypeController::RecordAssociationTime(base::TimeDelta time) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ UMA_HISTOGRAM_TIMES("Sync.PasswordAssociationTime", time);
}
-void PasswordDataTypeController::OnUnrecoverableErrorImpl(
- const tracked_objects::Location& from_here,
- const std::string& message) {
+void PasswordDataTypeController::RecordStartFailure(StartResult result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- sync_service_->OnUnrecoverableError(from_here, message);
+ UMA_HISTOGRAM_ENUMERATION("Sync.PasswordStartFailures",
+ result,
+ MAX_START_RESULT);
}
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/password_data_type_controller.h b/chrome/browser/sync/glue/password_data_type_controller.h
index 1a3a9e41..f2e14f8 100644
--- a/chrome/browser/sync/glue/password_data_type_controller.h
+++ b/chrome/browser/sync/glue/password_data_type_controller.h
@@ -8,83 +8,40 @@
#include <string>
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/waitable_event.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/glue/data_type_controller.h"
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
class PasswordStore;
-class Profile;
-class ProfileSyncFactory;
-class ProfileSyncService;
namespace browser_sync {
-class AssociatorInterface;
-class ChangeProcessor;
-class ControlTask;
-
// A class that manages the startup and shutdown of password sync.
-class PasswordDataTypeController : public DataTypeController {
+class PasswordDataTypeController : public NonFrontendDataTypeController {
public:
PasswordDataTypeController(
ProfileSyncFactory* profile_sync_factory,
- Profile* profile,
- ProfileSyncService* sync_service);
+ Profile* profile);
virtual ~PasswordDataTypeController();
- // DataTypeController implementation
- virtual void Start(StartCallback* start_callback);
-
- virtual void Stop();
-
- virtual bool enabled();
-
+ // NonFrontendDataTypeController implementation
virtual syncable::ModelType type() const;
-
virtual browser_sync::ModelSafeGroup model_safe_group() const;
- virtual std::string name() const;
-
- virtual State state() const;
-
- // UnrecoverableHandler implementation
- virtual void OnUnrecoverableError(const tracked_objects::Location& from_here,
- const std::string& message);
+ protected:
+ // NonFrontendDataTypeController interface.
+ virtual bool StartModels();
+ virtual bool StartAssociationAsync();
+ virtual void CreateSyncComponents();
+ virtual bool StopAssociationAsync();
+ virtual void RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message);
+ virtual void RecordAssociationTime(base::TimeDelta time);
+ virtual void RecordStartFailure(StartResult result);
private:
- void StartImpl();
- void StartDone(StartResult result, State state);
- void StartDoneImpl(StartResult result, State state);
- void StopImpl();
- void StartFailed(StartResult result);
- void OnUnrecoverableErrorImpl(const tracked_objects::Location& from_here,
- const std::string& message);
-
- void set_state(State state) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- state_ = state;
- }
-
- ProfileSyncFactory* profile_sync_factory_;
- Profile* profile_;
- ProfileSyncService* sync_service_;
- State state_;
-
- scoped_ptr<AssociatorInterface> model_associator_;
- scoped_ptr<ChangeProcessor> change_processor_;
- scoped_ptr<StartCallback> start_callback_;
scoped_refptr<PasswordStore> password_store_;
- base::Lock abort_association_lock_;
- bool abort_association_;
- base::WaitableEvent abort_association_complete_;
-
- // Barrier to ensure that the datatype has been stopped on the DB thread
- // from the UI thread.
- base::WaitableEvent datatype_stopped_;
-
DISALLOW_COPY_AND_ASSIGN(PasswordDataTypeController);
};
diff --git a/chrome/browser/sync/glue/typed_url_data_type_controller.cc b/chrome/browser/sync/glue/typed_url_data_type_controller.cc
index 93be84d..73776fe 100644
--- a/chrome/browser/sync/glue/typed_url_data_type_controller.cc
+++ b/chrome/browser/sync/glue/typed_url_data_type_controller.cc
@@ -4,14 +4,10 @@
#include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
-#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/task.h"
-#include "base/time.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync/glue/typed_url_change_processor.h"
-#include "chrome/browser/sync/glue/typed_url_model_associator.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "content/browser/browser_thread.h"
@@ -26,11 +22,7 @@ class ControlTask : public HistoryDBTask {
virtual bool RunOnDBThread(history::HistoryBackend* backend,
history::HistoryDatabase* db) {
- if (start_) {
- controller_->StartImpl(backend);
- } else {
- controller_->StopImpl();
- }
+ controller_->RunOnHistoryThread(start_, backend);
// Release the reference to the controller. This ensures that
// the controller isn't held past its lifetime in unit tests.
@@ -47,104 +39,90 @@ class ControlTask : public HistoryDBTask {
TypedUrlDataTypeController::TypedUrlDataTypeController(
ProfileSyncFactory* profile_sync_factory,
- Profile* profile,
- ProfileSyncService* sync_service)
- : profile_sync_factory_(profile_sync_factory),
- profile_(profile),
- sync_service_(sync_service),
- state_(NOT_RUNNING),
- abort_association_(false),
- abort_association_complete_(false, false),
- datatype_stopped_(false, false) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(profile_sync_factory);
- DCHECK(profile);
- DCHECK(sync_service);
+ Profile* profile)
+ : NonFrontendDataTypeController(profile_sync_factory,
+ profile),
+ backend_(NULL) {
}
TypedUrlDataTypeController::~TypedUrlDataTypeController() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
-void TypedUrlDataTypeController::Start(StartCallback* start_callback) {
- VLOG(1) << "Starting typed_url data controller.";
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(start_callback);
- if (state_ != NOT_RUNNING || start_callback_.get()) {
- start_callback->Run(BUSY, FROM_HERE);
- delete start_callback;
- return;
+void TypedUrlDataTypeController::RunOnHistoryThread(bool start,
+ history::HistoryBackend* backend) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // The only variable we can access here is backend_, since it is always
+ // read from the DB thread. Touching anything else could lead to memory
+ // corruption.
+ backend_ = backend;
+ if (start) {
+ StartAssociation();
+ } else {
+ StopAssociation();
}
+ backend_ = NULL;
+}
- start_callback_.reset(start_callback);
- abort_association_ = false;
-
- HistoryService* history = profile_->GetHistoryServiceWithoutCreating();
+bool TypedUrlDataTypeController::StartModels() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), MODEL_STARTING);
+ HistoryService* history = profile()->GetHistoryServiceWithoutCreating();
if (history) {
- set_state(ASSOCIATING);
history_service_ = history;
- history_service_->ScheduleDBTask(new ControlTask(this, true), this);
+ return true;
} else {
- set_state(MODEL_STARTING);
notification_registrar_.Add(this, NotificationType::HISTORY_LOADED,
NotificationService::AllSources());
+ return false;
}
}
+bool TypedUrlDataTypeController::StartAssociationAsync() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), ASSOCIATING);
+ DCHECK(history_service_.get());
+ history_service_->ScheduleDBTask(new ControlTask(this, true), this);
+ return true;
+}
+
+void TypedUrlDataTypeController::CreateSyncComponents() {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), ASSOCIATING);
+ DCHECK(backend_);
+ ProfileSyncFactory::SyncComponents sync_components =
+ profile_sync_factory()->CreateTypedUrlSyncComponents(
+ profile_sync_service(),
+ backend_,
+ this);
+ set_model_associator(sync_components.model_associator);
+ set_change_processor(sync_components.change_processor);
+}
+
void TypedUrlDataTypeController::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- VLOG(1) << "History loaded observed.";
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), MODEL_STARTING);
notification_registrar_.Remove(this,
NotificationType::HISTORY_LOADED,
NotificationService::AllSources());
-
- history_service_ = profile_->GetHistoryServiceWithoutCreating();
+ history_service_ = profile()->GetHistoryServiceWithoutCreating();
DCHECK(history_service_.get());
- history_service_->ScheduleDBTask(new ControlTask(this, true), this);
+ set_state(ASSOCIATING);
+ StopAssociationAsync();
}
-// TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of
-// distinguishing chrome shutdown from sync shutdown, we should be able to avoid
-// this (http://crbug.com/55662). Further, all this functionality should be
-// abstracted to a higher layer, where we could ensure all datatypes are doing
-// the same thing (http://crbug.com/76232).
-void TypedUrlDataTypeController::Stop() {
- VLOG(1) << "Stopping typed_url data type controller.";
+void TypedUrlDataTypeController::StopModels() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(state() == STOPPING || state() == NOT_RUNNING);
+ notification_registrar_.RemoveAll();
+}
- // If Stop() is called while Start() is waiting for association to
- // complete, we need to abort the association and wait for the DB
- // thread to finish the StartImpl() task.
- if (state_ == ASSOCIATING) {
- {
- base::AutoLock lock(abort_association_lock_);
- abort_association_ = true;
- if (model_associator_.get())
- model_associator_->AbortAssociation();
- }
- // Wait for the model association to abort.
- abort_association_complete_.Wait();
- StartDoneImpl(ABORTED, STOPPING);
- }
-
- // If Stop() is called while Start() is waiting for the history service to
- // load, abort the start.
- if (state_ == MODEL_STARTING)
- StartDoneImpl(ABORTED, STOPPING);
-
- DCHECK(!start_callback_.get());
-
- if (change_processor_ != NULL)
- sync_service_->DeactivateDataType(this, change_processor_.get());
-
- set_state(NOT_RUNNING);
+bool TypedUrlDataTypeController::StopAssociationAsync() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(state(), STOPPING);
DCHECK(history_service_.get());
history_service_->ScheduleDBTask(new ControlTask(this, false), this);
- datatype_stopped_.Wait();
-}
-
-bool TypedUrlDataTypeController::enabled() {
return true;
}
@@ -157,125 +135,22 @@ browser_sync::ModelSafeGroup TypedUrlDataTypeController::model_safe_group()
return browser_sync::GROUP_HISTORY;
}
-std::string TypedUrlDataTypeController::name() const {
- // For logging only.
- return "typed_url";
-}
-
-DataTypeController::State TypedUrlDataTypeController::state() const {
- return state_;
-}
-
-void TypedUrlDataTypeController::StartImpl(history::HistoryBackend* backend) {
- VLOG(1) << "TypedUrl data type controller StartImpl called.";
- // No additional services need to be started before we can proceed
- // with model association.
- {
- base::AutoLock lock(abort_association_lock_);
- if (abort_association_) {
- abort_association_complete_.Signal();
- return;
- }
- ProfileSyncFactory::SyncComponents sync_components =
- profile_sync_factory_->CreateTypedUrlSyncComponents(
- sync_service_,
- backend,
- this);
- model_associator_.reset(sync_components.model_associator);
- change_processor_.reset(sync_components.change_processor);
- }
-
- if (!model_associator_->CryptoReadyIfNecessary()) {
- StartFailed(NEEDS_CRYPTO);
- return;
- }
-
- bool sync_has_nodes = false;
- if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
- StartFailed(UNRECOVERABLE_ERROR);
- return;
- }
-
- base::TimeTicks start_time = base::TimeTicks::Now();
- bool merge_success = model_associator_->AssociateModels();
- UMA_HISTOGRAM_TIMES("Sync.TypedUrlAssociationTime",
- base::TimeTicks::Now() - start_time);
- if (!merge_success) {
- StartFailed(ASSOCIATION_FAILED);
- return;
- }
-
- sync_service_->ActivateDataType(this, change_processor_.get());
- StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING);
-}
-
-void TypedUrlDataTypeController::StartDone(
- DataTypeController::StartResult result,
- DataTypeController::State new_state) {
- VLOG(1) << "TypedUrl data type controller StartDone called.";
-
- abort_association_complete_.Signal();
- base::AutoLock lock(abort_association_lock_);
- if (!abort_association_) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this,
- &TypedUrlDataTypeController::StartDoneImpl,
- result,
- new_state));
- }
-}
-
-void TypedUrlDataTypeController::StartDoneImpl(
- DataTypeController::StartResult result,
- DataTypeController::State new_state) {
- VLOG(1) << "TypedUrl data type controller StartDoneImpl called.";
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- set_state(new_state);
- start_callback_->Run(result, FROM_HERE);
- start_callback_.reset();
-
- if (result == UNRECOVERABLE_ERROR || result == ASSOCIATION_FAILED) {
- UMA_HISTOGRAM_ENUMERATION("Sync.TypedUrlStartFailures",
- result,
- MAX_START_RESULT);
- }
-}
-
-void TypedUrlDataTypeController::StopImpl() {
- VLOG(1) << "TypedUrl data type controller StopImpl called.";
-
- if (model_associator_ != NULL)
- model_associator_->DisassociateModels();
-
- change_processor_.reset();
- model_associator_.reset();
-
- datatype_stopped_.Signal();
-}
-
-void TypedUrlDataTypeController::StartFailed(StartResult result) {
- change_processor_.reset();
- model_associator_.reset();
- StartDone(result, NOT_RUNNING);
-}
-
-void TypedUrlDataTypeController::OnUnrecoverableError(
+void TypedUrlDataTypeController::RecordUnrecoverableError(
const tracked_objects::Location& from_here,
const std::string& message) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this,
- &TypedUrlDataTypeController::OnUnrecoverableErrorImpl,
- from_here, message));
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ UMA_HISTOGRAM_COUNTS("Sync.TypedUrlRunFailures", 1);
}
-void TypedUrlDataTypeController::OnUnrecoverableErrorImpl(
- const tracked_objects::Location& from_here,
- const std::string& message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- UMA_HISTOGRAM_COUNTS("Sync.TypedUrlRunFailures", 1);
- sync_service_->OnUnrecoverableError(from_here, message);
+void TypedUrlDataTypeController::RecordAssociationTime(base::TimeDelta time) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ UMA_HISTOGRAM_TIMES("Sync.TypedUrlAssociationTime", time);
}
+void TypedUrlDataTypeController::RecordStartFailure(StartResult result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ UMA_HISTOGRAM_ENUMERATION("Sync.TypedUrlStartFailures",
+ result,
+ MAX_START_RESULT);
+}
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/typed_url_data_type_controller.h b/chrome/browser/sync/glue/typed_url_data_type_controller.h
index 386a01d..2db5520 100644
--- a/chrome/browser/sync/glue/typed_url_data_type_controller.h
+++ b/chrome/browser/sync/glue/typed_url_data_type_controller.h
@@ -8,11 +8,8 @@
#include <string>
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/waitable_event.h"
-#include "chrome/browser/sync/glue/data_type_controller.h"
-#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
#include "content/browser/cancelable_request.h"
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
@@ -21,9 +18,6 @@
class NotificationSource;
class NotificationDetails;
class HistoryService;
-class Profile;
-class ProfileSyncFactory;
-class ProfileSyncService;
namespace history {
class HistoryBackend;
@@ -31,40 +25,22 @@ class HistoryBackend;
namespace browser_sync {
-class AssociatorInterface;
-class ChangeProcessor;
class ControlTask;
// A class that manages the startup and shutdown of typed_url sync.
-class TypedUrlDataTypeController : public DataTypeController,
+class TypedUrlDataTypeController : public NonFrontendDataTypeController,
public NotificationObserver,
public CancelableRequestConsumerBase {
public:
TypedUrlDataTypeController(
ProfileSyncFactory* profile_sync_factory,
- Profile* profile,
- ProfileSyncService* sync_service);
+ Profile* profile);
virtual ~TypedUrlDataTypeController();
- // DataTypeController implementation
- virtual void Start(StartCallback* start_callback);
-
- virtual void Stop();
-
- virtual bool enabled();
-
+ // NonFrontendDataTypeController implementation
virtual syncable::ModelType type() const;
-
virtual browser_sync::ModelSafeGroup model_safe_group() const;
- virtual std::string name() const;
-
- virtual State state() const;
-
- // UnrecoverableHandler implementation
- virtual void OnUnrecoverableError(const tracked_objects::Location& from_here,
- const std::string& message);
-
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
const NotificationSource& source,
@@ -73,50 +49,35 @@ class TypedUrlDataTypeController : public DataTypeController,
// CancelableRequestConsumerBase implementation.
virtual void OnRequestAdded(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle) {}
-
virtual void OnRequestRemoved(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle) {}
-
virtual void WillExecute(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle) {}
-
virtual void DidExecute(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle) {}
+ protected:
+ // NonFrontendDataTypeController interface.
+ virtual bool StartModels();
+ virtual bool StartAssociationAsync();
+ virtual void CreateSyncComponents();
+ virtual void StopModels();
+ virtual bool StopAssociationAsync();
+ virtual void RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message);
+ virtual void RecordAssociationTime(base::TimeDelta time);
+ virtual void RecordStartFailure(StartResult result);
+
private:
friend class ControlTask;
- void StartImpl(history::HistoryBackend* backend);
- void StartDone(StartResult result, State state);
- void StartDoneImpl(StartResult result, State state);
- void StopImpl();
- void StartFailed(StartResult result);
- void OnUnrecoverableErrorImpl(const tracked_objects::Location& from_here,
- const std::string& message);
-
- void set_state(State state) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- state_ = state;
- }
-
- ProfileSyncFactory* profile_sync_factory_;
- Profile* profile_;
- ProfileSyncService* sync_service_;
- State state_;
-
- scoped_ptr<AssociatorInterface> model_associator_;
- scoped_ptr<ChangeProcessor> change_processor_;
- scoped_ptr<StartCallback> start_callback_;
- scoped_refptr<HistoryService> history_service_;
- NotificationRegistrar notification_registrar_;
-
- base::Lock abort_association_lock_;
- bool abort_association_;
- base::WaitableEvent abort_association_complete_;
+ // Helper method to launch Associate() and Destroy() on the history thread.
+ void RunOnHistoryThread(bool start, history::HistoryBackend* backend);
- // Barrier to ensure that the datatype has been stopped on the DB thread
- // from the UI thread.
- base::WaitableEvent datatype_stopped_;
+ history::HistoryBackend* backend_;
+ scoped_refptr<HistoryService> history_service_;
+ NotificationRegistrar notification_registrar_;
DISALLOW_COPY_AND_ASSIGN(TypedUrlDataTypeController);
};
diff --git a/chrome/browser/sync/profile_sync_factory.h b/chrome/browser/sync/profile_sync_factory.h
index 776b61d..8befe35 100644
--- a/chrome/browser/sync/profile_sync_factory.h
+++ b/chrome/browser/sync/profile_sync_factory.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -47,12 +47,15 @@ class ProfileSyncFactory {
virtual ~ProfileSyncFactory() {}
- // Instantiates and initializes a new ProfileSyncService. Enabled
- // data types are registered with the service. The return pointer
- // is owned by the caller.
+ // Instantiates a new ProfileSyncService. The return pointer is owned by the
+ // caller.
virtual ProfileSyncService* CreateProfileSyncService(
const std::string& cros_user) = 0;
+ // Creates and registers enabled datatypes with the provided
+ // ProfileSyncService.
+ virtual void RegisterDataTypes(ProfileSyncService* pss) = 0;
+
// Instantiates a new DataTypeManager with a SyncBackendHost and a
// list of data type controllers. The return pointer is owned by
// the caller.
diff --git a/chrome/browser/sync/profile_sync_factory_impl.cc b/chrome/browser/sync/profile_sync_factory_impl.cc
index 9102e88..19f4938 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_factory_impl.cc
@@ -86,7 +86,10 @@ ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService(
ProfileSyncService* pss = new ProfileSyncService(
this, profile_, cros_user);
+ return pss;
+}
+void ProfileSyncFactoryImpl::RegisterDataTypes(ProfileSyncService* pss) {
// App sync is enabled by default. Register unless explicitly
// disabled.
if (!command_line_->HasSwitch(switches::kDisableSyncApps)) {
@@ -98,7 +101,7 @@ ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService(
// disabled.
if (!command_line_->HasSwitch(switches::kDisableSyncAutofill)) {
pss->RegisterDataTypeController(
- new AutofillDataTypeController(this, profile_, pss));
+ new AutofillDataTypeController(this, profile_));
}
// Bookmark sync is enabled by default. Register unless explicitly
@@ -119,7 +122,7 @@ ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService(
// disabled.
if (!command_line_->HasSwitch(switches::kDisableSyncPasswords)) {
pss->RegisterDataTypeController(
- new PasswordDataTypeController(this, profile_, pss));
+ new PasswordDataTypeController(this, profile_));
}
// Preference sync is enabled by default. Register unless explicitly
@@ -139,7 +142,7 @@ ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService(
// explicitly enabled.
if (command_line_->HasSwitch(switches::kEnableSyncTypedUrls)) {
pss->RegisterDataTypeController(
- new TypedUrlDataTypeController(this, profile_, pss));
+ new TypedUrlDataTypeController(this, profile_));
}
// Session sync is disabled by default. Register only if explicitly
@@ -150,10 +153,9 @@ ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService(
}
if (!command_line_->HasSwitch(switches::kDisableSyncAutofillProfile)) {
- pss->RegisterDataTypeController(new AutofillProfileDataTypeController(
- this, profile_, pss));
+ pss->RegisterDataTypeController(
+ new AutofillProfileDataTypeController(this, profile_));
}
- return pss;
}
DataTypeManager* ProfileSyncFactoryImpl::CreateDataTypeManager(
diff --git a/chrome/browser/sync/profile_sync_factory_impl.h b/chrome/browser/sync/profile_sync_factory_impl.h
index eb93f1c..2015a40 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.h
+++ b/chrome/browser/sync/profile_sync_factory_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -23,6 +23,8 @@ class ProfileSyncFactoryImpl : public ProfileSyncFactory {
virtual ProfileSyncService* CreateProfileSyncService(
const std::string& cros_user);
+ virtual void RegisterDataTypes(ProfileSyncService* pss);
+
virtual browser_sync::DataTypeManager* CreateDataTypeManager(
browser_sync::SyncBackendHost* backend,
const browser_sync::DataTypeController::TypeMap& controllers);
diff --git a/chrome/browser/sync/profile_sync_factory_impl_unittest.cc b/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
index 907b2f6..56643ac 100644
--- a/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
+++ b/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
@@ -76,6 +76,7 @@ class ProfileSyncFactoryImplTest : public testing::Test {
command_line_->AppendSwitch(cmd_switch);
scoped_ptr<ProfileSyncService> pss(
profile_sync_service_factory_->CreateProfileSyncService(""));
+ profile_sync_service_factory_->RegisterDataTypes(pss.get());
DataTypeController::StateMap controller_states;
pss->GetDataTypeControllerStates(&controller_states);
EXPECT_EQ(DefaultDatatypesCount() - 1, controller_states.size());
@@ -92,6 +93,7 @@ class ProfileSyncFactoryImplTest : public testing::Test {
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDefault) {
scoped_ptr<ProfileSyncService> pss(
profile_sync_service_factory_->CreateProfileSyncService(""));
+ profile_sync_service_factory_->RegisterDataTypes(pss.get());
DataTypeController::StateMap controller_states;
pss->GetDataTypeControllerStates(&controller_states);
EXPECT_EQ(DefaultDatatypesCount(), controller_states.size());
diff --git a/chrome/browser/sync/profile_sync_factory_mock.h b/chrome/browser/sync/profile_sync_factory_mock.h
index 2d8d8e2..3fa856c 100644
--- a/chrome/browser/sync/profile_sync_factory_mock.h
+++ b/chrome/browser/sync/profile_sync_factory_mock.h
@@ -26,6 +26,7 @@ class ProfileSyncFactoryMock : public ProfileSyncFactory {
MOCK_METHOD1(CreateProfileSyncService,
ProfileSyncService*(const std::string&));
+ MOCK_METHOD1(RegisterDataTypes, void(ProfileSyncService*));
MOCK_METHOD2(CreateDataTypeManager,
browser_sync::DataTypeManager*(
browser_sync::SyncBackendHost*,
diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
index a7b0e36..763d6bb 100644
--- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
@@ -207,8 +207,7 @@ class AutofillEntryFactory : public AbstractAutofillFactory {
ProfileMock* profile,
ProfileSyncService* service) {
return new AutofillDataTypeController(factory,
- profile,
- service);
+ profile);
}
void SetExpectation(ProfileSyncFactoryMock* factory,
@@ -228,8 +227,7 @@ class AutofillProfileFactory : public AbstractAutofillFactory {
ProfileMock* profile,
ProfileSyncService* service) {
return new AutofillProfileDataTypeController(factory,
- profile,
- service);
+ profile);
}
void SetExpectation(ProfileSyncFactoryMock* factory,
@@ -302,6 +300,8 @@ class ProfileSyncServiceAutofillTest : public AbstractProfileSyncServiceTest {
service_.reset(
new TestProfileSyncService(&factory_, &profile_, "test_user", false,
task));
+ EXPECT_CALL(profile_, GetProfileSyncService()).WillRepeatedly(
+ Return(service_.get()));
AutofillDataTypeController* data_type_controller =
factory->CreateDataTypeController(&factory_,
&profile_,
@@ -670,7 +670,6 @@ TEST_F(ProfileSyncServiceAutofillTest, HasNativeEntriesEmptySync) {
}
TEST_F(ProfileSyncServiceAutofillTest, HasProfileEmptySync) {
-
std::vector<AutofillProfile*> profiles;
std::vector<AutofillProfile> expected_profiles;
// Owned by GetAutofillProfiles caller.
diff --git a/chrome/browser/sync/profile_sync_service_password_unittest.cc b/chrome/browser/sync/profile_sync_service_password_unittest.cc
index 22005ce..94f2169 100644
--- a/chrome/browser/sync/profile_sync_service_password_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_password_unittest.cc
@@ -189,10 +189,11 @@ class ProfileSyncServicePasswordTest : public AbstractProfileSyncServiceTest {
&factory_, &profile_, "test_user", false, root_task, node_task));
service_->RegisterPreferences();
profile_.GetPrefs()->SetBoolean(prefs::kSyncPasswords, true);
+ EXPECT_CALL(profile_, GetProfileSyncService()).WillRepeatedly(
+ Return(service_.get()));
PasswordDataTypeController* data_type_controller =
new PasswordDataTypeController(&factory_,
- &profile_,
- service_.get());
+ &profile_);
EXPECT_CALL(factory_, CreatePasswordSyncComponents(_, _, _)).
Times(AtLeast(1)). // Can be more if we hit NEEDS_CRYPTO.
diff --git a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
index 7125cce..6184b6a 100644
--- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
@@ -163,10 +163,11 @@ class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
service_.reset(
new TestProfileSyncService(&factory_, &profile_, "test", false,
task));
+ EXPECT_CALL(profile_, GetProfileSyncService()).WillRepeatedly(
+ Return(service_.get()));
TypedUrlDataTypeController* data_type_controller =
new TypedUrlDataTypeController(&factory_,
- &profile_,
- service_.get());
+ &profile_);
EXPECT_CALL(factory_, CreateTypedUrlSyncComponents(_, _, _)).
WillOnce(MakeTypedUrlSyncComponents(service_.get(),