diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-12 23:29:10 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-12 23:31:52 +0000 |
commit | f5de7a00d48ef86eeb126652d9f68ac00ac6db23 (patch) | |
tree | e46b13ae2e4c8ea820091cef6e3b5523f21047a8 | |
parent | 209d521c49a8cae194ea5f1458a2ecbbba2bcc78 (diff) | |
download | chromium_src-f5de7a00d48ef86eeb126652d9f68ac00ac6db23.zip chromium_src-f5de7a00d48ef86eeb126652d9f68ac00ac6db23.tar.gz chromium_src-f5de7a00d48ef86eeb126652d9f68ac00ac6db23.tar.bz2 |
Revert 288557 "[Sync] Use OnSingleDataTypeUnrecoverableError for..."
Reason for revert: see crbug.com/403098
> [Sync] Use OnSingleDataTypeUnrecoverableError for all errors
>
> This removes the disable callback from all datatype controllers as well
> as the DisableDataType method from the PSS, in favor of
> OnSingleDataTypeUnrecoverable error (which now accepts a SyncError).
>
> BUG=368834,403098
> TBR=bauerb@chromium.org
>
> Review URL: https://codereview.chromium.org/436733002
TBR=zea@chromium.org
Review URL: https://codereview.chromium.org/465113002
Cr-Commit-Position: refs/heads/master@{#289113}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289113 0039d316-1c4b-4281-b951-d872f2087c98
60 files changed, 482 insertions, 285 deletions
diff --git a/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.cc b/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.cc index 8c23834..8e42c4e 100644 --- a/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.cc +++ b/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.cc @@ -9,6 +9,7 @@ #include "content/public/browser/browser_thread.h" SupervisedUserSyncDataTypeController::SupervisedUserSyncDataTypeController( + const DisableTypeCallback& disable_callback, syncer::ModelType type, sync_driver::SyncApiComponentFactory* sync_factory, Profile* profile) @@ -16,6 +17,7 @@ SupervisedUserSyncDataTypeController::SupervisedUserSyncDataTypeController( content::BrowserThread::GetMessageLoopProxyForThread( content::BrowserThread::UI), base::Bind(&browser_sync::ChromeReportUnrecoverableError), + disable_callback, type, sync_factory), profile_(profile) { diff --git a/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.h b/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.h index a2818a9..5b7b1af 100644 --- a/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.h +++ b/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.h @@ -22,6 +22,7 @@ class SupervisedUserSyncDataTypeController : public sync_driver::UIDataTypeController { public: SupervisedUserSyncDataTypeController( + const DisableTypeCallback& disable_callback, syncer::ModelType type, sync_driver::SyncApiComponentFactory* sync_factory, Profile* profile); diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.cc b/chrome/browser/sync/glue/autofill_data_type_controller.cc index 8225b24..48dec09 100644 --- a/chrome/browser/sync/glue/autofill_data_type_controller.cc +++ b/chrome/browser/sync/glue/autofill_data_type_controller.cc @@ -23,10 +23,12 @@ namespace browser_sync { AutofillDataTypeController::AutofillDataTypeController( ProfileSyncComponentsFactory* profile_sync_factory, - Profile* profile) + Profile* profile, + const DisableTypeCallback& disable_callback) : NonUIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, profile_sync_factory), profile_(profile) { } diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.h b/chrome/browser/sync/glue/autofill_data_type_controller.h index a213d12..1f4c126 100644 --- a/chrome/browser/sync/glue/autofill_data_type_controller.h +++ b/chrome/browser/sync/glue/autofill_data_type_controller.h @@ -27,7 +27,8 @@ class AutofillDataTypeController public: AutofillDataTypeController( ProfileSyncComponentsFactory* profile_sync_factory, - Profile* profile); + Profile* profile, + const DisableTypeCallback& disable_callback); // NonUIDataTypeController implementation. virtual syncer::ModelType type() const OVERRIDE; 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 fcdd0e7..6107331 100644 --- a/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc +++ b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc @@ -153,7 +153,8 @@ class SyncAutofillDataTypeControllerTest : public testing::Test { autofill_dtc_ = new AutofillDataTypeController( - &profile_sync_factory_, &profile_); + &profile_sync_factory_, &profile_, + sync_driver::DataTypeController::DisableTypeCallback()); } // Passed to AutofillDTC::Start(). 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 9907386..f8edcd7 100644 --- a/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc +++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc @@ -24,10 +24,12 @@ namespace browser_sync { AutofillProfileDataTypeController::AutofillProfileDataTypeController( ProfileSyncComponentsFactory* profile_sync_factory, - Profile* profile) + Profile* profile, + const DisableTypeCallback& disable_callback) : NonUIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, profile_sync_factory), profile_(profile), personal_data_(NULL), 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 9641c67..9b1b4fd 100644 --- a/chrome/browser/sync/glue/autofill_profile_data_type_controller.h +++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.h @@ -26,7 +26,8 @@ class AutofillProfileDataTypeController public: AutofillProfileDataTypeController( ProfileSyncComponentsFactory* profile_sync_factory, - Profile* profile); + Profile* profile, + const DisableTypeCallback& disable_callback); // NonUIDataTypeController implementation. virtual syncer::ModelType type() const OVERRIDE; diff --git a/chrome/browser/sync/glue/bookmark_change_processor.cc b/chrome/browser/sync/glue/bookmark_change_processor.cc index d6c4d6a..8e31f92 100644 --- a/chrome/browser/sync/glue/bookmark_change_processor.cc +++ b/chrome/browser/sync/glue/bookmark_change_processor.cc @@ -120,11 +120,8 @@ void BookmarkChangeProcessor::RemoveSyncNodeHierarchy( syncer::WriteNode topmost_sync_node(&trans); if (!model_associator_->InitSyncNodeFromChromeId(topmost->id(), &topmost_sync_node)) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to init sync node from chrome node", - syncer::BOOKMARKS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + std::string()); return; } // Check that |topmost| has been unlinked. @@ -166,11 +163,8 @@ void BookmarkChangeProcessor::RemoveAllChildNodes( syncer::WriteNode topmost_node(trans); if (!model_associator_->InitSyncNodeFromChromeId(topmost_node_id, &topmost_node)) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to init sync node from chrome node", - syncer::BOOKMARKS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + std::string()); return; } const int64 topmost_sync_id = topmost_node.GetId(); @@ -278,11 +272,8 @@ int64 BookmarkChangeProcessor::CreateSyncNode(const BookmarkNode* parent, // Actually create the node with the appropriate initial position. if (!PlaceSyncNode(CREATE, parent, index, trans, &sync_child, associator)) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed ot creat sync node.", - syncer::BOOKMARKS); - error_handler->OnSingleDataTypeUnrecoverableError(error); + error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "Sync node creation failed; recovery unlikely"); return syncer::kInvalidId; } @@ -330,11 +321,8 @@ int64 BookmarkChangeProcessor::UpdateSyncNode( // Lookup the sync node that's associated with |node|. syncer::WriteNode sync_node(trans); if (!associator->InitSyncNodeFromChromeId(node->id(), &sync_node)) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to init sync node from chrome node", - syncer::BOOKMARKS); - error_handler->OnSingleDataTypeUnrecoverableError(error); + error_handler->OnSingleDatatypeUnrecoverableError( + FROM_HERE, "Could not load bookmark node on update."); return syncer::kInvalidId; } UpdateSyncNodeProperties(node, model, &sync_node); @@ -368,21 +356,15 @@ void BookmarkChangeProcessor::BookmarkNodeMoved(BookmarkModel* model, // Lookup the sync node that's associated with |child|. syncer::WriteNode sync_node(&trans); if (!model_associator_->InitSyncNodeFromChromeId(child->id(), &sync_node)) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to init sync node from chrome node", - syncer::BOOKMARKS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + std::string()); return; } if (!PlaceSyncNode(MOVE, new_parent, new_index, &trans, &sync_node, model_associator_)) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to place sync node", - syncer::BOOKMARKS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + std::string()); return; } } @@ -414,11 +396,8 @@ void BookmarkChangeProcessor::BookmarkNodeChildrenReordered( syncer::WriteNode sync_child(&trans); if (!model_associator_->InitSyncNodeFromChromeId(child->id(), &sync_child)) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to init sync node from chrome node", - syncer::BOOKMARKS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + std::string()); return; } DCHECK_EQ(sync_child.GetParentId(), @@ -426,11 +405,8 @@ void BookmarkChangeProcessor::BookmarkNodeChildrenReordered( if (!PlaceSyncNode(MOVE, node, i, &trans, &sync_child, model_associator_)) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to place sync node", - syncer::BOOKMARKS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + std::string()); return; } } @@ -552,11 +528,8 @@ void BookmarkChangeProcessor::ApplyChangesFromSyncModel( model->other_node()->child_count(), base::string16()); if (!foster_parent) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to create foster parent", - syncer::BOOKMARKS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "Failed to create foster parent."); return; } } @@ -613,11 +586,8 @@ void BookmarkChangeProcessor::ApplyChangesFromSyncModel( syncer::ReadNode src(trans); if (src.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to load sync node", - syncer::BOOKMARKS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "ApplyModelChanges was passed a bad ID"); return; } diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc index 3c00de5..d8b7ead 100644 --- a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc +++ b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc @@ -335,3 +335,21 @@ TEST_F(SyncBookmarkDataTypeControllerTest, Stop) { bookmark_dtc_->Stop(); EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state()); } + +TEST_F(SyncBookmarkDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) { + CreateBookmarkModel(LOAD_MODEL); + SetStartExpectations(); + SetAssociateExpectations(); + EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true))); + EXPECT_CALL(service_, DisableDatatype(_)). + WillOnce(InvokeWithoutArgs(bookmark_dtc_.get(), + &BookmarkDataTypeController::Stop)); + SetStopExpectations(); + + EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); + Start(); + // This should cause bookmark_dtc_->Stop() to be called. + bookmark_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test"); + base::RunLoop().RunUntilIdle(); +} diff --git a/chrome/browser/sync/glue/bookmark_model_associator.cc b/chrome/browser/sync/glue/bookmark_model_associator.cc index c77bf96..4ea6b9c 100644 --- a/chrome/browser/sync/glue/bookmark_model_associator.cc +++ b/chrome/browser/sync/glue/bookmark_model_associator.cc @@ -730,12 +730,9 @@ void BookmarkModelAssociator::PersistAssociations() { int64 sync_id = *iter; syncer::WriteNode sync_node(&trans); if (sync_node.InitByIdLookup(sync_id) != syncer::BaseNode::INIT_OK) { - syncer::SyncError error( + unrecoverable_error_handler_->OnSingleDatatypeUnrecoverableError( FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Could not lookup bookmark node for ID persistence.", - syncer::BOOKMARKS); - unrecoverable_error_handler_->OnSingleDataTypeUnrecoverableError(error); + "Could not lookup bookmark node for ID persistence."); return; } const BookmarkNode* node = GetChromeNodeFromSyncId(sync_id); diff --git a/chrome/browser/sync/glue/device_info_data_type_controller.cc b/chrome/browser/sync/glue/device_info_data_type_controller.cc index 81d0fa8..a8deb06 100644 --- a/chrome/browser/sync/glue/device_info_data_type_controller.cc +++ b/chrome/browser/sync/glue/device_info_data_type_controller.cc @@ -14,10 +14,12 @@ namespace browser_sync { DeviceInfoDataTypeController::DeviceInfoDataTypeController( sync_driver::SyncApiComponentFactory* sync_factory, - LocalDeviceInfoProvider* local_device_info_provider) + LocalDeviceInfoProvider* local_device_info_provider, + const DisableTypeCallback& disable_callback) : UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, syncer::DEVICE_INFO, sync_factory), local_device_info_provider_(local_device_info_provider) { diff --git a/chrome/browser/sync/glue/device_info_data_type_controller.h b/chrome/browser/sync/glue/device_info_data_type_controller.h index 38c7b45..979536f 100644 --- a/chrome/browser/sync/glue/device_info_data_type_controller.h +++ b/chrome/browser/sync/glue/device_info_data_type_controller.h @@ -16,7 +16,8 @@ class DeviceInfoDataTypeController : public sync_driver::UIDataTypeController { public: DeviceInfoDataTypeController( sync_driver::SyncApiComponentFactory* sync_factory, - LocalDeviceInfoProvider* local_device_info_provider); + LocalDeviceInfoProvider* local_device_info_provider, + const DisableTypeCallback& disable_callback); private: virtual ~DeviceInfoDataTypeController(); diff --git a/chrome/browser/sync/glue/device_info_data_type_controller_unittest.cc b/chrome/browser/sync/glue/device_info_data_type_controller_unittest.cc index 0f0a2b9..92a94a9 100644 --- a/chrome/browser/sync/glue/device_info_data_type_controller_unittest.cc +++ b/chrome/browser/sync/glue/device_info_data_type_controller_unittest.cc @@ -38,7 +38,8 @@ class DeviceInfoDataTypeControllerTest : public testing::Test { controller_ = new DeviceInfoDataTypeController( &profile_sync_factory_, - local_device_.get()); + local_device_.get(), + DataTypeController::DisableTypeCallback()); load_finished_ = false; last_type_ = syncer::UNSPECIFIED; diff --git a/chrome/browser/sync/glue/extension_backed_data_type_controller.cc b/chrome/browser/sync/glue/extension_backed_data_type_controller.cc index 7de4d7e..b06f6df 100644 --- a/chrome/browser/sync/glue/extension_backed_data_type_controller.cc +++ b/chrome/browser/sync/glue/extension_backed_data_type_controller.cc @@ -30,6 +30,7 @@ std::string IdToHash(const std::string extension_id) { } // namespace ExtensionBackedDataTypeController::ExtensionBackedDataTypeController( + const DisableTypeCallback& disable_callback, syncer::ModelType type, const std::string& extension_hash, sync_driver::SyncApiComponentFactory* sync_factory, @@ -37,6 +38,7 @@ ExtensionBackedDataTypeController::ExtensionBackedDataTypeController( : UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, type, sync_factory), extension_hash_(extension_hash), @@ -73,16 +75,20 @@ void ExtensionBackedDataTypeController::OnExtensionUnloaded( const extensions::Extension* extension, extensions::UnloadedExtensionInfo::Reason reason) { if (DoesExtensionMatch(*extension)) { + ProfileSyncService* sync_service = + ProfileSyncServiceFactory::GetForProfile(profile_); + // This will trigger purging the datatype from the sync directory. This // may not always be the right choice, especially in the face of transient // unloads (e.g. for permission changes). If that becomes a large enough // issue, we should consider using the extension unload reason to just // trigger a reconfiguration without disabling (type will be unready). - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_POLICY_ERROR, - "Extension unloaded", - type()); - OnSingleDataTypeUnrecoverableError(error); + syncer::SyncError error( + FROM_HERE, + syncer::SyncError::DATATYPE_ERROR, + "Extension unloaded", + type()); + sync_service->DisableDatatype(error); } } diff --git a/chrome/browser/sync/glue/extension_backed_data_type_controller.h b/chrome/browser/sync/glue/extension_backed_data_type_controller.h index d5c6df8..9d438d2 100644 --- a/chrome/browser/sync/glue/extension_backed_data_type_controller.h +++ b/chrome/browser/sync/glue/extension_backed_data_type_controller.h @@ -22,6 +22,7 @@ class ExtensionBackedDataTypeController public extensions::ExtensionRegistryObserver { public: ExtensionBackedDataTypeController( + const DisableTypeCallback& disable_callback, syncer::ModelType type, const std::string& extension_hash, sync_driver::SyncApiComponentFactory* sync_factory, diff --git a/chrome/browser/sync/glue/extension_data_type_controller.cc b/chrome/browser/sync/glue/extension_data_type_controller.cc index cdeead6..7f3e258 100644 --- a/chrome/browser/sync/glue/extension_data_type_controller.cc +++ b/chrome/browser/sync/glue/extension_data_type_controller.cc @@ -17,10 +17,12 @@ namespace browser_sync { ExtensionDataTypeController::ExtensionDataTypeController( syncer::ModelType type, sync_driver::SyncApiComponentFactory* sync_factory, - Profile* profile) + Profile* profile, + const DisableTypeCallback& disable_callback) : UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, type, sync_factory), profile_(profile) { diff --git a/chrome/browser/sync/glue/extension_data_type_controller.h b/chrome/browser/sync/glue/extension_data_type_controller.h index 0904d35..4cb1113 100644 --- a/chrome/browser/sync/glue/extension_data_type_controller.h +++ b/chrome/browser/sync/glue/extension_data_type_controller.h @@ -22,7 +22,8 @@ class ExtensionDataTypeController : public sync_driver::UIDataTypeController { ExtensionDataTypeController( syncer::ModelType type, // Either EXTENSIONS or APPS. sync_driver::SyncApiComponentFactory* sync_factory, - Profile* profile); + Profile* profile, + const DisableTypeCallback& disable_callback); private: virtual ~ExtensionDataTypeController(); diff --git a/chrome/browser/sync/glue/extension_setting_data_type_controller.cc b/chrome/browser/sync/glue/extension_setting_data_type_controller.cc index 9e015d9..dc9e29e 100644 --- a/chrome/browser/sync/glue/extension_setting_data_type_controller.cc +++ b/chrome/browser/sync/glue/extension_setting_data_type_controller.cc @@ -22,10 +22,12 @@ namespace browser_sync { ExtensionSettingDataTypeController::ExtensionSettingDataTypeController( syncer::ModelType type, ProfileSyncComponentsFactory* profile_sync_factory, - Profile* profile) + Profile* profile, + const DisableTypeCallback& disable_callback) : NonUIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, profile_sync_factory), type_(type), profile_(profile) { diff --git a/chrome/browser/sync/glue/extension_setting_data_type_controller.h b/chrome/browser/sync/glue/extension_setting_data_type_controller.h index a7215b0..d53e9bf 100644 --- a/chrome/browser/sync/glue/extension_setting_data_type_controller.h +++ b/chrome/browser/sync/glue/extension_setting_data_type_controller.h @@ -30,7 +30,8 @@ class ExtensionSettingDataTypeController // Either EXTENSION_SETTINGS or APP_SETTINGS. syncer::ModelType type, ProfileSyncComponentsFactory* profile_sync_factory, - Profile* profile); + Profile* profile, + const DisableTypeCallback& disable_callback); // NonFrontendDataTypeController implementation virtual syncer::ModelType type() const OVERRIDE; diff --git a/chrome/browser/sync/glue/frontend_data_type_controller.cc b/chrome/browser/sync/glue/frontend_data_type_controller.cc index eaa6ea5..38435a8 100644 --- a/chrome/browser/sync/glue/frontend_data_type_controller.cc +++ b/chrome/browser/sync/glue/frontend_data_type_controller.cc @@ -30,7 +30,7 @@ FrontendDataTypeController::FrontendDataTypeController( ProfileSyncComponentsFactory* profile_sync_factory, Profile* profile, ProfileSyncService* sync_service) - : DataTypeController(ui_thread, error_callback), + : DataTypeController(ui_thread, error_callback, DisableTypeCallback()), profile_sync_factory_(profile_sync_factory), profile_(profile), sync_service_(sync_service), @@ -85,6 +85,7 @@ void FrontendDataTypeController::StartAssociating( const StartCallback& start_callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(!start_callback.is_null()); + DCHECK(start_callback_.is_null()); DCHECK_EQ(state_, MODEL_LOADED); start_callback_ = start_callback; @@ -101,9 +102,6 @@ void FrontendDataTypeController::StartAssociating( void FrontendDataTypeController::Stop() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (state_ == NOT_RUNNING) - return; - State prev_state = state_; state_ = STOPPING; @@ -115,6 +113,7 @@ void FrontendDataTypeController::Stop() { // still in MODEL_STARTING. return; } + DCHECK(start_callback_.is_null()); CleanUpState(); @@ -146,21 +145,17 @@ sync_driver::DataTypeController::State FrontendDataTypeController::state() return state_; } -void FrontendDataTypeController::OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) { - DCHECK_EQ(type(), error.model_type()); - RecordUnrecoverableError(error.location(), error.message()); - if (!start_callback_.is_null()) { - syncer::SyncMergeResult local_merge_result(type()); - local_merge_result.set_error(error); - start_callback_.Run(RUNTIME_ERROR, - local_merge_result, - syncer::SyncMergeResult(type())); - } +void FrontendDataTypeController::OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, const std::string& message) { + RecordUnrecoverableError(from_here, message); + syncer::SyncError error( + from_here, syncer::SyncError::DATATYPE_ERROR, message, type()); + sync_service_->DisableDatatype(error); } FrontendDataTypeController::FrontendDataTypeController() - : DataTypeController(base::MessageLoopProxy::current(), base::Closure()), + : DataTypeController(base::MessageLoopProxy::current(), base::Closure(), + DisableTypeCallback()), profile_sync_factory_(NULL), profile_(NULL), sync_service_(NULL), @@ -284,7 +279,12 @@ void FrontendDataTypeController::StartDone( RecordStartFailure(start_result); } - start_callback_.Run(start_result, local_merge_result, syncer_merge_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_. + StartCallback callback = start_callback_; + start_callback_.Reset(); + callback.Run(start_result, local_merge_result, syncer_merge_result); } void FrontendDataTypeController::RecordAssociationTime(base::TimeDelta time) { diff --git a/chrome/browser/sync/glue/frontend_data_type_controller.h b/chrome/browser/sync/glue/frontend_data_type_controller.h index dcc24c2..ab85db4 100644 --- a/chrome/browser/sync/glue/frontend_data_type_controller.h +++ b/chrome/browser/sync/glue/frontend_data_type_controller.h @@ -62,8 +62,9 @@ class FrontendDataTypeController : public sync_driver::DataTypeController { virtual State state() const OVERRIDE; // DataTypeErrorHandler interface. - virtual void OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) OVERRIDE; + virtual void OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) OVERRIDE; protected: friend class FrontendDataTypeControllerMock; 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 6f0b9bd..88fd3fd 100644 --- a/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc +++ b/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc @@ -255,3 +255,21 @@ TEST_F(SyncFrontendDataTypeControllerTest, Stop) { frontend_dtc_->Stop(); EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); } + +TEST_F(SyncFrontendDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) { + SetStartExpectations(); + SetAssociateExpectations(); + SetActivateExpectations(DataTypeController::OK); + EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, "Test")); + EXPECT_CALL(service_, DisableDatatype(_)) + .WillOnce(InvokeWithoutArgs(frontend_dtc_.get(), + &FrontendDataTypeController::Stop)); + SetStopExpectations(); + EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); + Start(); + EXPECT_EQ(DataTypeController::RUNNING, frontend_dtc_->state()); + // This should cause frontend_dtc_->Stop() to be called. + frontend_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test"); + PumpLoop(); + EXPECT_EQ(DataTypeController::NOT_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 index ea9d144..5b83a8e 100644 --- a/chrome/browser/sync/glue/non_frontend_data_type_controller.cc +++ b/chrome/browser/sync/glue/non_frontend_data_type_controller.cc @@ -157,15 +157,16 @@ NonFrontendDataTypeController::AssociationResult::AssociationResult( NonFrontendDataTypeController::AssociationResult::~AssociationResult() {} // TODO(tim): Legacy controllers are being left behind in componentization -// effort for now, hence still having a dependency on ProfileSyncService. -// That dep can probably be removed without too much work. +// effort for now, hence passing null DisableTypeCallback and still having +// a dependency on ProfileSyncService. That dep can probably be removed +// without too much work. NonFrontendDataTypeController::NonFrontendDataTypeController( scoped_refptr<base::MessageLoopProxy> ui_thread, const base::Closure& error_callback, ProfileSyncComponentsFactory* profile_sync_factory, Profile* profile, ProfileSyncService* sync_service) - : DataTypeController(ui_thread, error_callback), + : DataTypeController(ui_thread, error_callback, DisableTypeCallback()), state_(NOT_RUNNING), profile_sync_factory_(profile_sync_factory), profile_(profile), @@ -252,9 +253,7 @@ void DestroyComponentsInBackend( void NonFrontendDataTypeController::Stop() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - if (state_ == NOT_RUNNING) - return; + DCHECK_NE(state_, NOT_RUNNING); // Deactivate the date type on the UI thread first to stop processing // sync server changes. This needs to happen before posting task to destroy @@ -298,19 +297,21 @@ sync_driver::DataTypeController::State NonFrontendDataTypeController::state() return state_; } -void NonFrontendDataTypeController::OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) { +void NonFrontendDataTypeController::OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) { DCHECK(IsOnBackendThread()); - DCHECK_EQ(type(), error.model_type()); - RecordUnrecoverableError(error.location(), error.message()); - BrowserThread::PostTask(BrowserThread::UI, error.location(), + RecordUnrecoverableError(from_here, message); + BrowserThread::PostTask(BrowserThread::UI, from_here, base::Bind(&NonFrontendDataTypeController::DisableImpl, this, - error)); + from_here, + message)); } NonFrontendDataTypeController::NonFrontendDataTypeController() - : DataTypeController(base::MessageLoopProxy::current(), base::Closure()), + : DataTypeController(base::MessageLoopProxy::current(), base::Closure(), + DisableTypeCallback()), state_(NOT_RUNNING), profile_sync_factory_(NULL), profile_(NULL), @@ -370,19 +371,22 @@ void NonFrontendDataTypeController::StartDoneImpl( RecordStartFailure(start_result); } - start_callback_.Run(start_result, local_merge_result, syncer_merge_result); + DCHECK(!start_callback_.is_null()); + // 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_. + StartCallback callback = start_callback_; + start_callback_.Reset(); + callback.Run(start_result, local_merge_result, syncer_merge_result); } void NonFrontendDataTypeController::DisableImpl( - const syncer::SyncError& error) { + const tracked_objects::Location& from_here, + const std::string& message) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (!start_callback_.is_null()) { - syncer::SyncMergeResult local_merge_result(type()); - local_merge_result.set_error(error); - start_callback_.Run(RUNTIME_ERROR, - local_merge_result, - syncer::SyncMergeResult(type())); - } + syncer::SyncError error( + from_here, syncer::SyncError::DATATYPE_ERROR, message, type()); + profile_sync_service_->DisableDatatype(error); } void NonFrontendDataTypeController::RecordAssociationTime( diff --git a/chrome/browser/sync/glue/non_frontend_data_type_controller.h b/chrome/browser/sync/glue/non_frontend_data_type_controller.h index e2e5043..41f3fcf 100644 --- a/chrome/browser/sync/glue/non_frontend_data_type_controller.h +++ b/chrome/browser/sync/glue/non_frontend_data_type_controller.h @@ -68,8 +68,9 @@ class NonFrontendDataTypeController : public sync_driver::DataTypeController { // DataTypeErrorHandler interface. // Note: this is performed on the datatype's thread. - virtual void OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) OVERRIDE; + virtual void OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) OVERRIDE; // Callback to receive background association results. struct AssociationResult { @@ -146,7 +147,8 @@ class NonFrontendDataTypeController : public sync_driver::DataTypeController { // The actual implementation of Disabling the datatype. This happens // on the UI thread. - virtual void DisableImpl(const syncer::SyncError& error); + virtual void DisableImpl(const tracked_objects::Location& from_here, + const std::string& message); // Record association time. Called on Datatype's thread. virtual void RecordAssociationTime(base::TimeDelta time); 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 index 605313b..a383e14 100644 --- a/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc +++ b/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc @@ -373,7 +373,7 @@ TEST_F(SyncNonFrontendDataTypeControllerTest, Stop) { // Disabled due to http://crbug.com/388367 TEST_F(SyncNonFrontendDataTypeControllerTest, - DISABLED_OnSingleDataTypeUnrecoverableError) { + DISABLED_OnSingleDatatypeUnrecoverableError) { SetStartExpectations(); SetAssociateExpectations(); SetActivateExpectations(DataTypeController::OK); @@ -387,14 +387,11 @@ TEST_F(SyncNonFrontendDataTypeControllerTest, WaitForDTC(); EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state()); // This should cause non_frontend_dtc_->Stop() to be called. - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "error", - non_frontend_dtc_->type()); BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind( - &NonFrontendDataTypeControllerFake::OnSingleDataTypeUnrecoverableError, + &NonFrontendDataTypeControllerFake::OnSingleDatatypeUnrecoverableError, non_frontend_dtc_.get(), - error)); + 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 3681b04..2ff1b37 100644 --- a/chrome/browser/sync/glue/password_data_type_controller.cc +++ b/chrome/browser/sync/glue/password_data_type_controller.cc @@ -19,10 +19,12 @@ namespace browser_sync { PasswordDataTypeController::PasswordDataTypeController( ProfileSyncComponentsFactory* profile_sync_factory, - Profile* profile) + Profile* profile, + const DisableTypeCallback& disable_callback) : NonUIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, profile_sync_factory), profile_(profile) { } diff --git a/chrome/browser/sync/glue/password_data_type_controller.h b/chrome/browser/sync/glue/password_data_type_controller.h index e701a89..7394f0b 100644 --- a/chrome/browser/sync/glue/password_data_type_controller.h +++ b/chrome/browser/sync/glue/password_data_type_controller.h @@ -24,7 +24,8 @@ class PasswordDataTypeController : public sync_driver::NonUIDataTypeController { public: PasswordDataTypeController( ProfileSyncComponentsFactory* profile_sync_factory, - Profile* profile); + Profile* profile, + const DisableTypeCallback& disable_callback); // NonFrontendDataTypeController implementation virtual syncer::ModelType type() const OVERRIDE; diff --git a/chrome/browser/sync/glue/search_engine_data_type_controller.cc b/chrome/browser/sync/glue/search_engine_data_type_controller.cc index 5ac663a..7a596aa 100644 --- a/chrome/browser/sync/glue/search_engine_data_type_controller.cc +++ b/chrome/browser/sync/glue/search_engine_data_type_controller.cc @@ -18,10 +18,12 @@ namespace browser_sync { SearchEngineDataTypeController::SearchEngineDataTypeController( sync_driver::SyncApiComponentFactory* sync_factory, - Profile* profile) + Profile* profile, + const DisableTypeCallback& disable_callback) : UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, syncer::SEARCH_ENGINES, sync_factory), profile_(profile) { diff --git a/chrome/browser/sync/glue/search_engine_data_type_controller.h b/chrome/browser/sync/glue/search_engine_data_type_controller.h index f40a6fa..b55dafc 100644 --- a/chrome/browser/sync/glue/search_engine_data_type_controller.h +++ b/chrome/browser/sync/glue/search_engine_data_type_controller.h @@ -24,7 +24,8 @@ class SearchEngineDataTypeController public: SearchEngineDataTypeController( sync_driver::SyncApiComponentFactory* profile_sync_factory, - Profile* profile); + Profile* profile, + const DisableTypeCallback& disable_callback); TemplateURLService::Subscription* GetSubscriptionForTesting(); diff --git a/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc b/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc index 470c11a..e8952c5 100644 --- a/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc +++ b/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc @@ -39,7 +39,8 @@ class SyncSearchEngineDataTypeControllerTest : public testing::Test { // Feed the DTC the profile so it is reused later. // This allows us to control the associated TemplateURLService. search_engine_dtc_ = new SearchEngineDataTypeController( - profile_sync_factory_.get(), &profile_); + profile_sync_factory_.get(), &profile_, + sync_driver::DataTypeController::DisableTypeCallback()); } virtual void TearDown() { diff --git a/chrome/browser/sync/glue/theme_data_type_controller.cc b/chrome/browser/sync/glue/theme_data_type_controller.cc index 6e9852e..162d9f6 100644 --- a/chrome/browser/sync/glue/theme_data_type_controller.cc +++ b/chrome/browser/sync/glue/theme_data_type_controller.cc @@ -15,10 +15,12 @@ namespace browser_sync { ThemeDataTypeController::ThemeDataTypeController( sync_driver::SyncApiComponentFactory* sync_factory, - Profile* profile) + Profile* profile, + const DisableTypeCallback& disable_callback) : UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, syncer::THEMES, sync_factory), profile_(profile) { diff --git a/chrome/browser/sync/glue/theme_data_type_controller.h b/chrome/browser/sync/glue/theme_data_type_controller.h index 47e24f8..086ef00 100644 --- a/chrome/browser/sync/glue/theme_data_type_controller.h +++ b/chrome/browser/sync/glue/theme_data_type_controller.h @@ -15,7 +15,8 @@ class ThemeDataTypeController : public sync_driver::UIDataTypeController { public: ThemeDataTypeController( sync_driver::SyncApiComponentFactory* sync_factory, - Profile* profile); + Profile* profile, + const DisableTypeCallback& disable_callback); private: virtual ~ThemeDataTypeController(); diff --git a/chrome/browser/sync/glue/typed_url_change_processor.cc b/chrome/browser/sync/glue/typed_url_change_processor.cc index ae25e4f..0ef8f7d 100644 --- a/chrome/browser/sync/glue/typed_url_change_processor.cc +++ b/chrome/browser/sync/glue/typed_url_change_processor.cc @@ -113,11 +113,9 @@ bool TypedUrlChangeProcessor::CreateOrUpdateSyncNode( syncer::ReadNode typed_url_root(trans); if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) != syncer::BaseNode::INIT_OK) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "No top level folder", - syncer::TYPED_URLS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "Server did not create the top-level typed_url node. We " + "might be running against an out-of-date server."); return false; } @@ -132,24 +130,47 @@ bool TypedUrlChangeProcessor::CreateOrUpdateSyncNode( if (result == syncer::BaseNode::INIT_OK) { model_associator_->WriteToSyncNode(url, visit_vector, &update_node); } else if (result == syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to decrypt.", - syncer::TYPED_URLS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); - return false; + // TODO(tim): Investigating bug 121587. + syncer::Cryptographer* crypto = trans->GetCryptographer(); + syncer::ModelTypeSet encrypted_types(trans->GetEncryptedTypes()); + const sync_pb::EntitySpecifics& specifics = + update_node.GetEntry()->GetSpecifics(); + CHECK(specifics.has_encrypted()); + const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted()); + const bool agreement = encrypted_types.Has(syncer::TYPED_URLS); + if (!agreement && !can_decrypt) { + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "Could not InitByIdLookup in CreateOrUpdateSyncNode, " + " Cryptographer thinks typed urls not encrypted, and CanDecrypt" + " failed."); + LOG(ERROR) << "Case 1."; + } else if (agreement && can_decrypt) { + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "Could not InitByIdLookup on CreateOrUpdateSyncNode, " + " Cryptographer thinks typed urls are encrypted, and CanDecrypt" + " succeeded (?!), but DecryptIfNecessary failed."); + LOG(ERROR) << "Case 2."; + } else if (agreement) { + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "Could not InitByIdLookup on CreateOrUpdateSyncNode, " + " Cryptographer thinks typed urls are encrypted, but CanDecrypt" + " failed."); + LOG(ERROR) << "Case 3."; + } else { + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "Could not InitByIdLookup on CreateOrUpdateSyncNode, " + " Cryptographer thinks typed urls not encrypted, but CanDecrypt" + " succeeded (super weird, btw)"); + LOG(ERROR) << "Case 4."; + } } else { syncer::WriteNode create_node(trans); syncer::WriteNode::InitUniqueByCreationResult result = create_node.InitUniqueByCreation(syncer::TYPED_URLS, typed_url_root, tag); if (result != syncer::WriteNode::INIT_SUCCESS) { - - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to create sync node", - syncer::TYPED_URLS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "Failed to create typed_url sync node."); return false; } @@ -173,11 +194,8 @@ void TypedUrlChangeProcessor::HandleURLsDeleted( if (details->all_history) { if (!model_associator_->DeleteAllNodes(&trans)) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to delete local nodes.", - syncer::TYPED_URLS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + std::string()); return; } } else { @@ -236,11 +254,8 @@ void TypedUrlChangeProcessor::ApplyChangesFromSyncModel( syncer::ReadNode typed_url_root(trans); if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) != syncer::BaseNode::INIT_OK) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to init type root.", - syncer::TYPED_URLS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "TypedUrl root node lookup failed."); return; } @@ -261,11 +276,8 @@ void TypedUrlChangeProcessor::ApplyChangesFromSyncModel( syncer::ReadNode sync_node(trans); if (sync_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) { - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "Failed to init sync node.", - syncer::TYPED_URLS); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + "TypedUrl node lookup failed."); return; } 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 caaa099..403d6b0 100644 --- a/chrome/browser/sync/glue/typed_url_data_type_controller.cc +++ b/chrome/browser/sync/glue/typed_url_data_type_controller.cc @@ -126,7 +126,7 @@ void TypedUrlDataTypeController::OnSavingBrowserHistoryDisabledChanged() { syncer::SyncError::DATATYPE_POLICY_ERROR, "History saving is now disabled by policy.", syncer::TYPED_URLS); - OnSingleDataTypeUnrecoverableError(error); + profile_sync_service()->DisableDatatype(error); } } } diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc index 5a74820..9778962 100644 --- a/chrome/browser/sync/profile_sync_components_factory_impl.cc +++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc @@ -179,6 +179,24 @@ void ProfileSyncComponentsFactoryImpl::RegisterDataTypes( #endif } +void ProfileSyncComponentsFactoryImpl::DisableBrokenType( + syncer::ModelType type, + const tracked_objects::Location& from_here, + const std::string& message) { + ProfileSyncService* p = ProfileSyncServiceFactory::GetForProfile(profile_); + syncer::SyncError error( + from_here, syncer::SyncError::DATATYPE_ERROR, message, type); + p->DisableDatatype(error); +} + +DataTypeController::DisableTypeCallback +ProfileSyncComponentsFactoryImpl::MakeDisableCallbackFor( + syncer::ModelType type) { + return base::Bind(&ProfileSyncComponentsFactoryImpl::DisableBrokenType, + weak_factory_.GetWeakPtr(), + type); +} + void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( syncer::ModelTypeSet disabled_types, syncer::ModelTypeSet enabled_types, @@ -187,14 +205,16 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( // disabled. if (!disabled_types.Has(syncer::AUTOFILL)) { pss->RegisterDataTypeController( - new AutofillDataTypeController(this, profile_)); + new AutofillDataTypeController( + this, profile_, MakeDisableCallbackFor(syncer::AUTOFILL))); } // Autofill profile sync is enabled by default. Register unless explicitly // disabled. if (!disabled_types.Has(syncer::AUTOFILL_PROFILE)) { pss->RegisterDataTypeController( - new AutofillProfileDataTypeController(this, profile_)); + new AutofillProfileDataTypeController( + this, profile_, MakeDisableCallbackFor(syncer::AUTOFILL_PROFILE))); } // Bookmark sync is enabled by default. Register unless explicitly @@ -219,20 +239,23 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( new UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + MakeDisableCallbackFor(syncer::HISTORY_DELETE_DIRECTIVES), syncer::HISTORY_DELETE_DIRECTIVES, this)); } // Session sync is enabled by default. Register unless explicitly disabled. if (!disabled_types.Has(syncer::PROXY_TABS)) { - pss->RegisterDataTypeController(new ProxyDataTypeController( - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), - syncer::PROXY_TABS)); + pss->RegisterDataTypeController(new ProxyDataTypeController( + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), + syncer::PROXY_TABS)); pss->RegisterDataTypeController( - new SessionDataTypeController(this, - profile_, - pss->GetSyncedWindowDelegatesGetter(), - pss->GetLocalDeviceInfoProvider())); + new SessionDataTypeController( + this, + profile_, + pss->GetSyncedWindowDelegatesGetter(), + pss->GetLocalDeviceInfoProvider(), + MakeDisableCallbackFor(syncer::SESSIONS))); } // Favicon sync is enabled by default. Register unless explicitly disabled. @@ -242,12 +265,14 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( new UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + MakeDisableCallbackFor(syncer::FAVICON_IMAGES), syncer::FAVICON_IMAGES, this)); pss->RegisterDataTypeController( new UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + MakeDisableCallbackFor(syncer::FAVICON_TRACKING), syncer::FAVICON_TRACKING, this)); } @@ -256,7 +281,8 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( // disabled. if (!disabled_types.Has(syncer::PASSWORDS)) { pss->RegisterDataTypeController( - new PasswordDataTypeController(this, profile_)); + new PasswordDataTypeController( + this, profile_, MakeDisableCallbackFor(syncer::PASSWORDS))); } // Article sync is disabled by default. Register only if explicitly enabled. @@ -265,6 +291,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( new UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + MakeDisableCallbackFor(syncer::ARTICLES), syncer::ARTICLES, this)); } @@ -272,16 +299,19 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( #if defined(ENABLE_MANAGED_USERS) pss->RegisterDataTypeController( new SupervisedUserSyncDataTypeController( + MakeDisableCallbackFor(syncer::SUPERVISED_USER_SETTINGS), syncer::SUPERVISED_USER_SETTINGS, this, profile_)); pss->RegisterDataTypeController( new SupervisedUserSyncDataTypeController( + MakeDisableCallbackFor(syncer::SUPERVISED_USERS), syncer::SUPERVISED_USERS, this, profile_)); pss->RegisterDataTypeController( new SupervisedUserSyncDataTypeController( + MakeDisableCallbackFor(syncer::SUPERVISED_USER_SHARED_SETTINGS), syncer::SUPERVISED_USER_SHARED_SETTINGS, this, profile_)); @@ -296,14 +326,17 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( // disabled. if (!disabled_types.Has(syncer::APPS)) { pss->RegisterDataTypeController( - new ExtensionDataTypeController(syncer::APPS, this, profile_)); + new ExtensionDataTypeController(syncer::APPS, this, profile_, + MakeDisableCallbackFor(syncer::APPS))); } // Extension sync is enabled by default. Register unless explicitly // disabled. if (!disabled_types.Has(syncer::EXTENSIONS)) { pss->RegisterDataTypeController( - new ExtensionDataTypeController(syncer::EXTENSIONS, this, profile_)); + new ExtensionDataTypeController( + syncer::EXTENSIONS, this, profile_, + MakeDisableCallbackFor(syncer::EXTENSIONS))); } // Preference sync is enabled by default. Register unless explicitly @@ -313,6 +346,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( new UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + MakeDisableCallbackFor(syncer::PREFERENCES), syncer::PREFERENCES, this)); } @@ -322,6 +356,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( new UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + MakeDisableCallbackFor(syncer::PRIORITY_PREFERENCES), syncer::PRIORITY_PREFERENCES, this)); } @@ -330,7 +365,8 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( // Theme sync is enabled by default. Register unless explicitly disabled. if (!disabled_types.Has(syncer::THEMES)) { pss->RegisterDataTypeController( - new ThemeDataTypeController(this, profile_)); + new ThemeDataTypeController(this, profile_, + MakeDisableCallbackFor(syncer::THEMES))); } #endif @@ -338,21 +374,26 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( // disabled. if (!disabled_types.Has(syncer::SEARCH_ENGINES)) { pss->RegisterDataTypeController( - new SearchEngineDataTypeController(this, profile_)); + new SearchEngineDataTypeController( + this, profile_, MakeDisableCallbackFor(syncer::SEARCH_ENGINES))); } // Extension setting sync is enabled by default. Register unless explicitly // disabled. if (!disabled_types.Has(syncer::EXTENSION_SETTINGS)) { - pss->RegisterDataTypeController(new ExtensionSettingDataTypeController( - syncer::EXTENSION_SETTINGS, this, profile_)); + pss->RegisterDataTypeController( + new ExtensionSettingDataTypeController( + syncer::EXTENSION_SETTINGS, this, profile_, + MakeDisableCallbackFor(syncer::EXTENSION_SETTINGS))); } // App setting sync is enabled by default. Register unless explicitly // disabled. if (!disabled_types.Has(syncer::APP_SETTINGS)) { - pss->RegisterDataTypeController(new ExtensionSettingDataTypeController( - syncer::APP_SETTINGS, this, profile_)); + pss->RegisterDataTypeController( + new ExtensionSettingDataTypeController( + syncer::APP_SETTINGS, this, profile_, + MakeDisableCallbackFor(syncer::APP_SETTINGS))); } #if defined(ENABLE_APP_LIST) @@ -361,6 +402,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( new UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + MakeDisableCallbackFor(syncer::APP_LIST), syncer::APP_LIST, this)); } @@ -371,6 +413,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( if (enabled_types.Has(syncer::SYNCED_NOTIFICATIONS)) { pss->RegisterDataTypeController( new ExtensionBackedDataTypeController( + MakeDisableCallbackFor(syncer::SYNCED_NOTIFICATIONS), syncer::SYNCED_NOTIFICATIONS, "", // TODO(dewittj): pass the extension hash here. this, @@ -378,6 +421,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( pss->RegisterDataTypeController( new ExtensionBackedDataTypeController( + MakeDisableCallbackFor(syncer::SYNCED_NOTIFICATION_APP_INFO), syncer::SYNCED_NOTIFICATION_APP_INFO, "", // TODO(dewittj): pass the extension hash here. this, @@ -392,6 +436,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( new UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + MakeDisableCallbackFor(syncer::DICTIONARY), syncer::DICTIONARY, this)); } diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index 4f5353e..79defa9 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -951,6 +951,24 @@ void ProfileSyncService::OnUnrecoverableErrorImpl( syncer::DISABLE_SYNC : syncer::STOP_SYNC)); } +// TODO(zea): Move this logic into the DataTypeController/DataTypeManager. +void ProfileSyncService::DisableDatatype(const syncer::SyncError& error) { + // First deactivate the type so that no further server changes are + // passed onto the change processor. + DeactivateDataType(error.model_type()); + + std::map<syncer::ModelType, syncer::SyncError> errors; + errors[error.model_type()] = error; + + // Update this before posting a task. So if a configure happens before + // the task that we are going to post, this type would still be disabled. + failed_data_types_handler_.UpdateFailedDataTypes(errors); + + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(&ProfileSyncService::ReconfigureDatatypeManager, + weak_factory_.GetWeakPtr())); +} + void ProfileSyncService::ReenableDatatype(syncer::ModelType type) { // Only reconfigure if the type actually had a data type or unready error. if (!failed_data_types_handler_.ResetDataTypeErrorFor(type) && @@ -1366,10 +1384,7 @@ void ProfileSyncService::OnEncryptedTypesChanged( syncer::SyncError::DATATYPE_POLICY_ERROR, "Delete directives not supported with encryption.", syncer::HISTORY_DELETE_DIRECTIVES); - FailedDataTypesHandler::TypeErrorMap error_map; - error_map[error.model_type()] = error; - failed_data_types_handler_.UpdateFailedDataTypes(error_map); - ReconfigureDatatypeManager(); + DisableDatatype(error); } } @@ -1777,9 +1792,7 @@ void ProfileSyncService::OnUserChoseDatatypes( syncer::SyncError::DATATYPE_POLICY_ERROR, "Delete directives not supported with encryption.", syncer::HISTORY_DELETE_DIRECTIVES); - FailedDataTypesHandler::TypeErrorMap error_map; - error_map[error.model_type()] = error; - failed_data_types_handler_.UpdateFailedDataTypes(error_map); + DisableDatatype(error); } ChangePreferredDataTypes(chosen_types); AcknowledgeSyncedTypes(); diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index 98d3254..455075d 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h @@ -558,6 +558,11 @@ class ProfileSyncService : public ProfileSyncServiceBase, const tracked_objects::Location& from_here, const std::string& message) OVERRIDE; + // Called when a datatype wishes to disable itself. The datatype to be + // disabled is passed via |error.model_type()|. Note, this does not change + // preferred state of a datatype and is not persisted across restarts. + virtual void DisableDatatype(const syncer::SyncError& error); + // Called to re-enable a type disabled by DisableDatatype(..). Note, this does // not change the preferred state of a datatype, and is not persisted across // restarts. diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc index 8c7cddf..fd9d5ec 100644 --- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc @@ -392,7 +392,10 @@ class AutofillEntryFactory : public AbstractAutofillFactory { ProfileSyncComponentsFactory* factory, TestingProfile* profile, ProfileSyncService* service) OVERRIDE { - return new AutofillDataTypeController(factory, profile); + return new AutofillDataTypeController( + factory, + profile, + DataTypeController::DisableTypeCallback()); } virtual void SetExpectation(ProfileSyncComponentsFactoryMock* factory, @@ -410,7 +413,10 @@ class AutofillProfileFactory : public AbstractAutofillFactory { ProfileSyncComponentsFactory* factory, TestingProfile* profile, ProfileSyncService* service) OVERRIDE { - return new AutofillProfileDataTypeController(factory, profile); + return new AutofillProfileDataTypeController( + factory, + profile, + DataTypeController::DisableTypeCallback()); } virtual void SetExpectation(ProfileSyncComponentsFactoryMock* factory, diff --git a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc index f276ac8..f0adb7c 100644 --- a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc @@ -1163,7 +1163,7 @@ TEST_F(ProfileSyncServiceBookmarkTest, RepeatedMiddleInsertion) { // puts itself into a lame, error state. TEST_F(ProfileSyncServiceBookmarkTest, UnrecoverableErrorSuspendsService) { EXPECT_CALL(mock_error_handler_, - OnSingleDataTypeUnrecoverableError(_)); + OnSingleDatatypeUnrecoverableError(_, _)); LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); StartSync(); diff --git a/chrome/browser/sync/sessions/session_data_type_controller.cc b/chrome/browser/sync/sessions/session_data_type_controller.cc index 24930ad..466ece1 100644 --- a/chrome/browser/sync/sessions/session_data_type_controller.cc +++ b/chrome/browser/sync/sessions/session_data_type_controller.cc @@ -22,10 +22,12 @@ SessionDataTypeController::SessionDataTypeController( sync_driver::SyncApiComponentFactory* sync_factory, Profile* profile, SyncedWindowDelegatesGetter* synced_window_getter, - LocalDeviceInfoProvider* local_device) + LocalDeviceInfoProvider* local_device, + const DisableTypeCallback& disable_callback) : UIDataTypeController( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), base::Bind(&ChromeReportUnrecoverableError), + disable_callback, syncer::SESSIONS, sync_factory), profile_(profile), diff --git a/chrome/browser/sync/sessions/session_data_type_controller.h b/chrome/browser/sync/sessions/session_data_type_controller.h index 3ba97f4..851fa28 100644 --- a/chrome/browser/sync/sessions/session_data_type_controller.h +++ b/chrome/browser/sync/sessions/session_data_type_controller.h @@ -25,7 +25,8 @@ class SessionDataTypeController : public sync_driver::UIDataTypeController, SessionDataTypeController(sync_driver::SyncApiComponentFactory* factory, Profile* profile, SyncedWindowDelegatesGetter* synced_window_getter, - LocalDeviceInfoProvider* local_device); + LocalDeviceInfoProvider* local_device, + const DisableTypeCallback& disable_callback); // NotificationObserver interface. virtual void Observe(int type, diff --git a/chrome/browser/sync/sessions/session_data_type_controller_unittest.cc b/chrome/browser/sync/sessions/session_data_type_controller_unittest.cc index 5044803..4b86bab 100644 --- a/chrome/browser/sync/sessions/session_data_type_controller_unittest.cc +++ b/chrome/browser/sync/sessions/session_data_type_controller_unittest.cc @@ -103,7 +103,8 @@ class SessionDataTypeControllerTest &profile_sync_factory_, &profile_, synced_window_getter_.get(), - local_device_.get()); + local_device_.get(), + sync_driver::DataTypeController::DisableTypeCallback()); load_finished_ = false; last_type_ = syncer::UNSPECIFIED; diff --git a/components/sync_driver/change_processor_mock.h b/components/sync_driver/change_processor_mock.h index 7acf83f..aaa7e82d 100644 --- a/components/sync_driver/change_processor_mock.h +++ b/components/sync_driver/change_processor_mock.h @@ -25,8 +25,9 @@ class ChangeProcessorMock MOCK_CONST_METHOD0(IsRunning, bool()); MOCK_METHOD2(OnUnrecoverableError, void(const tracked_objects::Location&, const std::string&)); - MOCK_METHOD1(OnSingleDataTypeUnrecoverableError, - void(const syncer::SyncError&)); + MOCK_METHOD2(OnSingleDatatypeUnrecoverableError, + void(const tracked_objects::Location&, + const std::string&)); MOCK_METHOD3(CreateAndUploadError, syncer::SyncError(const tracked_objects::Location&, const std::string&, diff --git a/components/sync_driver/data_type_controller.cc b/components/sync_driver/data_type_controller.cc index db26151..3f7a681 100644 --- a/components/sync_driver/data_type_controller.cc +++ b/components/sync_driver/data_type_controller.cc @@ -12,9 +12,11 @@ namespace sync_driver { DataTypeController::DataTypeController( scoped_refptr<base::MessageLoopProxy> ui_thread, - const base::Closure& error_callback) + const base::Closure& error_callback, + const DisableTypeCallback& disable_callback) : base::RefCountedDeleteOnMessageLoop<DataTypeController>(ui_thread), error_callback_(error_callback), + disable_callback_(disable_callback), user_share_(NULL) { } @@ -49,6 +51,11 @@ syncer::UserShare* DataTypeController::user_share() const { return user_share_; } +DataTypeController::DisableTypeCallback +DataTypeController::disable_callback() { + return disable_callback_; +} + bool DataTypeController::ReadyForStart() const { return true; } diff --git a/components/sync_driver/data_type_controller.h b/components/sync_driver/data_type_controller.h index a673b1f..7d8b67c 100644 --- a/components/sync_driver/data_type_controller.h +++ b/components/sync_driver/data_type_controller.h @@ -149,7 +149,8 @@ class DataTypeController friend class base::DeleteHelper<DataTypeController>; DataTypeController(scoped_refptr<base::MessageLoopProxy> ui_thread, - const base::Closure& error_callback); + const base::Closure& error_callback, + const DisableTypeCallback& disable_callback); // If the DTC is waiting for models to load, once the models are // loaded the datatype service will call this function on DTC to let @@ -159,12 +160,16 @@ class DataTypeController virtual ~DataTypeController(); syncer::UserShare* user_share() const; + DisableTypeCallback disable_callback(); // The callback that will be invoked when an unrecoverable error occurs. // TODO(sync): protected for use by legacy controllers. base::Closure error_callback_; private: + // TODO(tim): Bug 383480. Do we need two callbacks? + DisableTypeCallback disable_callback_; + syncer::UserShare* user_share_; }; diff --git a/components/sync_driver/data_type_error_handler.h b/components/sync_driver/data_type_error_handler.h index 174b9a8..a33a151 100644 --- a/components/sync_driver/data_type_error_handler.h +++ b/components/sync_driver/data_type_error_handler.h @@ -18,8 +18,9 @@ class DataTypeErrorHandler { public: // Call this to disable a datatype while it is running. This is usually // called for a runtime failure that is specific to a datatype. - virtual void OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) = 0; + virtual void OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) = 0; // This will create a syncer::SyncError object. This will also upload // a breakpad call stack to crash server. A sync error usually means diff --git a/components/sync_driver/data_type_error_handler_mock.h b/components/sync_driver/data_type_error_handler_mock.h index a5cd6d4..6e70e2b 100644 --- a/components/sync_driver/data_type_error_handler_mock.h +++ b/components/sync_driver/data_type_error_handler_mock.h @@ -14,8 +14,8 @@ class DataTypeErrorHandlerMock : public DataTypeErrorHandler { public: DataTypeErrorHandlerMock(); virtual ~DataTypeErrorHandlerMock(); - MOCK_METHOD1(OnSingleDataTypeUnrecoverableError, - void(const syncer::SyncError&)); + MOCK_METHOD2(OnSingleDatatypeUnrecoverableError, + void(const tracked_objects::Location&, const std::string&)); MOCK_METHOD3(CreateAndUploadError, syncer::SyncError(const tracked_objects::Location&, const std::string&, diff --git a/components/sync_driver/fake_data_type_controller.cc b/components/sync_driver/fake_data_type_controller.cc index 897e77a..5ba1c4c 100644 --- a/components/sync_driver/fake_data_type_controller.cc +++ b/components/sync_driver/fake_data_type_controller.cc @@ -12,7 +12,8 @@ using syncer::ModelType; namespace sync_driver { FakeDataTypeController::FakeDataTypeController(ModelType type) - : DataTypeController(base::MessageLoopProxy::current(), base::Closure()), + : DataTypeController(base::MessageLoopProxy::current(), base::Closure(), + DisableTypeCallback()), state_(NOT_RUNNING), model_load_delayed_(false), type_(type), @@ -136,8 +137,11 @@ DataTypeController::State FakeDataTypeController::state() const { return state_; } -void FakeDataTypeController::OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) { +void FakeDataTypeController::OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) { + syncer::SyncError error( + from_here, syncer::SyncError::DATATYPE_ERROR, message, type_); syncer::SyncMergeResult local_merge_result(type()); local_merge_result.set_error(error); last_start_callback_.Run( diff --git a/components/sync_driver/fake_data_type_controller.h b/components/sync_driver/fake_data_type_controller.h index a84bc27..840a5b2 100644 --- a/components/sync_driver/fake_data_type_controller.h +++ b/components/sync_driver/fake_data_type_controller.h @@ -33,8 +33,9 @@ class FakeDataTypeController : public DataTypeController { virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE; virtual ChangeProcessor* GetChangeProcessor() const OVERRIDE; virtual State state() const OVERRIDE; - virtual void OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) OVERRIDE; + virtual void OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) OVERRIDE; virtual bool ReadyForStart() const OVERRIDE; void FinishStart(ConfigureResult result); diff --git a/components/sync_driver/generic_change_processor.cc b/components/sync_driver/generic_change_processor.cc index c44ce72..d7a5c6e 100644 --- a/components/sync_driver/generic_change_processor.cc +++ b/components/sync_driver/generic_change_processor.cc @@ -144,13 +144,10 @@ void GenericChangeProcessor::ApplyChangesFromSyncModel( // Need to load specifics from node. syncer::ReadNode read_node(trans); if (read_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) { - syncer::SyncError error( + error_handler()->OnSingleDatatypeUnrecoverableError( FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, "Failed to look up data for received change with id " + - base::Int64ToString(it->id), - syncer::GetModelTypeFromSpecifics(it->specifics)); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + base::Int64ToString(it->id)); return; } syncer_changes_.push_back(syncer::SyncChange( @@ -171,14 +168,17 @@ void GenericChangeProcessor::CommitChangesFromSyncModel() { syncer::SyncError::DATATYPE_ERROR, "Local service destroyed.", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(error.location(), + error.message()); return; } syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE, syncer_changes_); syncer_changes_.clear(); - if (error.IsSet()) - error_handler()->OnSingleDataTypeUnrecoverableError(error); + if (error.IsSet()) { + error_handler()->OnSingleDatatypeUnrecoverableError( + error.location(), error.message()); + } } syncer::SyncDataList GenericChangeProcessor::GetAllSyncData( @@ -285,8 +285,9 @@ int GenericChangeProcessor::GetSyncCountForType(syncer::ModelType type) { namespace { +// TODO(isherman): Investigating http://crbug.com/121592 // WARNING: this code is sensitive to compiler optimizations. Be careful -// modifying any code around an OnSingleDataTypeUnrecoverableError call, else +// modifying any code around an OnSingleDatatypeUnrecoverableError call, else // the compiler attempts to merge it with other calls, losing useful information // in breakpad uploads. syncer::SyncError LogLookupFailure( @@ -302,21 +303,24 @@ syncer::SyncError LogLookupFailure( error_prefix + "could not find entry matching the lookup criteria.", type); - error_handler->OnSingleDataTypeUnrecoverableError(error); + error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Delete: Bad entry."; return error; } case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: { syncer::SyncError error; error.Reset(from_here, error_prefix + "entry is already deleted.", type); - error_handler->OnSingleDataTypeUnrecoverableError(error); + error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Delete: Deleted entry."; return error; } case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: { syncer::SyncError error; error.Reset(from_here, error_prefix + "unable to decrypt", type); - error_handler->OnSingleDataTypeUnrecoverableError(error); + error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Delete: Undecryptable entry."; return error; } @@ -325,7 +329,8 @@ syncer::SyncError LogLookupFailure( error.Reset(from_here, error_prefix + "a precondition was not met for calling init.", type); - error_handler->OnSingleDataTypeUnrecoverableError(error); + error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Delete: Failed precondition."; return error; } @@ -333,7 +338,8 @@ syncer::SyncError LogLookupFailure( syncer::SyncError error; // Should have listed all the possible error cases above. error.Reset(from_here, error_prefix + "unknown error", type); - error_handler->OnSingleDataTypeUnrecoverableError(error); + error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Delete: Unknown error."; return error; } @@ -355,7 +361,8 @@ syncer::SyncError AttemptDelete(const syncer::SyncChange& change, "Failed to delete " + type_str + " node. Local data, empty tag. " + change.location().ToString(), type); - error_handler->OnSingleDataTypeUnrecoverableError(error); + error_handler->OnSingleDatatypeUnrecoverableError(error.location(), + error.message()); NOTREACHED(); return error; } @@ -457,7 +464,8 @@ syncer::SyncError GenericChangeProcessor::ProcessSyncChanges( "Received unset SyncChange in the change processor, " + change.location().ToString(), type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); NOTREACHED(); LOG(ERROR) << "Unset sync change."; return error; @@ -472,7 +480,7 @@ syncer::SyncError GenericChangeProcessor::ProcessSyncChanges( } // WARNING: this code is sensitive to compiler optimizations. Be careful -// modifying any code around an OnSingleDataTypeUnrecoverableError call, else +// modifying any code around an OnSingleDatatypeUnrecoverableError call, else // the compiler attempts to merge it with other calls, losing useful information // in breakpad uploads. syncer::SyncError GenericChangeProcessor::HandleActionAdd( @@ -492,7 +500,8 @@ syncer::SyncError GenericChangeProcessor::HandleActionAdd( syncer::SyncError::DATATYPE_ERROR, "Failed to look up root node for type " + type_str, type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); NOTREACHED(); LOG(ERROR) << "Create: no root node."; return error; @@ -507,21 +516,24 @@ syncer::SyncError GenericChangeProcessor::HandleActionAdd( case syncer::WriteNode::INIT_FAILED_EMPTY_TAG: { syncer::SyncError error; error.Reset(FROM_HERE, error_prefix + "empty tag", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Create: Empty tag."; return error; } case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS: { syncer::SyncError error; error.Reset(FROM_HERE, error_prefix + "entry already exists", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Create: Entry exists."; return error; } case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: { syncer::SyncError error; error.Reset(FROM_HERE, error_prefix + "failed to create entry", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Create: Could not create entry."; return error; } @@ -529,14 +541,16 @@ syncer::SyncError GenericChangeProcessor::HandleActionAdd( syncer::SyncError error; error.Reset( FROM_HERE, error_prefix + "failed to set predecessor", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Create: Bad predecessor."; return error; } default: { syncer::SyncError error; error.Reset(FROM_HERE, error_prefix + "unknown error", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Create: Unknown error."; return error; } @@ -561,7 +575,7 @@ syncer::SyncError GenericChangeProcessor::HandleActionAdd( return syncer::SyncError(); } // WARNING: this code is sensitive to compiler optimizations. Be careful -// modifying any code around an OnSingleDataTypeUnrecoverableError call, else +// modifying any code around an OnSingleDatatypeUnrecoverableError call, else // the compiler attempts to merge it with other calls, losing useful information // in breakpad uploads. syncer::SyncError GenericChangeProcessor::HandleActionUpdate( @@ -583,19 +597,22 @@ syncer::SyncError GenericChangeProcessor::HandleActionUpdate( if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) { syncer::SyncError error; error.Reset(FROM_HERE, error_prefix + "empty tag", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Update: Empty tag."; return error; } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) { syncer::SyncError error; error.Reset(FROM_HERE, error_prefix + "bad entry", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Update: bad entry."; return error; } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) { syncer::SyncError error; error.Reset(FROM_HERE, error_prefix + "deleted entry", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Update: deleted entry."; return error; } else { @@ -613,7 +630,8 @@ syncer::SyncError GenericChangeProcessor::HandleActionUpdate( "nigori mismatch for " + type_str + ".", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Update: encr case 1."; return error; } else if (agreement && can_decrypt) { @@ -623,7 +641,8 @@ syncer::SyncError GenericChangeProcessor::HandleActionUpdate( "and the nigori matches (?!) for " + type_str + ".", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Update: encr case 2."; return error; } else if (agreement) { @@ -633,7 +652,8 @@ syncer::SyncError GenericChangeProcessor::HandleActionUpdate( "the nigori matches for " + type_str + ".", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Update: encr case 3."; return error; } else { @@ -643,7 +663,8 @@ syncer::SyncError GenericChangeProcessor::HandleActionUpdate( "(?!) and nigori mismatch for " + type_str + ".", type); - error_handler()->OnSingleDataTypeUnrecoverableError(error); + error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, + error.message()); LOG(ERROR) << "Update: encr case 4."; return error; } diff --git a/components/sync_driver/model_association_manager_unittest.cc b/components/sync_driver/model_association_manager_unittest.cc index 5c26319..906d99b 100644 --- a/components/sync_driver/model_association_manager_unittest.cc +++ b/components/sync_driver/model_association_manager_unittest.cc @@ -339,12 +339,8 @@ TEST_F(SyncModelAssociationManagerTest, StopAfterConfiguration) { testing::Mock::VerifyAndClearExpectations(&delegate_); EXPECT_CALL(delegate_, OnSingleDataTypeWillStop(syncer::BOOKMARKS, _)); - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "error", - syncer::BOOKMARKS); GetController(controllers_, syncer::BOOKMARKS) - ->OnSingleDataTypeUnrecoverableError(error); + ->OnSingleDatatypeUnrecoverableError(FROM_HERE, "runtime error"); } } // namespace sync_driver diff --git a/components/sync_driver/non_ui_data_type_controller.cc b/components/sync_driver/non_ui_data_type_controller.cc index 67edb40..211f142 100644 --- a/components/sync_driver/non_ui_data_type_controller.cc +++ b/components/sync_driver/non_ui_data_type_controller.cc @@ -24,8 +24,9 @@ NonUIDataTypeController::CreateSharedChangeProcessor() { NonUIDataTypeController::NonUIDataTypeController( scoped_refptr<base::MessageLoopProxy> ui_thread, const base::Closure& error_callback, + const DisableTypeCallback& disable_callback, SyncApiComponentFactory* sync_factory) - : DataTypeController(ui_thread, error_callback), + : DataTypeController(ui_thread, error_callback, disable_callback), sync_factory_(sync_factory), state_(NOT_RUNNING), ui_thread_(ui_thread) { @@ -110,7 +111,6 @@ void NonUIDataTypeController::StartAssociating( void NonUIDataTypeController::Stop() { DCHECK(ui_thread_->BelongsToCurrentThread()); - if (state() == NOT_RUNNING) return; @@ -166,20 +166,22 @@ DataTypeController::State NonUIDataTypeController::state() const { return state_; } -void NonUIDataTypeController::OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) { +void NonUIDataTypeController::OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, const std::string& message) { DCHECK(!ui_thread_->BelongsToCurrentThread()); // TODO(tim): We double-upload some errors. See bug 383480. if (!error_callback_.is_null()) error_callback_.Run(); - ui_thread_->PostTask(error.location(), + ui_thread_->PostTask(from_here, base::Bind(&NonUIDataTypeController::DisableImpl, this, - error)); + from_here, + message)); } NonUIDataTypeController::NonUIDataTypeController() - : DataTypeController(base::MessageLoopProxy::current(), base::Closure()), + : DataTypeController(base::MessageLoopProxy::current(), base::Closure(), + DisableTypeCallback()), sync_factory_(NULL) {} NonUIDataTypeController::~NonUIDataTypeController() {} @@ -270,12 +272,15 @@ void NonUIDataTypeController::AbortModelLoad() { } void NonUIDataTypeController::DisableImpl( - const syncer::SyncError& error) { + const tracked_objects::Location& from_here, + const std::string& message) { DCHECK(ui_thread_->BelongsToCurrentThread()); UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeRunFailures", ModelTypeToHistogramInt(type()), syncer::MODEL_TYPE_COUNT); if (!start_callback_.is_null()) { + syncer::SyncError error( + from_here, syncer::SyncError::DATATYPE_ERROR, message, type()); syncer::SyncMergeResult local_merge_result(type()); local_merge_result.set_error(error); start_callback_.Run(RUNTIME_ERROR, diff --git a/components/sync_driver/non_ui_data_type_controller.h b/components/sync_driver/non_ui_data_type_controller.h index 0f4fdab..17a0dbe 100644 --- a/components/sync_driver/non_ui_data_type_controller.h +++ b/components/sync_driver/non_ui_data_type_controller.h @@ -27,6 +27,7 @@ class NonUIDataTypeController : public DataTypeController { NonUIDataTypeController( scoped_refptr<base::MessageLoopProxy> ui_thread, const base::Closure& error_callback, + const DisableTypeCallback& disable_callback, SyncApiComponentFactory* sync_factory); // DataTypeController interface. @@ -39,8 +40,9 @@ class NonUIDataTypeController : public DataTypeController { virtual ChangeProcessor* GetChangeProcessor() const OVERRIDE; virtual std::string name() const OVERRIDE; virtual State state() const OVERRIDE; - virtual void OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) OVERRIDE; + virtual void OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) OVERRIDE; protected: // For testing only. @@ -123,7 +125,8 @@ class NonUIDataTypeController : public DataTypeController { // Disable this type with the sync service. Should only be invoked in case of // an unrecoverable error. // Note: this is performed on the UI thread. - void DisableImpl(const syncer::SyncError& error); + void DisableImpl(const tracked_objects::Location& from_here, + const std::string& message); SyncApiComponentFactory* const sync_factory_; diff --git a/components/sync_driver/non_ui_data_type_controller_mock.h b/components/sync_driver/non_ui_data_type_controller_mock.h index 3716a35..1369c33 100644 --- a/components/sync_driver/non_ui_data_type_controller_mock.h +++ b/components/sync_driver/non_ui_data_type_controller_mock.h @@ -26,8 +26,9 @@ class NonUIDataTypeControllerMock MOCK_CONST_METHOD0(name, std::string()); MOCK_CONST_METHOD0(model_safe_group, syncer::ModelSafeGroup()); MOCK_CONST_METHOD0(state, State()); - MOCK_METHOD1(OnSingleDataTypeUnrecoverableError, - void(const syncer::SyncError& error)); + MOCK_METHOD2(OnSingleDataTypeUnrecoverableError, + void(const tracked_objects::Location&, + const std::string&)); // NonUIDataTypeController mocks. MOCK_METHOD0(StartModels, bool()); diff --git a/components/sync_driver/non_ui_data_type_controller_unittest.cc b/components/sync_driver/non_ui_data_type_controller_unittest.cc index 875523d..021db41 100644 --- a/components/sync_driver/non_ui_data_type_controller_unittest.cc +++ b/components/sync_driver/non_ui_data_type_controller_unittest.cc @@ -96,10 +96,12 @@ class NonUIDataTypeControllerFake SyncApiComponentFactory* sync_factory, NonUIDataTypeControllerMock* mock, SharedChangeProcessor* change_processor, + const DisableTypeCallback& disable_callback, scoped_refptr<base::MessageLoopProxy> backend_loop) : NonUIDataTypeController( base::MessageLoopProxy::current(), base::Closure(), + disable_callback, sync_factory), blocked_(false), mock_(mock), @@ -186,17 +188,22 @@ class NonUIDataTypeControllerFake class SyncNonUIDataTypeControllerTest : public testing::Test { public: SyncNonUIDataTypeControllerTest() - : backend_thread_("dbthread") {} + : backend_thread_("dbthread"), + disable_callback_invoked_(false) {} virtual void SetUp() OVERRIDE { backend_thread_.Start(); change_processor_ = new SharedChangeProcessorMock(); // All of these are refcounted, so don't need to be released. dtc_mock_ = new StrictMock<NonUIDataTypeControllerMock>(); + DataTypeController::DisableTypeCallback disable_callback = + base::Bind(&SyncNonUIDataTypeControllerTest::DisableTypeCallback, + base::Unretained(this)); non_ui_dtc_ = new NonUIDataTypeControllerFake(NULL, dtc_mock_.get(), change_processor_, + disable_callback, backend_thread_.message_loop_proxy()); } @@ -264,6 +271,12 @@ class SyncNonUIDataTypeControllerTest : public testing::Test { done->Signal(); } + void DisableTypeCallback(const tracked_objects::Location& location, + const std::string& message) { + disable_callback_invoked_ = true; + non_ui_dtc_->Stop(); + } + base::MessageLoopForUI message_loop_; base::Thread backend_thread_; @@ -275,6 +288,8 @@ class SyncNonUIDataTypeControllerTest : public testing::Test { scoped_refptr<NonUIDataTypeControllerMock> dtc_mock_; scoped_refptr<SharedChangeProcessorMock> change_processor_; scoped_ptr<syncer::SyncChangeProcessor> saved_change_processor_; + + bool disable_callback_invoked_; }; TEST_F(SyncNonUIDataTypeControllerTest, StartOk) { @@ -481,7 +496,7 @@ TEST_F(SyncNonUIDataTypeControllerTest, StopStart) { EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state()); } -TEST_F(SyncNonUIDataTypeControllerTest, OnSingleDataTypeUnrecoverableError) { +TEST_F(SyncNonUIDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) { SetStartExpectations(); SetAssociateExpectations(); SetActivateExpectations(DataTypeController::OK); @@ -492,15 +507,12 @@ TEST_F(SyncNonUIDataTypeControllerTest, OnSingleDataTypeUnrecoverableError) { testing::Mock::VerifyAndClearExpectations(&start_callback_); EXPECT_CALL(start_callback_, Run(DataTypeController::RUNTIME_ERROR, _, _)); - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "error", - non_ui_dtc_->type()); backend_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( &NonUIDataTypeControllerFake:: - OnSingleDataTypeUnrecoverableError, + OnSingleDatatypeUnrecoverableError, non_ui_dtc_.get(), - error)); + FROM_HERE, + std::string("Test"))); WaitForDTC(); } diff --git a/components/sync_driver/proxy_data_type_controller.cc b/components/sync_driver/proxy_data_type_controller.cc index c017802..ae1ea53 100644 --- a/components/sync_driver/proxy_data_type_controller.cc +++ b/components/sync_driver/proxy_data_type_controller.cc @@ -9,7 +9,7 @@ namespace sync_driver { ProxyDataTypeController::ProxyDataTypeController( scoped_refptr<base::MessageLoopProxy> ui_thread, syncer::ModelType type) - : DataTypeController(ui_thread, base::Closure()), + : DataTypeController(ui_thread, base::Closure(), DisableTypeCallback()), state_(NOT_RUNNING), type_(type) { DCHECK(syncer::ProxyTypes().Has(type_)); @@ -61,8 +61,8 @@ DataTypeController::State ProxyDataTypeController::state() const { return state_; } -void ProxyDataTypeController::OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) { +void ProxyDataTypeController::OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, const std::string& message) { NOTIMPLEMENTED(); } diff --git a/components/sync_driver/proxy_data_type_controller.h b/components/sync_driver/proxy_data_type_controller.h index 6e255c6..e90ee24 100644 --- a/components/sync_driver/proxy_data_type_controller.h +++ b/components/sync_driver/proxy_data_type_controller.h @@ -32,8 +32,9 @@ class ProxyDataTypeController : public DataTypeController { virtual State state() const OVERRIDE; // DataTypeErrorHandler interface. - virtual void OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) OVERRIDE; + virtual void OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) OVERRIDE; protected: // DataTypeController is RefCounted. diff --git a/components/sync_driver/ui_data_type_controller.cc b/components/sync_driver/ui_data_type_controller.cc index eca5779..3b7945c 100644 --- a/components/sync_driver/ui_data_type_controller.cc +++ b/components/sync_driver/ui_data_type_controller.cc @@ -17,7 +17,8 @@ namespace sync_driver { UIDataTypeController::UIDataTypeController() : DataTypeController(base::MessageLoopProxy::current(), - base::Closure()), + base::Closure(), + DisableTypeCallback()), sync_factory_(NULL), state_(NOT_RUNNING), type_(syncer::UNSPECIFIED) { @@ -26,9 +27,10 @@ UIDataTypeController::UIDataTypeController() UIDataTypeController::UIDataTypeController( scoped_refptr<base::MessageLoopProxy> ui_thread, const base::Closure& error_callback, + const DisableTypeCallback& disable_callback, syncer::ModelType type, SyncApiComponentFactory* sync_factory) - : DataTypeController(ui_thread, error_callback), + : DataTypeController(ui_thread, error_callback, disable_callback), sync_factory_(sync_factory), state_(NOT_RUNNING), type_(type), @@ -267,9 +269,6 @@ void UIDataTypeController::Stop() { DCHECK(ui_thread_->BelongsToCurrentThread()); DCHECK(syncer::IsRealDataType(type_)); - if (state_ == NOT_RUNNING) - return; - State prev_state = state_; state_ = STOPPING; @@ -319,9 +318,8 @@ DataTypeController::State UIDataTypeController::state() const { return state_; } -void UIDataTypeController::OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) { - DCHECK_EQ(type(), error.model_type()); +void UIDataTypeController::OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, const std::string& message) { UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeRunFailures", ModelTypeToHistogramInt(type()), syncer::MODEL_TYPE_COUNT); @@ -329,6 +327,8 @@ void UIDataTypeController::OnSingleDataTypeUnrecoverableError( if (!error_callback_.is_null()) error_callback_.Run(); if (!start_callback_.is_null()) { + syncer::SyncError error( + from_here, syncer::SyncError::DATATYPE_ERROR, message, type()); syncer::SyncMergeResult local_merge_result(type()); local_merge_result.set_error(error); start_callback_.Run(RUNTIME_ERROR, diff --git a/components/sync_driver/ui_data_type_controller.h b/components/sync_driver/ui_data_type_controller.h index 3028991..ae7983e 100644 --- a/components/sync_driver/ui_data_type_controller.h +++ b/components/sync_driver/ui_data_type_controller.h @@ -34,6 +34,7 @@ class UIDataTypeController : public DataTypeController { UIDataTypeController( scoped_refptr<base::MessageLoopProxy> ui_thread, const base::Closure& error_callback, + const DisableTypeCallback& disable_callback, syncer::ModelType type, SyncApiComponentFactory* sync_factory); @@ -49,8 +50,9 @@ class UIDataTypeController : public DataTypeController { virtual State state() const OVERRIDE; // DataTypeErrorHandler interface. - virtual void OnSingleDataTypeUnrecoverableError( - const syncer::SyncError& error) OVERRIDE; + virtual void OnSingleDatatypeUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) OVERRIDE; // Used by tests to override the factory used to create // GenericChangeProcessors. diff --git a/components/sync_driver/ui_data_type_controller_unittest.cc b/components/sync_driver/ui_data_type_controller_unittest.cc index 20bd304..e1b6356 100644 --- a/components/sync_driver/ui_data_type_controller_unittest.cc +++ b/components/sync_driver/ui_data_type_controller_unittest.cc @@ -31,13 +31,17 @@ class SyncUIDataTypeControllerTest : public testing::Test, public: SyncUIDataTypeControllerTest() : type_(syncer::PREFERENCES), - change_processor_(NULL) {} + change_processor_(NULL), + disable_callback_invoked_(false) {} virtual void SetUp() { preference_dtc_ = new UIDataTypeController( base::MessageLoopProxy::current(), base::Closure(), + base::Bind(&SyncUIDataTypeControllerTest::DisableTypeCallback, + base::Unretained(this), + type_), type_, this); SetStartExpectations(); @@ -85,6 +89,13 @@ class SyncUIDataTypeControllerTest : public testing::Test, message_loop_.RunUntilIdle(); } + void DisableTypeCallback(syncer::ModelType type, + const tracked_objects::Location& location, + const std::string& message) { + disable_callback_invoked_ = true; + preference_dtc_->Stop(); + } + base::MessageLoopForUI message_loop_; const syncer::ModelType type_; StartCallbackMock start_callback_; @@ -92,6 +103,7 @@ class SyncUIDataTypeControllerTest : public testing::Test, scoped_refptr<UIDataTypeController> preference_dtc_; FakeGenericChangeProcessor* change_processor_; syncer::FakeSyncableService syncable_service_; + bool disable_callback_invoked_; }; // Start the DTC. Verify that the callback is called with OK, the @@ -188,11 +200,7 @@ TEST_F(SyncUIDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) { testing::Mock::VerifyAndClearExpectations(&start_callback_); EXPECT_CALL(start_callback_, Run(DataTypeController::RUNTIME_ERROR, _, _)); - syncer::SyncError error(FROM_HERE, - syncer::SyncError::DATATYPE_ERROR, - "error", - syncer::PREFERENCES); - preference_dtc_->OnSingleDataTypeUnrecoverableError(error); + preference_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test"); } } // namespace |