summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorskrul@chromium.org <skrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-14 18:32:06 +0000
committerskrul@chromium.org <skrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-14 18:32:06 +0000
commite29c77e0d8d63e3374a728bade376c01240820ba (patch)
tree258b23418f18b74fbd21cd39bfbec46f14cdb694 /chrome
parent5c9c1095e6156b45f1bf5cc7a5158faf3dba937d (diff)
downloadchromium_src-e29c77e0d8d63e3374a728bade376c01240820ba.zip
chromium_src-e29c77e0d8d63e3374a728bade376c01240820ba.tar.gz
chromium_src-e29c77e0d8d63e3374a728bade376c01240820ba.tar.bz2
AutofillDataTypeController should invoke start callback on abort.
BUG=41361 Review URL: http://codereview.chromium.org/1513034 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44504 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller.cc60
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller.h5
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc233
-rw-r--r--chrome/browser/sync/glue/autofill_model_associator.cc24
-rw-r--r--chrome/browser/sync/glue/autofill_model_associator.h12
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller.cc5
-rw-r--r--chrome/browser/sync/glue/bookmark_model_associator.h5
-rw-r--r--chrome/browser/sync/glue/change_processor.cc2
-rw-r--r--chrome/browser/sync/glue/model_associator.h5
-rw-r--r--chrome/browser/sync/glue/model_associator_mock.h1
-rw-r--r--chrome/browser/sync/glue/preference_data_type_controller.cc3
-rw-r--r--chrome/browser/sync/glue/preference_model_associator.h5
-rw-r--r--chrome/browser/sync/glue/theme_model_associator.h4
-rw-r--r--chrome/browser/sync/glue/typed_url_model_associator.h4
-rw-r--r--chrome/chrome_tests.gypi1
15 files changed, 349 insertions, 20 deletions
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.cc b/chrome/browser/sync/glue/autofill_data_type_controller.cc
index 7f2e1bc..e212e65 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller.cc
+++ b/chrome/browser/sync/glue/autofill_data_type_controller.cc
@@ -26,7 +26,9 @@ AutofillDataTypeController::AutofillDataTypeController(
profile_(profile),
sync_service_(sync_service),
state_(NOT_RUNNING),
- personal_data_(NULL) {
+ personal_data_(NULL),
+ abort_association_(false),
+ abort_association_complete_(false, false) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
DCHECK(profile_sync_factory);
DCHECK(profile);
@@ -48,6 +50,7 @@ void AutofillDataTypeController::Start(StartCallback* start_callback) {
}
start_callback_.reset(start_callback);
+ abort_association_ = false;
// 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
@@ -87,10 +90,8 @@ void AutofillDataTypeController::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
LOG(INFO) << "Web database loaded observed.";
- notification_registrar_.Remove(this,
- NotificationType::WEB_DATABASE_LOADED,
- NotificationService::AllSources());
-
+ notification_registrar_.RemoveAll();
+ set_state(ASSOCIATING);
ChromeThread::PostTask(ChromeThread::DB, FROM_HERE,
NewRunnableMethod(
this,
@@ -101,6 +102,30 @@ void AutofillDataTypeController::Stop() {
LOG(INFO) << "Stopping autofill data type controller.";
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ // If Stop() is called while Start() is waiting for association to
+ // complete, we need to abort the association.
+ if (state_ == ASSOCIATING) {
+ {
+ AutoLock lock(abort_association_lock_);
+ abort_association_ = true;
+ if (model_associator_.get())
+ model_associator_->Shutdown();
+ }
+ // Wait for the model association to abort.
+ abort_association_complete_.Wait();
+ StartDoneImpl(ABORTED, STOPPING);
+ }
+
+ // If Stop() is called while Start() is waiting for the personal web
+ // service or web data service to load, abort the start.
+ if (state_ == MODEL_STARTING)
+ StartDoneImpl(ABORTED, STOPPING);
+
+ // Note that we are doing most of the stop work here on the UI
+ // thread even though the associate & activate were done on the DB
+ // thread. This is because Stop() must be synchronous.
+ notification_registrar_.RemoveAll();
+ personal_data_->RemoveObserver(this);
if (change_processor_ != NULL)
sync_service_->DeactivateDataType(this, change_processor_.get());
@@ -152,12 +177,18 @@ void AutofillDataTypeController::StartDone(
DataTypeController::State new_state) {
LOG(INFO) << "Autofill data type controller StartDone called.";
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
- ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- this,
- &AutofillDataTypeController::StartDoneImpl,
- result,
- new_state));
+
+ AutoLock lock(abort_association_lock_);
+ if (abort_association_) {
+ abort_association_complete_.Signal();
+ } else {
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &AutofillDataTypeController::StartDoneImpl,
+ result,
+ new_state));
+ }
}
void AutofillDataTypeController::StartDoneImpl(
@@ -165,6 +196,13 @@ void AutofillDataTypeController::StartDoneImpl(
DataTypeController::State new_state) {
LOG(INFO) << "Autofill data type controller StartDoneImpl called.";
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ // If we were stopped while associating, just return.
+ if (state_ == NOT_RUNNING) {
+ LOG(WARNING) << "Stopped while associating.";
+ return;
+ }
+
set_state(new_state);
start_callback_->Run(result);
start_callback_.reset();
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.h b/chrome/browser/sync/glue/autofill_data_type_controller.h
index b9b5983..e522dbd 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller.h
+++ b/chrome/browser/sync/glue/autofill_data_type_controller.h
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "base/waitable_event.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
@@ -99,6 +100,10 @@ class AutofillDataTypeController : public DataTypeController,
NotificationRegistrar notification_registrar_;
+ Lock abort_association_lock_;
+ bool abort_association_;
+ base::WaitableEvent abort_association_complete_;
+
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
new file mode 100644
index 0000000..4897a88
--- /dev/null
+++ b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2010 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/message_loop.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/waitable_event.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
+#include "chrome/browser/sync/glue/change_processor_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/browser/sync/profile_sync_test_util.h"
+#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/test/profile_mock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using base::WaitableEvent;
+using browser_sync::AutofillDataTypeController;
+using browser_sync::ChangeProcessorMock;
+using browser_sync::DataTypeController;
+using browser_sync::ModelAssociatorMock;
+using testing::_;
+using testing::DoAll;
+using testing::Invoke;
+using testing::Return;
+using testing::SetArgumentPointee;
+
+namespace {
+
+ACTION_P(WaitOnEvent, event) {
+ event->Wait();
+}
+
+ACTION_P(SignalEvent, event) {
+ event->Signal();
+}
+
+class StartCallback {
+ public:
+ MOCK_METHOD1(Run, void(DataTypeController::StartResult result));
+};
+
+class PersonalDataManagerMock : public PersonalDataManager {
+ public:
+ MOCK_CONST_METHOD0(IsDataLoaded, bool());
+};
+
+class WebDataServiceFake : public WebDataService {
+ public:
+ WebDataServiceFake(bool is_database_loaded)
+ : is_database_loaded_(is_database_loaded) {}
+
+ virtual bool IsDatabaseLoaded() {
+ return is_database_loaded_;
+ }
+ private:
+ bool is_database_loaded_;
+};
+
+class SignalEventTask : public Task {
+ public:
+ SignalEventTask(WaitableEvent* done_event) : done_event_(done_event) {}
+
+ virtual void Run() {
+ done_event_->Signal();
+ }
+
+ private:
+ WaitableEvent* done_event_;
+};
+
+class AutofillDataTypeControllerTest : public testing::Test {
+ public:
+ AutofillDataTypeControllerTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_),
+ db_thread_(ChromeThread::DB) {}
+
+ virtual void SetUp() {
+ db_thread_.Start();
+ web_data_service_ = new WebDataServiceFake(true);
+ autofill_dtc_ =
+ new AutofillDataTypeController(&profile_sync_factory_,
+ &profile_,
+ &service_);
+ }
+
+ virtual void TearDown() {
+ WaitForEmptyDBMessageLoop();
+ db_thread_.Stop();
+ }
+
+ protected:
+ void SetStartExpectations() {
+ EXPECT_CALL(profile_, GetPersonalDataManager()).
+ WillRepeatedly(Return(&personal_data_manager_));
+ EXPECT_CALL(personal_data_manager_, IsDataLoaded()).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(profile_, GetWebDataService(_)).
+ WillOnce(Return(web_data_service_.get()));
+ }
+
+ void SetAssociateExpectations() {
+ model_associator_ = new ModelAssociatorMock();
+ change_processor_ = new ChangeProcessorMock();
+ EXPECT_CALL(profile_sync_factory_,
+ CreateAutofillSyncComponents(_, _, _, _)).
+ WillOnce(Return(
+ ProfileSyncFactory::SyncComponents(model_associator_,
+ change_processor_)));
+
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true)));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(service_, ActivateDataType(_, _));
+ }
+
+ void SetStopExpectations() {
+ EXPECT_CALL(service_, DeactivateDataType(_, _));
+ EXPECT_CALL(*model_associator_, DisassociateModels());
+ }
+
+ void WaitForEmptyDBMessageLoop() {
+ // Run a task through the DB message loop to ensure that
+ // everything before it has been run.
+ WaitableEvent done_event(false, false);
+ ChromeThread::PostTask(ChromeThread::DB,
+ FROM_HERE,
+ new SignalEventTask(&done_event));
+ done_event.Wait();
+ }
+
+ MessageLoopForUI message_loop_;
+ ChromeThread ui_thread_;
+ ChromeThread db_thread_;
+ scoped_refptr<AutofillDataTypeController> autofill_dtc_;
+ ProfileSyncFactoryMock profile_sync_factory_;
+ ProfileMock profile_;
+ PersonalDataManagerMock personal_data_manager_;
+ scoped_refptr<WebDataService> web_data_service_;
+ ProfileSyncServiceMock service_;
+ ModelAssociatorMock* model_associator_;
+ ChangeProcessorMock* change_processor_;
+ StartCallback start_callback_;
+};
+
+TEST_F(AutofillDataTypeControllerTest, StartPDMAndWDSReady) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, autofill_dtc_->state());
+ EXPECT_CALL(start_callback_, Run(DataTypeController::OK)).
+ WillOnce(QuitUIMessageLoop());;
+ autofill_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ MessageLoop::current()->Run();
+ EXPECT_EQ(DataTypeController::RUNNING, autofill_dtc_->state());
+ SetStopExpectations();
+ autofill_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, autofill_dtc_->state());
+}
+
+TEST_F(AutofillDataTypeControllerTest, AbortWhileSPDStarting) {
+ EXPECT_CALL(profile_, GetPersonalDataManager()).
+ WillRepeatedly(Return(&personal_data_manager_));
+ EXPECT_CALL(personal_data_manager_, IsDataLoaded()).
+ WillRepeatedly(Return(false));
+ autofill_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ EXPECT_EQ(DataTypeController::MODEL_STARTING, autofill_dtc_->state());
+
+ EXPECT_CALL(service_, DeactivateDataType(_, _)).Times(0);
+ EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED));
+ autofill_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, autofill_dtc_->state());
+}
+
+TEST_F(AutofillDataTypeControllerTest, AbortWhileWDSStarting) {
+ EXPECT_CALL(profile_, GetPersonalDataManager()).
+ WillRepeatedly(Return(&personal_data_manager_));
+ EXPECT_CALL(personal_data_manager_, IsDataLoaded()).
+ WillRepeatedly(Return(true));
+ scoped_refptr<WebDataServiceFake> web_data_service_not_loaded =
+ new WebDataServiceFake(false);
+ EXPECT_CALL(profile_, GetWebDataService(_)).
+ WillOnce(Return(web_data_service_not_loaded.get()));
+ autofill_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ EXPECT_EQ(DataTypeController::MODEL_STARTING, autofill_dtc_->state());
+
+ EXPECT_CALL(service_, DeactivateDataType(_, _)).Times(0);
+ EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED));
+ autofill_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, autofill_dtc_->state());
+}
+
+TEST_F(AutofillDataTypeControllerTest, AbortWhileAssociating) {
+ SetStartExpectations();
+
+ model_associator_ = new ModelAssociatorMock();
+ change_processor_ = new ChangeProcessorMock();
+ EXPECT_CALL(profile_sync_factory_,
+ CreateAutofillSyncComponents(_, _, _, _)).
+ WillOnce(Return(
+ ProfileSyncFactory::SyncComponents(model_associator_,
+ change_processor_)));
+
+ WaitableEvent pause_db_thread(false, false);
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(
+ WaitOnEvent(&pause_db_thread),
+ SetArgumentPointee<0>(true),
+ Return(false)));
+ EXPECT_CALL(*model_associator_, Shutdown()).
+ WillOnce(SignalEvent(&pause_db_thread));
+
+ autofill_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ EXPECT_EQ(DataTypeController::ASSOCIATING, autofill_dtc_->state());
+
+ EXPECT_CALL(service_, DeactivateDataType(_, _)).Times(0);
+ EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED));
+ autofill_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, autofill_dtc_->state());
+}
+
+} // namespace
diff --git a/chrome/browser/sync/glue/autofill_model_associator.cc b/chrome/browser/sync/glue/autofill_model_associator.cc
index ca3ae96..ec76cf5 100644
--- a/chrome/browser/sync/glue/autofill_model_associator.cc
+++ b/chrome/browser/sync/glue/autofill_model_associator.cc
@@ -38,7 +38,8 @@ AutofillModelAssociator::AutofillModelAssociator(
web_database_(web_database),
personal_data_(personal_data),
error_handler_(error_handler),
- autofill_node_id_(sync_api::kInvalidId) {
+ autofill_node_id_(sync_api::kInvalidId),
+ shutdown_(false) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
DCHECK(sync_service_);
DCHECK(web_database_);
@@ -60,6 +61,8 @@ bool AutofillModelAssociator::TraverseAndAssociateChromeAutofillEntries(
const std::vector<AutofillEntry>& entries = all_entries_from_db;
for (std::vector<AutofillEntry>::const_iterator ix = entries.begin();
ix != entries.end(); ++ix) {
+ if (ShouldShutdown())
+ return false;
std::string tag = KeyToTag(ix->key().name(), ix->key().value());
if (id_map_.find(tag) != id_map_.end()) {
// It seems that name/value pairs are not unique in the web database.
@@ -114,6 +117,8 @@ bool AutofillModelAssociator::TraverseAndAssociateChromeAutoFillProfiles(
const std::vector<AutoFillProfile*>& profiles = all_profiles_from_db;
for (std::vector<AutoFillProfile*>::const_iterator ix = profiles.begin();
ix != profiles.end(); ++ix) {
+ if (ShouldShutdown())
+ return false;
string16 label((*ix)->Label());
std::string tag(ProfileLabelToTag(label));
@@ -262,11 +267,15 @@ bool AutofillModelAssociator::SaveChangesToWebData(const DataBundle& bundle) {
}
for (size_t i = 0; i < bundle.new_profiles.size(); i++) {
+ if (ShouldShutdown())
+ return false;
if (!web_database_->AddAutoFillProfile(*bundle.new_profiles[i]))
return false;
}
for (size_t i = 0; i < bundle.updated_profiles.size(); i++) {
+ if (ShouldShutdown())
+ return false;
if (!web_database_->UpdateAutoFillProfile(*bundle.updated_profiles[i]))
return false;
}
@@ -281,6 +290,8 @@ bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes(
int64 sync_child_id = autofill_root.GetFirstChildId();
while (sync_child_id != sync_api::kInvalidId) {
+ if (ShouldShutdown())
+ return false;
sync_api::ReadNode sync_child(write_trans);
if (!sync_child.InitByIdLookup(sync_child_id)) {
LOG(ERROR) << "Failed to fetch child node.";
@@ -373,6 +384,12 @@ bool AutofillModelAssociator::ChromeModelHasUserCreatedNodes(bool* has_nodes) {
return true;
}
+void AutofillModelAssociator::Shutdown() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ AutoLock lock(shutdown_lock_);
+ shutdown_ = true;
+}
+
int64 AutofillModelAssociator::GetSyncIdFromChromeId(
const std::string autofill) {
AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill);
@@ -409,6 +426,11 @@ bool AutofillModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
return true;
}
+bool AutofillModelAssociator::ShouldShutdown() {
+ AutoLock lock(shutdown_lock_);
+ return shutdown_;
+}
+
// static
std::string AutofillModelAssociator::KeyToTag(const string16& name,
const string16& value) {
diff --git a/chrome/browser/sync/glue/autofill_model_associator.h b/chrome/browser/sync/glue/autofill_model_associator.h
index b1869b9..9dcf899 100644
--- a/chrome/browser/sync/glue/autofill_model_associator.h
+++ b/chrome/browser/sync/glue/autofill_model_associator.h
@@ -11,6 +11,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/lock.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/chrome_thread.h"
@@ -80,6 +81,10 @@ class AutofillModelAssociator
// user-defined autofill entries.
virtual bool ChromeModelHasUserCreatedNodes(bool* has_nodes);
+ // Call this from the main thread if the autofill model associator
+ // should stop what it is doing and shutdown.
+ virtual void Shutdown();
+
// Not implemented.
virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id) {
return NULL;
@@ -189,6 +194,8 @@ class AutofillModelAssociator
const AutoFillProfile& profile,
int64* sync_id);
+ bool ShouldShutdown();
+
ProfileSyncService* sync_service_;
WebDatabase* web_database_;
PersonalDataManager* personal_data_;
@@ -198,6 +205,11 @@ class AutofillModelAssociator
AutofillToSyncIdMap id_map_;
SyncIdToAutofillMap id_map_inverse_;
+ // Shutdown flag and lock. If this is set to true (via the Shutdown
+ // method), return from the current method as soon as possible.
+ Lock shutdown_lock_;
+ bool shutdown_;
+
DISALLOW_COPY_AND_ASSIGN(AutofillModelAssociator);
};
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.cc b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
index e9cf83f..65f649a 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller.cc
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
@@ -73,11 +73,8 @@ void BookmarkDataTypeController::Stop() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
// If Stop() is called while Start() is waiting for the bookmark
// model to load, abort the start.
- if (unrecoverable_error_detected_) {
- FinishStart(UNRECOVERABLE_ERROR);
- } else if (state_ == MODEL_STARTING) {
+ if (state_ == MODEL_STARTING)
FinishStart(ABORTED);
- }
registrar_.RemoveAll();
if (change_processor_ != NULL)
diff --git a/chrome/browser/sync/glue/bookmark_model_associator.h b/chrome/browser/sync/glue/bookmark_model_associator.h
index 9df77cd..ded5f2c 100644
--- a/chrome/browser/sync/glue/bookmark_model_associator.h
+++ b/chrome/browser/sync/glue/bookmark_model_associator.h
@@ -82,6 +82,11 @@ class BookmarkModelAssociator
// Remove the association that corresponds to the given sync id.
virtual void Disassociate(int64 sync_id);
+ virtual void Shutdown() {
+ // No implementation needed, this associator runs on the main
+ // thread.
+ }
+
protected:
// Stores the id of the node with the given tag in |sync_id|.
// Returns of that node was found successfully.
diff --git a/chrome/browser/sync/glue/change_processor.cc b/chrome/browser/sync/glue/change_processor.cc
index 0c608b8..6b25382 100644
--- a/chrome/browser/sync/glue/change_processor.cc
+++ b/chrome/browser/sync/glue/change_processor.cc
@@ -8,7 +8,7 @@
namespace browser_sync {
ChangeProcessor::~ChangeProcessor() {
- Stop();
+ DCHECK(!running_) << "ChangeProcessor dtor while running";
}
void ChangeProcessor::Start(Profile* profile,
diff --git a/chrome/browser/sync/glue/model_associator.h b/chrome/browser/sync/glue/model_associator.h
index b7f7622..a000291 100644
--- a/chrome/browser/sync/glue/model_associator.h
+++ b/chrome/browser/sync/glue/model_associator.h
@@ -43,6 +43,11 @@ class AssociatorInterface {
// has user-created nodes. The method may return false if an error
// occurred.
virtual bool ChromeModelHasUserCreatedNodes(bool* has_nodes) = 0;
+
+ // For associators that work off the main thread, calling this
+ // method will signal that they must stop and return "false" from
+ // any method they are currently in.
+ virtual void Shutdown() = 0;
};
// In addition to the generic methods, association can refer to operations
diff --git a/chrome/browser/sync/glue/model_associator_mock.h b/chrome/browser/sync/glue/model_associator_mock.h
index 6efe02d..9b33f72 100644
--- a/chrome/browser/sync/glue/model_associator_mock.h
+++ b/chrome/browser/sync/glue/model_associator_mock.h
@@ -16,6 +16,7 @@ class ModelAssociatorMock : public AssociatorInterface {
MOCK_METHOD0(DisassociateModels, bool());
MOCK_METHOD1(SyncModelHasUserCreatedNodes, bool(bool*));
MOCK_METHOD1(ChromeModelHasUserCreatedNodes, bool(bool*));
+ MOCK_METHOD0(Shutdown, void());
};
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/preference_data_type_controller.cc b/chrome/browser/sync/glue/preference_data_type_controller.cc
index 75b964f..6309d94d 100644
--- a/chrome/browser/sync/glue/preference_data_type_controller.cc
+++ b/chrome/browser/sync/glue/preference_data_type_controller.cc
@@ -73,9 +73,6 @@ void PreferenceDataTypeController::Start(StartCallback* start_callback) {
void PreferenceDataTypeController::Stop() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- if (unrecoverable_error_detected_) {
- FinishStart(UNRECOVERABLE_ERROR);
- }
if (change_processor_ != NULL)
sync_service_->DeactivateDataType(this, change_processor_.get());
diff --git a/chrome/browser/sync/glue/preference_model_associator.h b/chrome/browser/sync/glue/preference_model_associator.h
index 7495b59..de04e90 100644
--- a/chrome/browser/sync/glue/preference_model_associator.h
+++ b/chrome/browser/sync/glue/preference_model_associator.h
@@ -56,6 +56,11 @@ class PreferenceModelAssociator
// Returns whether the preference model has any user-defined preferences.
virtual bool ChromeModelHasUserCreatedNodes(bool* has_nodes);
+ virtual void Shutdown() {
+ // No implementation needed, this associator runs on the main
+ // thread.
+ }
+
// Not implemented.
virtual const PrefService::Preference* GetChromeNodeFromSyncId(
int64 sync_id) {
diff --git a/chrome/browser/sync/glue/theme_model_associator.h b/chrome/browser/sync/glue/theme_model_associator.h
index 12cbc62..8c90f75 100644
--- a/chrome/browser/sync/glue/theme_model_associator.h
+++ b/chrome/browser/sync/glue/theme_model_associator.h
@@ -31,6 +31,10 @@ class ThemeModelAssociator : public AssociatorInterface {
virtual bool DisassociateModels();
virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes);
virtual bool ChromeModelHasUserCreatedNodes(bool* has_nodes);
+ virtual void Shutdown() {
+ // No implementation needed, this associator runs on the main
+ // thread.
+ }
private:
ProfileSyncService* sync_service_;
diff --git a/chrome/browser/sync/glue/typed_url_model_associator.h b/chrome/browser/sync/glue/typed_url_model_associator.h
index b3087c6..65a0d9c 100644
--- a/chrome/browser/sync/glue/typed_url_model_associator.h
+++ b/chrome/browser/sync/glue/typed_url_model_associator.h
@@ -77,6 +77,10 @@ class TypedUrlModelAssociator
// user-defined typed_url entries.
virtual bool ChromeModelHasUserCreatedNodes(bool* has_nodes);
+ virtual void Shutdown() {
+ // TODO(zork): Implement this.
+ }
+
// Not implemented.
virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id) {
return NULL;
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 5c5f7d8..85fd8de 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -890,6 +890,7 @@
'browser/ssl/ssl_host_state_unittest.cc',
'browser/status_icons/status_icon_unittest.cc',
'browser/status_icons/status_tray_unittest.cc',
+ 'browser/sync/glue/autofill_data_type_controller_unittest.cc',
'browser/sync/glue/autofill_model_associator_unittest.cc',
'browser/sync/glue/bookmark_data_type_controller_unittest.cc',
'browser/sync/glue/change_processor_mock.h',