diff options
author | lipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-16 07:15:53 +0000 |
---|---|---|
committer | lipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-16 07:15:53 +0000 |
commit | a0bc3146a8657b2d47d4d883ac16946b0489a8d0 (patch) | |
tree | b4c926fbffd5f12130ec82e7e2d2e50760e286d0 /chrome/browser/sync | |
parent | 351e326d2e335db14f44edfc7bc69aa37133dd92 (diff) | |
download | chromium_src-a0bc3146a8657b2d47d4d883ac16946b0489a8d0.zip chromium_src-a0bc3146a8657b2d47d4d883ac16946b0489a8d0.tar.gz chromium_src-a0bc3146a8657b2d47d4d883ac16946b0489a8d0.tar.bz2 |
Rest of the autofill work.
Includes
1. change processor.
2. Migrating code.
3. new datatype registration/enabling/disabling from the UI. (It is keyed off of autofill datatype).
Review URL: http://codereview.chromium.org/5159001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69382 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sync')
37 files changed, 1631 insertions, 171 deletions
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc index 7965f65..112878d 100644 --- a/chrome/browser/sync/engine/syncapi.cc +++ b/chrome/browser/sync/engine/syncapi.cc @@ -43,6 +43,7 @@ #include "chrome/browser/sync/protocol/theme_specifics.pb.h" #include "chrome/browser/sync/protocol/typed_url_specifics.pb.h" #include "chrome/browser/sync/sessions/sync_session_context.h" +#include "chrome/browser/sync/syncable/autofill_migration.h" #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/util/crypto_helpers.h" @@ -375,6 +376,20 @@ void WriteNode::PutAutofillSpecificsAndMarkForSyncing( PutSpecificsAndMarkForSyncing(entity_specifics); } +void WriteNode::SetAutofillProfileSpecifics( + const sync_pb::AutofillProfileSpecifics& new_value) { + DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE); + PutAutofillProfileSpecificsAndMarkForSyncing(new_value); +} + +void WriteNode::PutAutofillProfileSpecificsAndMarkForSyncing( + const sync_pb::AutofillProfileSpecifics& new_value) { + sync_pb::EntitySpecifics entity_specifics; + entity_specifics.MutableExtension(sync_pb::autofill_profile)->CopyFrom( + new_value); + PutSpecificsAndMarkForSyncing(entity_specifics); +} + void WriteNode::SetBookmarkSpecifics( const sync_pb::BookmarkSpecifics& new_value) { DCHECK(GetModelType() == syncable::BOOKMARKS); @@ -1094,6 +1109,50 @@ class SyncManager::SyncInternal return true; } + syncable::AutofillMigrationState GetAutofillMigrationState() { + syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); + if (!lookup.good()) { + DCHECK(false) << "ScopedDirLookup failed when checking initial sync"; + return syncable::NOT_MIGRATED; + } + + return lookup->get_autofill_migration_state(); + } + + void SetAutofillMigrationState(syncable::AutofillMigrationState state) { + syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); + if (!lookup.good()) { + DCHECK(false) << "ScopedDirLookup failed when checking initial sync"; + return; + } + + return lookup->set_autofill_migration_state(state); + } + + void SetAutofillMigrationDebugInfo( + syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set, + const syncable::AutofillMigrationDebugInfo& info) { + syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); + if (!lookup.good()) { + DCHECK(false) << "ScopedDirLookup failed when checking initial sync"; + return; + } + + return lookup->set_autofill_migration_state_debug_info( + property_to_set, info); + } + + syncable::AutofillMigrationDebugInfo + GetAutofillMigrationDebugInfo() { + syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); + if (!lookup.good()) { + DCHECK(false) << "ScopedDirLookup failed when checking initial sync"; + syncable::AutofillMigrationDebugInfo null_value = {0}; + return null_value; + } + return lookup->get_autofill_migration_debug_info(); + } + // SyncEngineEventListener implementation. virtual void OnSyncEngineEvent(const SyncEngineEvent& event); private: @@ -1315,6 +1374,27 @@ void SyncManager::StartSyncing() { data_->StartSyncing(); } +syncable::AutofillMigrationState + SyncManager::GetAutofillMigrationState() { + return data_->GetAutofillMigrationState(); +} + +void SyncManager::SetAutofillMigrationState( + syncable::AutofillMigrationState state) { + return data_->SetAutofillMigrationState(state); +} + +syncable::AutofillMigrationDebugInfo + SyncManager::GetAutofillMigrationDebugInfo() { + return data_->GetAutofillMigrationDebugInfo(); +} + +void SyncManager::SetAutofillMigrationDebugInfo( + syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set, + const syncable::AutofillMigrationDebugInfo& info) { + return data_->SetAutofillMigrationDebugInfo(property_to_set, info); +} + void SyncManager::SetPassphrase(const std::string& passphrase, bool is_explicit) { data_->SetPassphrase(passphrase, is_explicit); diff --git a/chrome/browser/sync/engine/syncapi.h b/chrome/browser/sync/engine/syncapi.h index 2019f41..e2503cb 100644 --- a/chrome/browser/sync/engine/syncapi.h +++ b/chrome/browser/sync/engine/syncapi.h @@ -47,6 +47,7 @@ #include "base/scoped_ptr.h" #include "build/build_config.h" #include "chrome/browser/sync/protocol/password_specifics.pb.h" +#include "chrome/browser/sync/syncable/autofill_migration.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/util/cryptographer.h" #include "chrome/common/net/gaia/google_service_auth_error.h" @@ -347,6 +348,9 @@ class WriteNode : public BaseNode { // Should only be called if GetModelType() == AUTOFILL. void SetAutofillSpecifics(const sync_pb::AutofillSpecifics& specifics); + void SetAutofillProfileSpecifics( + const sync_pb::AutofillProfileSpecifics& specifics); + // Set the nigori specifics. // Should only be called if GetModelType() == NIGORI. void SetNigoriSpecifics(const sync_pb::NigoriSpecifics& specifics); @@ -398,6 +402,8 @@ class WriteNode : public BaseNode { const sync_pb::AppSpecifics& new_value); void PutAutofillSpecificsAndMarkForSyncing( const sync_pb::AutofillSpecifics& new_value); + void PutAutofillProfileSpecificsAndMarkForSyncing( + const sync_pb::AutofillProfileSpecifics& new_value); void PutBookmarkSpecificsAndMarkForSyncing( const sync_pb::BookmarkSpecifics& new_value); void PutNigoriSpecificsAndMarkForSyncing( @@ -817,6 +823,17 @@ class SyncManager { // called. bool InitialSyncEndedForAllEnabledTypes(); + syncable::AutofillMigrationState GetAutofillMigrationState(); + + void SetAutofillMigrationState( + syncable::AutofillMigrationState state); + + syncable::AutofillMigrationDebugInfo GetAutofillMigrationDebugInfo(); + + void SetAutofillMigrationDebugInfo( + syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set, + const syncable::AutofillMigrationDebugInfo& info); + // Migrate tokens from user settings DB to the token service. void MigrateTokens(); diff --git a/chrome/browser/sync/glue/autofill_change_processor.cc b/chrome/browser/sync/glue/autofill_change_processor.cc index 155e6e7..6914308 100644 --- a/chrome/browser/sync/glue/autofill_change_processor.cc +++ b/chrome/browser/sync/glue/autofill_change_processor.cc @@ -9,16 +9,20 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/profiles/profile.h" #include "chrome/browser/autofill/personal_data_manager.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/glue/autofill_change_processor2.h" #include "chrome/browser/sync/glue/autofill_model_associator.h" +#include "chrome/browser/sync/glue/autofill_profile_model_associator.h" +#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/webdata/autofill_change.h" #include "chrome/browser/webdata/web_data_service.h" #include "chrome/browser/webdata/web_database.h" #include "chrome/common/guid.h" #include "chrome/common/notification_service.h" +#include "chrome/common/pref_names.h" namespace browser_sync { @@ -83,7 +87,7 @@ void AutofillChangeProcessor::Observe(NotificationType type, void AutofillChangeProcessor::PostOptimisticRefreshTask() { BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - new AutofillModelAssociator::DoOptimisticRefreshTask( + new DoOptimisticRefreshForAutofill( personal_data_)); } @@ -195,6 +199,8 @@ void AutofillChangeProcessor::ApplyChangesFromSyncModel( return; StopObserving(); + bool autofill_profile_not_migrated = HasNotMigratedYet(trans); + sync_api::ReadNode autofill_root(trans); if (!autofill_root.InitByTagLookup(kAutofillTag)) { error_handler()->OnUnrecoverableError(FROM_HERE, @@ -210,7 +216,7 @@ void AutofillChangeProcessor::ApplyChangesFromSyncModel( const sync_pb::AutofillSpecifics& autofill = changes[i].specifics.GetExtension(sync_pb::autofill); if (autofill.has_value() || - (HasNotMigratedYet() && autofill.has_profile())) { + (autofill_profile_not_migrated && autofill.has_profile())) { autofill_changes_.push_back(AutofillChangeRecord(changes[i].action, changes[i].id, autofill)); @@ -236,7 +242,7 @@ void AutofillChangeProcessor::ApplyChangesFromSyncModel( sync_node.GetAutofillSpecifics()); int64 sync_id = sync_node.GetId(); if (autofill.has_value() || - (HasNotMigratedYet() && autofill.has_profile())) { + (autofill_profile_not_migrated && autofill.has_profile())) { autofill_changes_.push_back(AutofillChangeRecord(changes[i].action, sync_id, autofill)); } else { @@ -261,7 +267,6 @@ void AutofillChangeProcessor::CommitChangesFromSyncModel() { if (autofill_changes_[i].autofill_.has_value()) { ApplySyncAutofillEntryDelete(autofill_changes_[i].autofill_); } else if (autofill_changes_[i].autofill_.has_profile()) { - DCHECK(HasNotMigratedYet()); ApplySyncAutofillProfileDelete(autofill_changes_[i].id_); } else { NOTREACHED() << "Autofill's CommitChanges received change with no" @@ -276,7 +281,6 @@ void AutofillChangeProcessor::CommitChangesFromSyncModel() { autofill_changes_[i].autofill_, &new_entries, autofill_changes_[i].id_); } else if (autofill_changes_[i].autofill_.has_profile()) { - DCHECK(HasNotMigratedYet()); ApplySyncAutofillProfileChange(autofill_changes_[i].action_, autofill_changes_[i].autofill_.profile(), autofill_changes_[i].id_); @@ -433,40 +437,9 @@ void AutofillChangeProcessor::WriteAutofillEntry( node->SetAutofillSpecifics(autofill); } -// static -void AutofillChangeProcessor::WriteAutofillProfile( - const AutoFillProfile& profile, sync_api::WriteNode* node) { - sync_pb::AutofillSpecifics autofill; - sync_pb::AutofillProfileSpecifics* s(autofill.mutable_profile()); - s->set_name_first(UTF16ToUTF8( - profile.GetFieldText(AutoFillType(NAME_FIRST)))); - s->set_name_middle(UTF16ToUTF8( - profile.GetFieldText(AutoFillType(NAME_MIDDLE)))); - s->set_name_last(UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST)))); - s->set_address_home_line1( - UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1)))); - s->set_address_home_line2( - UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2)))); - s->set_address_home_city(UTF16ToUTF8(profile.GetFieldText( - AutoFillType(ADDRESS_HOME_CITY)))); - s->set_address_home_state(UTF16ToUTF8(profile.GetFieldText( - AutoFillType(ADDRESS_HOME_STATE)))); - s->set_address_home_country(UTF16ToUTF8(profile.GetFieldText( - AutoFillType(ADDRESS_HOME_COUNTRY)))); - s->set_address_home_zip(UTF16ToUTF8(profile.GetFieldText( - AutoFillType(ADDRESS_HOME_ZIP)))); - s->set_email_address(UTF16ToUTF8(profile.GetFieldText( - AutoFillType(EMAIL_ADDRESS)))); - s->set_company_name(UTF16ToUTF8(profile.GetFieldText( - AutoFillType(COMPANY_NAME)))); - s->set_phone_fax_whole_number(UTF16ToUTF8(profile.GetFieldText( - AutoFillType(PHONE_FAX_WHOLE_NUMBER)))); - s->set_phone_home_whole_number(UTF16ToUTF8(profile.GetFieldText( - AutoFillType(PHONE_HOME_WHOLE_NUMBER)))); - node->SetAutofillSpecifics(autofill); -} -bool AutofillChangeProcessor::HasNotMigratedYet() { - return true; +bool AutofillChangeProcessor::HasNotMigratedYet( + const sync_api::BaseTransaction* trans) { + return model_associator_->HasNotMigratedYet(trans); } } // namespace browser_sync diff --git a/chrome/browser/sync/glue/autofill_change_processor.h b/chrome/browser/sync/glue/autofill_change_processor.h index e901c8e..ba132fa 100644 --- a/chrome/browser/sync/glue/autofill_change_processor.h +++ b/chrome/browser/sync/glue/autofill_change_processor.h @@ -63,9 +63,6 @@ class AutofillChangeProcessor : public ChangeProcessor, // node. static void WriteAutofillEntry(const AutofillEntry& entry, sync_api::WriteNode* node); - // As above, for autofill profiles. - static void WriteAutofillProfile(const AutoFillProfile& profile, - sync_api::WriteNode* node); // TODO(georgey) : add the same processing for CC info (already in protocol // buffers). @@ -112,7 +109,7 @@ class AutofillChangeProcessor : public ChangeProcessor, void PostOptimisticRefreshTask(); // Called to see if we need to upgrade to the new autofill2 profile. - bool HasNotMigratedYet(); + bool HasNotMigratedYet(const sync_api::BaseTransaction* trans); // The two models should be associated according to this ModelAssociator. AutofillModelAssociator* model_associator_; diff --git a/chrome/browser/sync/glue/autofill_change_processor2.cc b/chrome/browser/sync/glue/autofill_change_processor2.cc index eb70809..49b669c 100644 --- a/chrome/browser/sync/glue/autofill_change_processor2.cc +++ b/chrome/browser/sync/glue/autofill_change_processor2.cc @@ -9,8 +9,8 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/profiles/profile.h" #include "chrome/browser/autofill/personal_data_manager.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/glue/autofill_model_associator.h" #include "chrome/browser/sync/glue/autofill_model_associator2.h" #include "chrome/browser/sync/profile_sync_service.h" @@ -581,4 +581,3 @@ void AutofillChangeProcessor2::WriteAutofillProfile( } } // namespace browser_sync - diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.cc b/chrome/browser/sync/glue/autofill_data_type_controller.cc index 6a827c9..8661e14 100644 --- a/chrome/browser/sync/glue/autofill_data_type_controller.cc +++ b/chrome/browser/sync/glue/autofill_data_type_controller.cc @@ -12,8 +12,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/glue/autofill_change_processor.h" #include "chrome/browser/sync/glue/autofill_model_associator.h" -#include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/profile_sync_factory.h" +#include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/webdata/web_data_service.h" #include "chrome/common/notification_service.h" @@ -170,6 +170,19 @@ DataTypeController::State AutofillDataTypeController::state() { return state_; } +ProfileSyncFactory::SyncComponents + AutofillDataTypeController::CreateSyncComponents( + ProfileSyncService* profile_sync_service, + WebDatabase* web_database, + PersonalDataManager* personal_data, + browser_sync::UnrecoverableErrorHandler* error_handler) { + return profile_sync_factory_->CreateAutofillSyncComponents( + profile_sync_service, + web_database, + personal_data, + this); +} + void AutofillDataTypeController::StartImpl() { VLOG(1) << "Autofill data type controller StartImpl called."; DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); @@ -182,7 +195,7 @@ void AutofillDataTypeController::StartImpl() { return; } ProfileSyncFactory::SyncComponents sync_components = - profile_sync_factory_->CreateAutofillSyncComponents( + CreateSyncComponents( sync_service_, web_data_service_->GetDatabase(), profile_->GetPersonalDataManager(), diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.h b/chrome/browser/sync/glue/autofill_data_type_controller.h index c66dcfd..d73edf2 100644 --- a/chrome/browser/sync/glue/autofill_data_type_controller.h +++ b/chrome/browser/sync/glue/autofill_data_type_controller.h @@ -12,6 +12,7 @@ #include "base/scoped_ptr.h" #include "base/waitable_event.h" #include "chrome/browser/autofill/personal_data_manager.h" +#include "chrome/browser/sync/profile_sync_factory.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/glue/data_type_controller.h" @@ -62,6 +63,14 @@ class AutofillDataTypeController : public DataTypeController, // PersonalDataManager::Observer implementation: virtual void OnPersonalDataLoaded(); + protected: + virtual ProfileSyncFactory::SyncComponents CreateSyncComponents( + ProfileSyncService* profile_sync_service, + WebDatabase* web_database, + PersonalDataManager* personal_data, + browser_sync::UnrecoverableErrorHandler* error_handler); + ProfileSyncFactory* profile_sync_factory_; + private: void StartImpl(); void StartDone(StartResult result, State state); @@ -80,7 +89,6 @@ class AutofillDataTypeController : public DataTypeController, state_ = state; } - ProfileSyncFactory* profile_sync_factory_; Profile* profile_; ProfileSyncService* sync_service_; State state_; diff --git a/chrome/browser/sync/glue/autofill_model_associator.cc b/chrome/browser/sync/glue/autofill_model_associator.cc index 06b28af..f1340df 100644 --- a/chrome/browser/sync/glue/autofill_model_associator.cc +++ b/chrome/browser/sync/glue/autofill_model_associator.cc @@ -12,13 +12,17 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/autofill_profile.h" #include "chrome/browser/browser_thread.h" +#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/engine/syncapi.h" #include "chrome/browser/sync/glue/autofill_change_processor.h" +#include "chrome/browser/sync/glue/autofill_profile_model_associator.h" +#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/protocol/autofill_specifics.pb.h" #include "chrome/browser/webdata/web_database.h" #include "chrome/common/guid.h" +#include "chrome/common/pref_names.h" #include "net/base/escape.h" using base::TimeTicks; @@ -37,16 +41,6 @@ struct AutofillModelAssociator::DataBundle { ~DataBundle() { STLDeleteElements(&new_profiles); } }; -AutofillModelAssociator::DoOptimisticRefreshTask::DoOptimisticRefreshTask( - PersonalDataManager* pdm) : pdm_(pdm) {} - -AutofillModelAssociator::DoOptimisticRefreshTask::~DoOptimisticRefreshTask() {} - -void AutofillModelAssociator::DoOptimisticRefreshTask::Run() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - pdm_->Refresh(); -} - AutofillModelAssociator::AutofillModelAssociator( ProfileSyncService* sync_service, WebDatabase* web_database, @@ -55,7 +49,8 @@ AutofillModelAssociator::AutofillModelAssociator( web_database_(web_database), personal_data_(personal_data), autofill_node_id_(sync_api::kInvalidId), - abort_association_pending_(false) { + abort_association_pending_(false), + number_of_entries_created_(0) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); DCHECK(sync_service_); DCHECK(web_database_); @@ -114,6 +109,7 @@ bool AutofillModelAssociator::TraverseAndAssociateChromeAutofillEntries( node.SetTitle(UTF8ToWide(tag)); AutofillChangeProcessor::WriteAutofillEntry(*ix, &node); Associate(&tag, node.GetId()); + number_of_entries_created_++; } current_entries->insert(ix->key()); @@ -121,21 +117,6 @@ bool AutofillModelAssociator::TraverseAndAssociateChromeAutofillEntries( return true; } -bool AutofillModelAssociator::MakeNewAutofillProfileSyncNode( - sync_api::WriteTransaction* trans, const sync_api::BaseNode& autofill_root, - const std::string& tag, const AutoFillProfile& profile, int64* sync_id) { - sync_api::WriteNode node(trans); - if (!node.InitUniqueByCreation(syncable::AUTOFILL, autofill_root, tag)) { - LOG(ERROR) << "Failed to create autofill sync node."; - return false; - } - node.SetTitle(UTF8ToWide(tag)); - AutofillChangeProcessor::WriteAutofillProfile(profile, &node); - *sync_id = node.GetId(); - return true; -} - - bool AutofillModelAssociator::LoadAutofillData( std::vector<AutofillEntry>* entries, std::vector<AutoFillProfile*>* profiles) { @@ -205,8 +186,18 @@ bool AutofillModelAssociator::AssociateModels() { return false; } + if (sync_service_->backend()->GetAutofillMigrationState() != + syncable::MIGRATED) { + syncable::AutofillMigrationDebugInfo debug_info; + debug_info.autofill_entries_added_during_migration = + number_of_entries_created_; + sync_service_->backend()->SetAutofillMigrationDebugInfo( + syncable::AutofillMigrationDebugInfo::ENTRIES_ADDED, + debug_info); + } + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - new DoOptimisticRefreshTask(personal_data_)); + new DoOptimisticRefreshForAutofill(personal_data_)); return true; } @@ -244,6 +235,27 @@ bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes( const std::vector<AutoFillProfile*>& all_profiles_from_db) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); + bool autofill_profile_not_migrated = HasNotMigratedYet(write_trans); + + if (MigrationLoggingEnabled() && + autofill_profile_not_migrated) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "Printing profiles from web db"; + + for (std::vector<AutoFillProfile*>::const_iterator ix = + all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) { + AutoFillProfile* p = *ix; + VLOG(1) << "[AUTOFILL MIGRATION] " + << p->GetFieldText(AutoFillType(NAME_FIRST)) + << p->GetFieldText(AutoFillType(NAME_LAST)); + } + } + + if (MigrationLoggingEnabled() && autofill_profile_not_migrated) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "Iterating over sync db"; + } + int64 sync_child_id = autofill_root.GetFirstChildId(); while (sync_child_id != sync_api::kInvalidId) { sync_api::ReadNode sync_child(write_trans); @@ -256,13 +268,20 @@ bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes( if (autofill.has_value()) { AddNativeEntryIfNeeded(autofill, bundle, sync_child); - } else if (autofill.has_profile() && HasNotMigratedYet()) { + } else if (autofill.has_profile()) { // Ignore autofill profiles if we are not upgrading. - AddNativeProfileIfNeeded( - autofill.profile(), - bundle, - sync_child, - all_profiles_from_db); + if (autofill_profile_not_migrated) { + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION] Looking for " + << autofill.profile().name_first() + << autofill.profile().name_last(); + } + AddNativeProfileIfNeeded( + autofill.profile(), + bundle, + sync_child, + all_profiles_from_db); + } } else { NOTREACHED() << "AutofillSpecifics has no autofill data!"; } @@ -332,15 +351,23 @@ void AutofillModelAssociator::AddNativeProfileIfNeeded( DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); - scoped_ptr<AutoFillProfile> profile_in_web_db(FindCorrespondingNodeFromWebDB( - profile, all_profiles_from_db)); + AutoFillProfile* profile_in_web_db = FindCorrespondingNodeFromWebDB( + profile, all_profiles_from_db); - if (profile_in_web_db.get() != NULL) { + if (profile_in_web_db != NULL) { + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "Node found in web db. So associating"; + } int64 sync_id = node.GetId(); std::string guid = profile_in_web_db->guid(); Associate(&guid, sync_id); return; } else { // Create a new node. + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "Node not found in web db so creating and associating"; + } std::string guid = guid::GenerateGUID(); Associate(&guid, node.GetId()); AutoFillProfile* p = new AutoFillProfile(guid); @@ -509,8 +536,61 @@ bool AutofillModelAssociator::FillProfileWithServerData( return diff; } -bool AutofillModelAssociator::HasNotMigratedYet() { - return true; +bool AutofillModelAssociator::HasNotMigratedYet( + const sync_api::BaseTransaction* trans) { + + // Now read the current value from the directory. + syncable::AutofillMigrationState autofill_migration_state = + sync_service()->backend()->GetAutofillMigrationState(); + + DCHECK_NE(autofill_migration_state, syncable::NOT_DETERMINED); + + if (autofill_migration_state== syncable::NOT_DETERMINED) { + VLOG(1) << "Autofill migration state is not determined inside " + << " model associator"; + } + + if (autofill_migration_state == syncable::NOT_MIGRATED) { + return true; + } + + if (autofill_migration_state == syncable::INSUFFICIENT_INFO_TO_DETERMINE) { + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "current autofill migration state is insufficient info to" + << "determine."; + } + sync_api::ReadNode autofill_profile_root_node(trans); + if (!autofill_profile_root_node.InitByTagLookup( + browser_sync::kAutofillProfileTag) || + autofill_profile_root_node.GetFirstChildId()== + static_cast<int64>(0)) { + sync_service()->backend()->SetAutofillMigrationState( + syncable::NOT_MIGRATED); + + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "Current autofill migration state is NOT Migrated because" + << "legacy autofill root node is present whereas new " + << "Autofill profile root node is absent."; + } + return true; + } + + sync_service()->backend()->SetAutofillMigrationState(syncable::MIGRATED); + + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "Current autofill migration state is migrated."; + } + } + + return false; } +bool AutofillModelAssociator::MigrationLoggingEnabled() { + // [TODO] enable logging via a command line flag. + return false; +} } // namespace browser_sync + diff --git a/chrome/browser/sync/glue/autofill_model_associator.h b/chrome/browser/sync/glue/autofill_model_associator.h index 63db0e8..3f1104e 100644 --- a/chrome/browser/sync/glue/autofill_model_associator.h +++ b/chrome/browser/sync/glue/autofill_model_associator.h @@ -52,17 +52,6 @@ class AutofillModelAssociator PersonalDataManager* data_manager); virtual ~AutofillModelAssociator(); - // A task used by this class and the change processor to inform the - // PersonalDataManager living on the UI thread that it needs to refresh. - class DoOptimisticRefreshTask : public Task { - public: - explicit DoOptimisticRefreshTask(PersonalDataManager* pdm); - virtual ~DoOptimisticRefreshTask(); - virtual void Run(); - private: - scoped_refptr<PersonalDataManager> pdm_; - }; - // PerDataTypeAssociatorInterface implementation. // // Iterates through the sync model looking for matched pairs of items. @@ -114,13 +103,13 @@ class AutofillModelAssociator // Returns sync service instance. ProfileSyncService* sync_service() { return sync_service_; } - protected: // Is called to determine if we need to upgrade to the new // autofillprofile2 data type. If so we need to sync up autofillprofile // first to the latest available changes on the server and then upgrade // to autofillprofile2. - virtual bool HasNotMigratedYet(); + virtual bool HasNotMigratedYet(const sync_api::BaseTransaction* trans); + protected: // Given a profile from sync db it tries to match the profile against // one in web db. it ignores the guid and compares the actual data. AutoFillProfile* FindCorrespondingNodeFromWebDB( @@ -180,20 +169,12 @@ class AutofillModelAssociator const sync_api::ReadNode& node, const std::vector<AutoFillProfile*>& all_profiles_from_db); - // Helper to insert a sync node for the given AutoFillProfile (e.g. in - // response to encountering a native profile that doesn't exist yet in the - // cloud). - bool MakeNewAutofillProfileSyncNode( - sync_api::WriteTransaction* trans, - const sync_api::BaseNode& autofill_root, - const std::string& tag, - const AutoFillProfile& profile, - int64* sync_id); - // Called at various points in model association to determine if the // user requested an abort. bool IsAbortPending(); + bool MigrationLoggingEnabled(); + ProfileSyncService* sync_service_; WebDatabase* web_database_; PersonalDataManager* personal_data_; @@ -207,6 +188,7 @@ class AutofillModelAssociator // AssociateModels method as soon as possible. Lock abort_association_pending_lock_; bool abort_association_pending_; + int number_of_entries_created_; DISALLOW_COPY_AND_ASSIGN(AutofillModelAssociator); }; diff --git a/chrome/browser/sync/glue/autofill_profile_change_processor.cc b/chrome/browser/sync/glue/autofill_profile_change_processor.cc new file mode 100644 index 0000000..bb99391 --- /dev/null +++ b/chrome/browser/sync/glue/autofill_profile_change_processor.cc @@ -0,0 +1,338 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file
+
+#include "chrome/browser/sync/glue/autofill_profile_change_processor.h"
+
+#include <string>
+#include <vector>
+
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/autofill_profile.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
+#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
+#include "chrome/browser/sync/unrecoverable_error_handler.h"
+#include "chrome/browser/webdata/autofill_change.h"
+#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+
+namespace browser_sync {
+
+AutofillProfileChangeProcessor::AutofillProfileChangeProcessor(
+ AutofillProfileModelAssociator *model_associator,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data_manager,
+ UnrecoverableErrorHandler* error_handler)
+ : ChangeProcessor(error_handler),
+ model_associator_(model_associator),
+ observing_(false),
+ web_database_(web_database),
+ personal_data_(personal_data_manager) {
+ DCHECK(model_associator);
+ DCHECK(web_database);
+ DCHECK(error_handler);
+ DCHECK(personal_data_manager);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+
+ StartObserving();
+}
+
+AutofillProfileChangeProcessor::ScopedStopObserving::ScopedStopObserving(
+ AutofillProfileChangeProcessor* processor) {
+ processor_ = processor;
+ processor_->StopObserving();
+}
+
+AutofillProfileChangeProcessor::ScopedStopObserving::~ScopedStopObserving() {
+ processor_->StartObserving();
+}
+
+void AutofillProfileChangeProcessor::ApplyChangesFromSyncModel(
+ const sync_api::BaseTransaction *write_trans,
+ const sync_api::SyncManager::ChangeRecord* changes,
+ int change_count) {
+
+ ScopedStopObserving observer(this);
+
+ sync_api::ReadNode autofill_profile_root(write_trans);
+ if (!autofill_profile_root.InitByTagLookup(kAutofillProfileTag)) {
+ error_handler()->OnUnrecoverableError(FROM_HERE,
+ "Autofill Profile root node lookup failed");
+ return;
+ }
+
+ for (int i = 0; i < change_count; ++i) {
+ if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
+ changes[i].action) {
+ DCHECK(changes[i].specifics.HasExtension(
+ sync_pb::autofill_profile));
+
+ const sync_pb::AutofillProfileSpecifics& specifics =
+ changes[i].specifics.GetExtension(sync_pb::autofill_profile);
+
+ autofill_changes_.push_back(AutofillProfileChangeRecord(changes[i].action,
+ changes[i].id,
+ specifics));
+ continue;
+ }
+
+ // If it is not a delete.
+ sync_api::ReadNode sync_node(write_trans);
+ if (!sync_node.InitByIdLookup(changes[i].id)) {
+ LOG(ERROR) << "Could not find the id in sync db " << changes[i].id;
+ continue;
+ }
+
+ const sync_pb::AutofillProfileSpecifics& autofill(
+ sync_node.GetAutofillProfileSpecifics());
+
+ autofill_changes_.push_back(AutofillProfileChangeRecord(changes[i].action,
+ changes[i].id,
+ autofill));
+ }
+}
+
+void AutofillProfileChangeProcessor::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(type.value, NotificationType::AUTOFILL_PROFILE_CHANGED_GUID);
+ WebDataService* wds = Source<WebDataService>(source).ptr();
+
+ if (!wds || wds->GetDatabase() != web_database_)
+ return;
+
+ sync_api::WriteTransaction trans(share_handle());
+ sync_api::ReadNode autofill_root(&trans);
+ if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) {
+ error_handler()->OnUnrecoverableError(FROM_HERE,
+ "Server did not create a tolp level node");
+ return;
+ }
+
+ AutofillProfileChangeGUID* change =
+ Details<AutofillProfileChangeGUID>(details).ptr();
+
+ ActOnChange(change, &trans, autofill_root);
+}
+
+void AutofillProfileChangeProcessor::ActOnChange(
+ AutofillProfileChangeGUID* change,
+ sync_api::WriteTransaction* trans,
+ sync_api::ReadNode& autofill_root) {
+ DCHECK(change->type() == AutofillProfileChangeGUID::REMOVE ||
+ change->profile());
+ switch (change->type()) {
+ case AutofillProfileChangeGUID::ADD: {
+ AddAutofillProfileSyncNode(trans, autofill_root, *(change->profile()));
+ break;
+ }
+ case AutofillProfileChangeGUID::UPDATE: {
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key());
+ if (sync_api::kInvalidId == sync_id) {
+ LOG(ERROR) << "Sync id is not found for " << change->key();
+ break;
+ }
+ sync_api::WriteNode node(trans);
+ if (!node.InitByIdLookup(sync_id)) {
+ LOG(ERROR) << "Could not find sync node for id " << sync_id;
+ break;
+ }
+
+ WriteAutofillProfile(*(change->profile()), &node);
+ break;
+ }
+ case AutofillProfileChangeGUID::REMOVE: {
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key());
+ if (sync_api::kInvalidId == sync_id) {
+ LOG(ERROR) << "Sync id is not found for " << change->key();
+ break;
+ }
+ sync_api::WriteNode node(trans);
+ if (!node.InitByIdLookup(sync_id)) {
+ LOG(ERROR) << "Could not find sync node for id " << sync_id;
+ break;
+ }
+ node.Remove();
+ model_associator_->Disassociate(sync_id);
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+void AutofillProfileChangeProcessor::CommitChangesFromSyncModel() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+
+ if (!running())
+ return;
+
+ ScopedStopObserving observer(this);
+
+ for (unsigned int i = 0;i < autofill_changes_.size(); ++i) {
+ if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
+ autofill_changes_[i].action_) {
+ if (!web_database_->RemoveAutoFillProfile(
+ autofill_changes_[i].profile_specifics_.guid())) {
+ LOG(ERROR) << "could not delete the profile " <<
+ autofill_changes_[i].profile_specifics_.guid();
+ continue;
+ }
+ continue;
+ }
+
+ // Now for updates and adds.
+ ApplyAutofillProfileChange(autofill_changes_[i].action_,
+ autofill_changes_[i].profile_specifics_,
+ autofill_changes_[i].id_);
+ }
+
+ autofill_changes_.clear();
+
+ PostOptimisticRefreshTask();
+}
+
+void AutofillProfileChangeProcessor::PostOptimisticRefreshTask() {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ new DoOptimisticRefreshForAutofill(
+ personal_data_));
+}
+
+void AutofillProfileChangeProcessor::ApplyAutofillProfileChange(
+ sync_api::SyncManager::ChangeRecord::Action action,
+ const sync_pb::AutofillProfileSpecifics& profile_specifics,
+ int64 sync_id) {
+
+ DCHECK_NE(sync_api::SyncManager::ChangeRecord::ACTION_DELETE, action);
+ switch (action) {
+ case sync_api::SyncManager::ChangeRecord::ACTION_ADD: {
+ AutoFillProfile p(profile_specifics.guid());
+ AutofillProfileModelAssociator::OverwriteProfileWithServerData(&p,
+ profile_specifics);
+ if (!web_database_->AddAutoFillProfile(p)) {
+ LOG(ERROR) << "could not add autofill profile for guid " << p.guid();
+ break;
+ }
+
+ // Now that the node has been succesfully created we can associate it.
+ std::string guid = p.guid();
+ model_associator_->Associate(&guid, sync_id);
+ break;
+ }
+ case sync_api::SyncManager::ChangeRecord::ACTION_UPDATE: {
+ AutoFillProfile *p;
+ if (!web_database_->GetAutoFillProfileForGUID(
+ profile_specifics.guid(), &p)) {
+ LOG(ERROR) << "Could not find the autofill profile to update for " <<
+ profile_specifics.guid();
+ break;
+ }
+ scoped_ptr<AutoFillProfile> autofill_pointer(p);
+ AutofillProfileModelAssociator::OverwriteProfileWithServerData(
+ autofill_pointer.get(),
+ profile_specifics);
+
+ if (!web_database_->UpdateAutoFillProfile(*(autofill_pointer.get()))) {
+ LOG(ERROR) << "Could not update autofill profile for " <<
+ profile_specifics.guid();
+ break;
+ }
+ break;
+ }
+ default: {
+ NOTREACHED();
+ break;
+ }
+ }
+}
+
+void AutofillProfileChangeProcessor::RemoveSyncNode(const std::string& guid,
+ sync_api::WriteTransaction* trans) {
+ sync_api::WriteNode node(trans);
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(guid);
+ if (sync_api::kInvalidId == sync_id) {
+ LOG(ERROR) << "Could not find the node in associator " << guid;
+ return;
+ }
+
+ if (!node.InitByIdLookup(sync_id)) {
+ LOG(ERROR) << "Could not find the sync node for " << guid;
+ return;
+ }
+
+ model_associator_->Disassociate(sync_id);
+ node.Remove();
+}
+
+void AutofillProfileChangeProcessor::AddAutofillProfileSyncNode(
+ sync_api::WriteTransaction* trans,
+ sync_api::BaseNode& autofill_profile_root,
+ const AutoFillProfile& profile) {
+ sync_api::WriteNode node(trans);
+ if (!node.InitUniqueByCreation(syncable::AUTOFILL_PROFILE,
+ autofill_profile_root,
+ profile.guid())) {
+ LOG(ERROR) << "could not create a sync node ";
+ return;
+ }
+
+ node.SetTitle(UTF8ToWide(profile.guid()));
+
+ WriteAutofillProfile(profile, &node);
+}
+
+void AutofillProfileChangeProcessor::StartObserving() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ notification_registrar_.Add(this,
+ NotificationType::AUTOFILL_PROFILE_CHANGED_GUID,
+ NotificationService::AllSources());
+}
+
+void AutofillProfileChangeProcessor::StopObserving() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ notification_registrar_.RemoveAll();
+}
+
+void AutofillProfileChangeProcessor::WriteAutofillProfile(
+ const AutoFillProfile& profile,
+ sync_api::WriteNode* node) {
+ sync_pb::AutofillProfileSpecifics specifics;
+ specifics.set_guid(profile.guid());
+ specifics.set_name_first(UTF16ToUTF8(
+ profile.GetFieldText(AutoFillType(NAME_FIRST))));
+ specifics.set_name_middle(UTF16ToUTF8(
+ profile.GetFieldText(AutoFillType(NAME_MIDDLE))));
+ specifics.set_name_last(
+ UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST))));
+ specifics.set_address_home_line1(
+ UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1))));
+ specifics.set_address_home_line2(
+ UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2))));
+ specifics.set_address_home_city(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(ADDRESS_HOME_CITY))));
+ specifics.set_address_home_state(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(ADDRESS_HOME_STATE))));
+ specifics.set_address_home_country(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(ADDRESS_HOME_COUNTRY))));
+ specifics.set_address_home_zip(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(ADDRESS_HOME_ZIP))));
+ specifics.set_email_address(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(EMAIL_ADDRESS))));
+ specifics.set_company_name(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(COMPANY_NAME))));
+ specifics.set_phone_fax_whole_number(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(PHONE_FAX_WHOLE_NUMBER))));
+ specifics.set_phone_home_whole_number(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(PHONE_HOME_WHOLE_NUMBER))));
+ node->SetAutofillProfileSpecifics(specifics);
+}
+
+} // namespace browser_sync
+
diff --git a/chrome/browser/sync/glue/autofill_profile_change_processor.h b/chrome/browser/sync/glue/autofill_profile_change_processor.h new file mode 100644 index 0000000..0b408a3 --- /dev/null +++ b/chrome/browser/sync/glue/autofill_profile_change_processor.h @@ -0,0 +1,120 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_CHANGE_PROCESSOR_H_ +#define CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_CHANGE_PROCESSOR_H_ +#pragma once +#include <string> +#include <vector> + +#include "chrome/browser/autofill/autofill_profile.h" +#include "chrome/browser/autofill/personal_data_manager.h" +#include "chrome/browser/sync/engine/syncapi.h" +#include "chrome/browser/sync/glue/autofill_profile_model_associator.h" +#include "chrome/browser/sync/glue/change_processor.h" +#include "chrome/browser/sync/unrecoverable_error_handler.h" +#include "chrome/browser/webdata/autofill_change.h" +#include "chrome/browser/webdata/web_database.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" + +namespace browser_sync { + +class AutofillProfileChangeProcessor : public ChangeProcessor, + public NotificationObserver { + public: + AutofillProfileChangeProcessor( + AutofillProfileModelAssociator *model_associator, + WebDatabase* web_database, + PersonalDataManager* personal_data_manager, + UnrecoverableErrorHandler* error_handler); + + virtual ~AutofillProfileChangeProcessor() {} + + // Virtual methods from ChangeProcessor class. + virtual void ApplyChangesFromSyncModel( + const sync_api::BaseTransaction *write_trans, + const sync_api::SyncManager::ChangeRecord* changes, + int change_count); + + virtual void CommitChangesFromSyncModel(); + + // Virtual method implemented for the observer class. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + + static void WriteAutofillProfile(const AutoFillProfile& profile, + sync_api::WriteNode* node); + + protected: + // Protected methods from ChangeProcessor. + virtual void StartImpl(Profile* profile) {} + virtual void StopImpl() {} + + struct AutofillProfileChangeRecord { + sync_api::SyncManager::ChangeRecord::Action action_; + int64 id_; + sync_pb::AutofillProfileSpecifics profile_specifics_; + AutofillProfileChangeRecord( + sync_api::SyncManager::ChangeRecord::Action action, + int64 id, + const sync_pb::AutofillProfileSpecifics profile_specifics) + : action_(action), + id_(id), + profile_specifics_(profile_specifics) {} + }; + + std::vector<AutofillProfileChangeRecord> autofill_changes_; + + virtual void AddAutofillProfileSyncNode(sync_api::WriteTransaction* trans, + sync_api::BaseNode& autofill_profile_root, + const AutoFillProfile& profile); + + void ActOnChange(AutofillProfileChangeGUID* change, + sync_api::WriteTransaction* trans, + sync_api::ReadNode& autofill_root); + + private: + + // This ensures that startobsrving gets called after stopobserving even + // if there is an early return in the function. + // TODO(lipalani) - generalize this and add it to other change processors. + class ScopedStopObserving { + public: + explicit ScopedStopObserving(AutofillProfileChangeProcessor* processor); + ~ScopedStopObserving(); + + private: + ScopedStopObserving() {} + AutofillProfileChangeProcessor* processor_; + }; + + void StartObserving(); + void StopObserving(); + + void PostOptimisticRefreshTask(); + + void ApplyAutofillProfileChange( + sync_api::SyncManager::ChangeRecord::Action action, + const sync_pb::AutofillProfileSpecifics& profile, + int64 sync_id); + + void RemoveSyncNode( + const std::string& guid, sync_api::WriteTransaction *trans); + + AutofillProfileModelAssociator* model_associator_; + bool observing_; + + WebDatabase* web_database_; + PersonalDataManager* personal_data_; + NotificationRegistrar notification_registrar_; +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_CHANGE_PROCESSOR_H_ + diff --git a/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc b/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc new file mode 100644 index 0000000..230b680 --- /dev/null +++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/glue/autofill_profile_data_type_controller.h" + +#include "chrome/browser/sync/glue/autofill_data_type_controller.h" +#include "chrome/browser/sync/profile_sync_factory.h" + +namespace browser_sync { + +AutofillProfileDataTypeController::AutofillProfileDataTypeController( + ProfileSyncFactory* profile_sync_factory, + Profile* profile, + ProfileSyncService* sync_service) : AutofillDataTypeController( + profile_sync_factory, + profile, + sync_service) {} + +ProfileSyncFactory::SyncComponents + AutofillProfileDataTypeController::CreateSyncComponents( + ProfileSyncService* profile_sync_service, + WebDatabase* web_database, + PersonalDataManager* personal_data, + browser_sync::UnrecoverableErrorHandler* error_handler) { + return profile_sync_factory_->CreateAutofillProfileSyncComponents( + profile_sync_service, + web_database, + personal_data, + this); +} +} // namepsace browser_sync + diff --git a/chrome/browser/sync/glue/autofill_profile_data_type_controller.h b/chrome/browser/sync/glue/autofill_profile_data_type_controller.h new file mode 100644 index 0000000..8bb6e8e --- /dev/null +++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.h @@ -0,0 +1,39 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_DATA_TYPE_CONTROLLER_H_ +#define CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_DATA_TYPE_CONTROLLER_H_ +#pragma once + +#include "chrome/browser/sync/glue/autofill_data_type_controller.h" +#include "chrome/browser/sync/profile_sync_factory.h" + +namespace browser_sync { + +class AutofillProfileDataTypeController : public AutofillDataTypeController { + public: + AutofillProfileDataTypeController( + ProfileSyncFactory* profile_sync_factory, + Profile* profile, + ProfileSyncService* sync_service); + virtual ~AutofillProfileDataTypeController() {} + + virtual syncable::ModelType type() { + return syncable::AUTOFILL_PROFILE; + } + + virtual const char* name() const { + // For logging only. + return "autofill_profile"; + } + protected: + virtual ProfileSyncFactory::SyncComponents CreateSyncComponents( + ProfileSyncService* profile_sync_service, + WebDatabase* web_database, + PersonalDataManager* personal_data, + browser_sync::UnrecoverableErrorHandler* error_handler); +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_DATA_TYPE_CONTROLLER_H_ diff --git a/chrome/browser/sync/glue/autofill_profile_model_associator.cc b/chrome/browser/sync/glue/autofill_profile_model_associator.cc index 91027e3..b2d2e2c 100644 --- a/chrome/browser/sync/glue/autofill_profile_model_associator.cc +++ b/chrome/browser/sync/glue/autofill_profile_model_associator.cc @@ -5,13 +5,15 @@ #include "chrome/browser/sync/glue/autofill_profile_model_associator.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/sync/glue/autofill_profile_change_processor.h" +#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/webdata/web_database.h" using sync_api::ReadNode; namespace browser_sync { -const char kAutofillProfileTag[] = "google_chrome_autofill_profile"; +const char kAutofillProfileTag[] = "google_chrome_autofill_profiles"; AutofillProfileModelAssociator::AutofillProfileModelAssociator( ProfileSyncService* sync_service, @@ -21,7 +23,8 @@ AutofillProfileModelAssociator::AutofillProfileModelAssociator( web_database_(web_database), personal_data_(personal_data), autofill_node_id_(sync_api::kInvalidId), - abort_association_pending_(false) { + abort_association_pending_(false), + number_of_profiles_created_(0) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); DCHECK(sync_service_); DCHECK(web_database_); @@ -43,6 +46,24 @@ bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutoFillProfiles( std::vector<AutoFillProfile*>* new_profiles, std::vector<std::string>* profiles_to_delete) { + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "Printing profiles from web db"; + + for (std::vector<AutoFillProfile*>::const_iterator ix = + all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) { + AutoFillProfile* p = *ix; + VLOG(1) << "[AUTOFILL MIGRATION] " + << p->GetFieldText(AutoFillType(NAME_FIRST)) + << p->GetFieldText(AutoFillType(NAME_LAST)) + << p->guid(); + } + } + + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "Looking for the above data in sync db.."; + } // Alias the all_profiles_from_db so we fit in 80 characters const std::vector<AutoFillProfile*>& profiles(all_profiles_from_db); for (std::vector<AutoFillProfile*>::const_iterator ix = profiles.begin(); @@ -52,6 +73,14 @@ bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutoFillProfiles( ReadNode node(write_trans); if (node.InitByClientTagLookup(syncable::AUTOFILL_PROFILE, guid)) { + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << " Found in sync db: " + << (*ix)->GetFieldText(AutoFillType(NAME_FIRST)) + << (*ix)->GetFieldText(AutoFillType(NAME_LAST)) + << (*ix)->guid() + << " so associating"; + } const sync_pb::AutofillProfileSpecifics& autofill( node.GetAutofillProfileSpecifics()); if (OverwriteProfileWithServerData(*ix, autofill)) { @@ -68,7 +97,18 @@ bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutoFillProfiles( profiles_to_delete); } } + return true; +} +bool AutofillProfileModelAssociator::GetSyncIdForTaggedNode( + const std::string& tag, + int64* sync_id) { + sync_api::ReadTransaction trans( + sync_service_->backend()->GetUserShareHandle()); + sync_api::ReadNode sync_node(&trans); + if (!sync_node.InitByTagLookup(tag.c_str())) + return false; + *sync_id = sync_node.GetId(); return true; } @@ -98,6 +138,11 @@ bool AutofillProfileModelAssociator::AssociateModels() { return false; } + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << " Now associating to the new autofill profile model associator" + << " root node"; + } DataBundle bundle; { // The write transaction lock is held inside this block. @@ -127,12 +172,20 @@ bool AutofillProfileModelAssociator::AssociateModels() { return false; } - // TODO(lipalani) Bug 64111- split out the OptimisticRefreshTask - // into its own class - // from autofill_model_associator - // Will be done as part of the autofill_model_associator work. - // BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - // new DoOptimisticRefreshTask(personal_data_)); + if (sync_service_->backend()->GetAutofillMigrationState() != + syncable::MIGRATED) { + syncable::AutofillMigrationDebugInfo debug_info; + debug_info.autofill_profile_added_during_migration = + number_of_profiles_created_; + sync_service_->backend()->SetAutofillMigrationDebugInfo( + syncable::AutofillMigrationDebugInfo::PROFILES_ADDED, + debug_info); + sync_service()->backend()->SetAutofillMigrationState( + syncable::MIGRATED); + } + + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + new DoOptimisticRefreshForAutofill(personal_data_)); return true; } @@ -160,9 +213,7 @@ bool AutofillProfileModelAssociator::SyncModelHasUserCreatedNodes( sync_api::ReadNode node(&trans); - if (!node.InitByClientTagLookup( - syncable::AUTOFILL_PROFILE, - kAutofillProfileTag)) { + if (!node.InitByTagLookup(kAutofillProfileTag)) { LOG(ERROR) << "Sever did not create a top level node" << "Out of data server or autofill type not enabled"; return false; @@ -205,7 +256,7 @@ int64 AutofillProfileModelAssociator::FindSyncNodeWithProfile( while (sync_child_id != sync_api::kInvalidId) { ReadNode read_node(trans); AutoFillProfile p; - if (read_node.InitByIdLookup(sync_child_id)) { + if (!read_node.InitByIdLookup(sync_child_id)) { LOG(ERROR) << "unable to find the id given by getfirst child " << sync_child_id; return sync_api::kInvalidId; @@ -247,6 +298,14 @@ bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNodeIfNeeded( std::string guid = autofill_specifics.guid(); Associate(&guid, sync_node_id); current_profiles->insert(autofill_specifics.guid()); + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "Found in sync db but with a different guid: " + << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_FIRST))) + << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST))) + << "New guid " << autofill_specifics.guid() + << " so associating"; + } } else { sync_api::WriteNode node(trans); if (!node.InitUniqueByCreation( @@ -255,10 +314,18 @@ bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNodeIfNeeded( return false; } node.SetTitle(UTF8ToWide(profile.guid())); + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION]" + << "NOT Found in sync db " + << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_FIRST))) + << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST))) + << profile.guid() + << " so creating a new sync node."; + } + AutofillProfileChangeProcessor::WriteAutofillProfile(profile, &node); + current_profiles->insert(profile.guid()); + number_of_profiles_created_++; - // TODO(lipalani) -Bug 64111 This needs rewriting. This will be tackled - // when rewriting autofill change processor. - // AutofillChangeProcessor::WriteAutofillProfile(profile, &node); } return true; } @@ -269,6 +336,10 @@ bool AutofillProfileModelAssociator::TraverseAndAssociateAllSyncNodes( DataBundle* bundle) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION] " + << " Iterating over sync nodes of autofill profile root node"; + } int64 sync_child_id = autofill_root.GetFirstChildId(); while (sync_child_id != sync_api::kInvalidId) { ReadNode sync_child(write_trans); @@ -292,6 +363,14 @@ void AutofillProfileModelAssociator::AddNativeProfileIfNeeded( const sync_api::ReadNode& node) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION] " + << "Trying to lookup " + << profile.name_first() + << " " + << profile.name_last() + << " in the web db"; + } if (bundle->current_profiles.find(profile.guid()) == bundle->current_profiles.end()) { std::string guid(profile.guid()); @@ -299,6 +378,15 @@ void AutofillProfileModelAssociator::AddNativeProfileIfNeeded( AutoFillProfile* p = new AutoFillProfile(profile.guid()); OverwriteProfileWithServerData(p, profile); bundle->new_profiles.push_back(p); + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION] " + << " Did not find one so creating it on web db"; + } + } else { + if (MigrationLoggingEnabled()) { + VLOG(1) << "[AUTOFILL MIGRATION] " + << " Found it on web db. Moving on "; + } } } @@ -332,23 +420,12 @@ bool AutofillProfileModelAssociator::SaveChangesToWebData( return true; } -const std::string* AutofillProfileModelAssociator::GetChromeNodeFromSyncId( - int64 sync_id) { - return NULL; - } - bool AutofillProfileModelAssociator::InitSyncNodeFromChromeId( const std::string& node_id, sync_api::BaseNode* sync_node) { return false; } -bool AutofillProfileModelAssociator::GetSyncIdForTaggedNode( - const std::string& tag, - int64* sync_id) { - return false; -} - void AutofillProfileModelAssociator::Associate( const std::string* autofill, int64 sync_id) { @@ -381,10 +458,21 @@ void AutofillProfileModelAssociator::AbortAssociation() { abort_association_pending_ = true; } +const std::string* AutofillProfileModelAssociator::GetChromeNodeFromSyncId( + int64 sync_id) { + SyncIdToAutofillMap::const_iterator iter = id_map_inverse_.find(sync_id); + return iter == id_map_inverse_.end() ? NULL : &(iter->second); +} + bool AutofillProfileModelAssociator::IsAbortPending() { AutoLock lock(abort_association_pending_lock_); return abort_association_pending_; } +bool AutofillProfileModelAssociator::MigrationLoggingEnabled() { + // TODO(lipalani) enable logging via a command line flag. + return false; +} + } // namespace browser_sync diff --git a/chrome/browser/sync/glue/autofill_profile_model_associator.h b/chrome/browser/sync/glue/autofill_profile_model_associator.h index ad8af5c..f636b63 100644 --- a/chrome/browser/sync/glue/autofill_profile_model_associator.h +++ b/chrome/browser/sync/glue/autofill_profile_model_associator.h @@ -31,6 +31,8 @@ class WriteTransaction; namespace browser_sync { +extern const char kAutofillProfileTag[]; + class AutofillChangeProcessor; class UnrecoverableErrorHandler; @@ -94,6 +96,10 @@ class AutofillProfileModelAssociator // Returns sync service instance. ProfileSyncService* sync_service() { return sync_service_; } + static bool OverwriteProfileWithServerData( + AutoFillProfile* merge_into, + const sync_pb::AutofillProfileSpecifics& specifics); + protected: AutofillProfileModelAssociator(); bool TraverseAndAssociateChromeAutoFillProfiles( @@ -130,10 +136,6 @@ class AutofillProfileModelAssociator const sync_api::ReadNode& autofill_root, DataBundle* bundle); - static bool OverwriteProfileWithServerData( - AutoFillProfile* merge_into, - const sync_pb::AutofillProfileSpecifics& specifics); - private: typedef std::map<std::string, int64> AutofillToSyncIdMap; typedef std::map<int64, std::string> SyncIdToAutofillMap; @@ -161,6 +163,8 @@ class AutofillProfileModelAssociator const sync_api::BaseNode& autofill_root, const AutoFillProfile& profile); + bool MigrationLoggingEnabled(); + ProfileSyncService* sync_service_; WebDatabase* web_database_; PersonalDataManager* personal_data_; @@ -175,6 +179,8 @@ class AutofillProfileModelAssociator Lock abort_association_pending_lock_; bool abort_association_pending_; + int number_of_profiles_created_; + DISALLOW_COPY_AND_ASSIGN(AutofillProfileModelAssociator); }; @@ -189,3 +195,4 @@ struct AutofillProfileModelAssociator::DataBundle { } // namespace browser_sync #endif // CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_MODEL_ASSOCIATOR_H_ + diff --git a/chrome/browser/sync/glue/bookmark_change_processor.cc b/chrome/browser/sync/glue/bookmark_change_processor.cc index 80e02c3..ebc7f1f 100644 --- a/chrome/browser/sync/glue/bookmark_change_processor.cc +++ b/chrome/browser/sync/glue/bookmark_change_processor.cc @@ -1,7 +1,6 @@ // Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - #include "chrome/browser/sync/glue/bookmark_change_processor.h" #include <stack> @@ -9,6 +8,7 @@ #include "base/string16.h" #include "base/string_util.h" + #include "base/utf_string_conversions.h" #include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/browser_thread.h" @@ -451,6 +451,7 @@ const BookmarkNode* BookmarkChangeProcessor::CreateOrUpdateBookmarkNode( DLOG(WARNING) << "Could not find parent of node being added/updated." << " Node title: " << src->GetTitle() << ", parent id = " << src->GetParentId(); + return NULL; } int index = CalculateBookmarkModelInsertionIndex(parent, src); diff --git a/chrome/browser/sync/glue/bookmark_model_associator.cc b/chrome/browser/sync/glue/bookmark_model_associator.cc index 9e9fac7..dba6a21 100644 --- a/chrome/browser/sync/glue/bookmark_model_associator.cc +++ b/chrome/browser/sync/glue/bookmark_model_associator.cc @@ -14,6 +14,7 @@ #include "chrome/browser/browser_thread.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/engine/syncapi.h" +#include "chrome/browser/sync/syncable/autofill_migration.h" #include "chrome/browser/sync/glue/bookmark_change_processor.h" #include "chrome/browser/sync/profile_sync_service.h" @@ -159,7 +160,8 @@ BookmarkModelAssociator::BookmarkModelAssociator( UnrecoverableErrorHandler* persist_ids_error_handler) : sync_service_(sync_service), persist_ids_error_handler_(persist_ids_error_handler), - ALLOW_THIS_IN_INITIALIZER_LIST(persist_associations_(this)) { + ALLOW_THIS_IN_INITIALIZER_LIST(persist_associations_(this)), + number_of_new_sync_nodes_created_at_association_(0) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(sync_service_); DCHECK(persist_ids_error_handler_); @@ -413,8 +415,19 @@ bool BookmarkModelAssociator::BuildAssociations() { parent_node, model, i, &trans, this, sync_service_); if (parent_node->GetChild(i)->is_folder()) dfs_stack.push(sync_child_id); + number_of_new_sync_nodes_created_at_association_++; } } + + if (sync_service_->backend()->GetAutofillMigrationState() != + syncable::MIGRATED) { + syncable::AutofillMigrationDebugInfo debug_info; + debug_info.bookmarks_added_during_migration = + number_of_new_sync_nodes_created_at_association_; + sync_service_->backend()->SetAutofillMigrationDebugInfo( + syncable::AutofillMigrationDebugInfo::BOOKMARK_ADDED, + debug_info); + } return true; } diff --git a/chrome/browser/sync/glue/bookmark_model_associator.h b/chrome/browser/sync/glue/bookmark_model_associator.h index 37b8e35..577979f 100644 --- a/chrome/browser/sync/glue/bookmark_model_associator.h +++ b/chrome/browser/sync/glue/bookmark_model_associator.h @@ -135,6 +135,8 @@ class BookmarkModelAssociator // allows this class to be non-refcounted). ScopedRunnableMethodFactory<BookmarkModelAssociator> persist_associations_; + int number_of_new_sync_nodes_created_at_association_; + DISALLOW_COPY_AND_ASSIGN(BookmarkModelAssociator); }; diff --git a/chrome/browser/sync/glue/data_type_manager_impl.cc b/chrome/browser/sync/glue/data_type_manager_impl.cc index af980fa..119a616 100644 --- a/chrome/browser/sync/glue/data_type_manager_impl.cc +++ b/chrome/browser/sync/glue/data_type_manager_impl.cc @@ -23,6 +23,7 @@ static const syncable::ModelType kStartOrder[] = { syncable::BOOKMARKS, syncable::PREFERENCES, syncable::AUTOFILL, + syncable::AUTOFILL_PROFILE, syncable::THEMES, syncable::TYPED_URLS, syncable::PASSWORDS, diff --git a/chrome/browser/sync/glue/do_optimistic_refresh_task.cc b/chrome/browser/sync/glue/do_optimistic_refresh_task.cc new file mode 100644 index 0000000..654fed2 --- /dev/null +++ b/chrome/browser/sync/glue/do_optimistic_refresh_task.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
+
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/browser_thread.h"
+
+namespace browser_sync {
+
+DoOptimisticRefreshForAutofill::DoOptimisticRefreshForAutofill(
+ PersonalDataManager* pdm) : pdm_(pdm) {}
+
+DoOptimisticRefreshForAutofill::~DoOptimisticRefreshForAutofill() {}
+
+void DoOptimisticRefreshForAutofill::Run() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ pdm_->Refresh();
+}
+
+} // namespace browser_sync
+
diff --git a/chrome/browser/sync/glue/do_optimistic_refresh_task.h b/chrome/browser/sync/glue/do_optimistic_refresh_task.h new file mode 100644 index 0000000..f98d436 --- /dev/null +++ b/chrome/browser/sync/glue/do_optimistic_refresh_task.h @@ -0,0 +1,26 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef CHROME_BROWSER_SYNC_GLUE_DO_OPTIMISTIC_REFRESH_TASK_H_
+#define CHROME_BROWSER_SYNC_GLUE_DO_OPTIMISTIC_REFRESH_TASK_H_
+#pragma once
+
+#include "base/ref_counted.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+
+namespace browser_sync {
+
+// A task used by this class and the change processor to inform the
+// PersonalDataManager living on the UI thread that it needs to refresh.
+class DoOptimisticRefreshForAutofill : public Task {
+ public:
+ explicit DoOptimisticRefreshForAutofill(PersonalDataManager* pdm);
+ virtual ~DoOptimisticRefreshForAutofill();
+ virtual void Run();
+ private:
+ scoped_refptr<PersonalDataManager> pdm_;
+};
+
+} // namespace browser_sync
+#endif // CHROME_BROWSER_SYNC_GLUE_DO_OPTIMISTIC_REFRESH_TASK_H_
+
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc index fb63ce5..4dafe24 100644 --- a/chrome/browser/sync/glue/sync_backend_host.cc +++ b/chrome/browser/sync/glue/sync_backend_host.cc @@ -15,6 +15,8 @@ #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/engine/syncapi.h" +#include "chrome/browser/sync/glue/autofill_model_associator.h" +#include "chrome/browser/sync/glue/autofill_profile_model_associator.h" #include "chrome/browser/sync/glue/change_processor.h" #include "chrome/browser/sync/glue/database_model_worker.h" #include "chrome/browser/sync/glue/history_model_worker.h" @@ -24,6 +26,7 @@ #include "chrome/browser/sync/sessions/session_state.h" // TODO(tim): Remove this! We should have a syncapi pass-thru instead. #include "chrome/browser/sync/syncable/directory_manager.h" // Cryptographer. +#include "chrome/browser/sync/syncable/model_type.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_version_info.h" #include "chrome/common/net/gaia/gaia_constants.h" @@ -251,12 +254,73 @@ void SyncBackendHost::Shutdown(bool sync_disabled) { core_ = NULL; // Releases reference to core_. } +syncable::AutofillMigrationState + SyncBackendHost::GetAutofillMigrationState() { + return core_->syncapi()->GetAutofillMigrationState(); +} + +void SyncBackendHost::SetAutofillMigrationState( + syncable::AutofillMigrationState state) { + return core_->syncapi()->SetAutofillMigrationState(state); +} + +syncable::AutofillMigrationDebugInfo + SyncBackendHost::GetAutofillMigrationDebugInfo() { + return core_->syncapi()->GetAutofillMigrationDebugInfo(); +} + +void SyncBackendHost::SetAutofillMigrationDebugInfo( + syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set, + const syncable::AutofillMigrationDebugInfo& info) { + return core_->syncapi()->SetAutofillMigrationDebugInfo(property_to_set, info); +} + +void SyncBackendHost::ConfigureAutofillMigration() { + if (GetAutofillMigrationState() == syncable::NOT_DETERMINED) { + sync_api::ReadTransaction trans(GetUserShareHandle()); + sync_api::ReadNode autofil_root_node(&trans); + + // Check for the presence of autofill node. + if (!autofil_root_node.InitByTagLookup(browser_sync::kAutofillTag)) { + SetAutofillMigrationState(syncable::INSUFFICIENT_INFO_TO_DETERMINE); + return; + } + + // Check for children under autofill node. + if (autofil_root_node.GetFirstChildId() == static_cast<int64>(0)) { + SetAutofillMigrationState(syncable::INSUFFICIENT_INFO_TO_DETERMINE); + return; + } + + sync_api::ReadNode autofill_profile_root_node(&trans); + + // Check for the presence of autofill profile root node. + if (!autofill_profile_root_node.InitByTagLookup( + browser_sync::kAutofillProfileTag)) { + SetAutofillMigrationState(syncable::NOT_MIGRATED); + return; + } + + // If our state is not determined then we should not have the autofill + // profile node. + DCHECK(false); + + // just set it as not migrated. + SetAutofillMigrationState(syncable::NOT_MIGRATED); + return; + } +} + void SyncBackendHost::ConfigureDataTypes(const syncable::ModelTypeSet& types, CancelableTask* ready_task) { // Only one configure is allowed at a time. DCHECK(!configure_ready_task_.get()); DCHECK(syncapi_initialized_); + if (types.count(syncable::AUTOFILL_PROFILE) != 0) { + ConfigureAutofillMigration(); + } + bool deleted_type = false; { diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h index 3edd648..fdfc7b4 100644 --- a/chrome/browser/sync/glue/sync_backend_host.h +++ b/chrome/browser/sync/glue/sync_backend_host.h @@ -142,6 +142,19 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar { virtual void ConfigureDataTypes(const syncable::ModelTypeSet& types, CancelableTask* ready_task); + syncable::AutofillMigrationState + GetAutofillMigrationState(); + + void SetAutofillMigrationState( + syncable::AutofillMigrationState state); + + syncable::AutofillMigrationDebugInfo + GetAutofillMigrationDebugInfo(); + + void SetAutofillMigrationDebugInfo( + syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set, + const syncable::AutofillMigrationDebugInfo& info); + // Activates change processing for the given data type. This must // be called synchronously with the data type's model association so // no changes are dropped between model association and change @@ -445,6 +458,8 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar { UIModelWorker* ui_worker(); + void ConfigureAutofillMigration(); + // A thread we dedicate for use by our Core to perform initialization, // authentication, handle messages from the syncapi, and periodically tell // the syncapi to persist itself. diff --git a/chrome/browser/sync/profile_sync_factory.h b/chrome/browser/sync/profile_sync_factory.h index a4a2550..776b61d 100644 --- a/chrome/browser/sync/profile_sync_factory.h +++ b/chrome/browser/sync/profile_sync_factory.h @@ -77,6 +77,15 @@ class ProfileSyncFactory { browser_sync::UnrecoverableErrorHandler* error_handler) = 0; // Instantiates both a model associator and change processor for the + // autofill data type. The pointers in the return struct are owned + // by the caller. + virtual SyncComponents CreateAutofillProfileSyncComponents( + ProfileSyncService* profile_sync_service, + WebDatabase* web_database, + PersonalDataManager* personal_data, + browser_sync::UnrecoverableErrorHandler* error_handler) = 0; + + // Instantiates both a model associator and change processor for the // bookmark data type. The pointers in the return struct are owned // by the caller. virtual SyncComponents CreateBookmarkSyncComponents( diff --git a/chrome/browser/sync/profile_sync_factory_impl.cc b/chrome/browser/sync/profile_sync_factory_impl.cc index a763a4c..07c1145 100644 --- a/chrome/browser/sync/profile_sync_factory_impl.cc +++ b/chrome/browser/sync/profile_sync_factory_impl.cc @@ -10,6 +10,9 @@ #include "chrome/browser/sync/glue/autofill_data_type_controller.h" #include "chrome/browser/sync/glue/autofill_model_associator.h" #include "chrome/browser/sync/glue/autofill_model_associator2.h" +#include "chrome/browser/sync/glue/autofill_profile_change_processor.h" +#include "chrome/browser/sync/glue/autofill_profile_data_type_controller.h" +#include "chrome/browser/sync/glue/autofill_profile_model_associator.h" #include "chrome/browser/sync/glue/bookmark_change_processor.h" #include "chrome/browser/sync/glue/bookmark_data_type_controller.h" #include "chrome/browser/sync/glue/bookmark_model_associator.h" @@ -38,13 +41,17 @@ #include "chrome/browser/sync/profile_sync_factory_impl.h" #include "chrome/browser/webdata/web_data_service.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" using browser_sync::AppDataTypeController; using browser_sync::AutofillChangeProcessor; using browser_sync::AutofillChangeProcessor2; +using browser_sync::AutofillProfileChangeProcessor; using browser_sync::AutofillDataTypeController; +using browser_sync::AutofillProfileDataTypeController; using browser_sync::AutofillModelAssociator; using browser_sync::AutofillModelAssociator2; +using browser_sync::AutofillProfileModelAssociator; using browser_sync::BookmarkChangeProcessor; using browser_sync::BookmarkDataTypeController; using browser_sync::BookmarkModelAssociator; @@ -145,6 +152,12 @@ ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService( pss->RegisterDataTypeController( new SessionDataTypeController(this, pss)); } + + if (!command_line_->HasSwitch(switches::kDisableSyncAutofillProfile) && + command_line_->HasSwitch(switches::kEnableSyncNewAutofill)) { + pss->RegisterDataTypeController(new AutofillProfileDataTypeController( + this, profile_, pss)); + } return pss; } @@ -202,6 +215,25 @@ ProfileSyncFactoryImpl::CreateAutofillSyncComponents( } ProfileSyncFactory::SyncComponents +ProfileSyncFactoryImpl::CreateAutofillProfileSyncComponents( + ProfileSyncService* profile_sync_service, + WebDatabase* web_database, + PersonalDataManager* personal_data, + browser_sync::UnrecoverableErrorHandler* error_handler) { + + AutofillProfileModelAssociator* model_associator = + new AutofillProfileModelAssociator(profile_sync_service, + web_database, + personal_data); + AutofillProfileChangeProcessor* change_processor = + new AutofillProfileChangeProcessor(model_associator, + web_database, + personal_data, + error_handler); + return SyncComponents(model_associator, change_processor); +} + +ProfileSyncFactory::SyncComponents ProfileSyncFactoryImpl::CreateBookmarkSyncComponents( ProfileSyncService* profile_sync_service, UnrecoverableErrorHandler* error_handler) { diff --git a/chrome/browser/sync/profile_sync_factory_impl.h b/chrome/browser/sync/profile_sync_factory_impl.h index 233f3f1..eb93f1c 100644 --- a/chrome/browser/sync/profile_sync_factory_impl.h +++ b/chrome/browser/sync/profile_sync_factory_impl.h @@ -37,6 +37,12 @@ class ProfileSyncFactoryImpl : public ProfileSyncFactory { PersonalDataManager* personal_data, browser_sync::UnrecoverableErrorHandler* error_handler); + virtual SyncComponents CreateAutofillProfileSyncComponents( + ProfileSyncService* profile_sync_service, + WebDatabase* web_database, + PersonalDataManager* personal_data, + browser_sync::UnrecoverableErrorHandler* error_handler); + virtual SyncComponents CreateBookmarkSyncComponents( ProfileSyncService* profile_sync_service, browser_sync::UnrecoverableErrorHandler* error_handler); diff --git a/chrome/browser/sync/profile_sync_factory_mock.h b/chrome/browser/sync/profile_sync_factory_mock.h index 18cc30c..f5210a0 100644 --- a/chrome/browser/sync/profile_sync_factory_mock.h +++ b/chrome/browser/sync/profile_sync_factory_mock.h @@ -38,6 +38,12 @@ class ProfileSyncFactoryMock : public ProfileSyncFactory { WebDatabase* web_database, PersonalDataManager* personal_data, browser_sync::UnrecoverableErrorHandler* error_handler)); + MOCK_METHOD4(CreateAutofillProfileSyncComponents, + SyncComponents( + ProfileSyncService* profile_sync_service, + WebDatabase* web_database, + PersonalDataManager* personal_data, + browser_sync::UnrecoverableErrorHandler* error_handler)); MOCK_METHOD2(CreateBookmarkSyncComponents, SyncComponents(ProfileSyncService* profile_sync_service, browser_sync::UnrecoverableErrorHandler* error_handler)); diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index fb2473f..eac1026 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -24,6 +24,7 @@ #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/net/gaia/token_service.h" +#include "chrome/browser/sync/glue/autofill_profile_data_type_controller.h" #include "chrome/browser/sync/glue/change_processor.h" #include "chrome/browser/sync/glue/data_type_controller.h" #include "chrome/browser/sync/glue/data_type_manager.h" @@ -367,6 +368,9 @@ void ProfileSyncService::RegisterPreferences() { enable_by_default); pref_service->RegisterBooleanPref(prefs::kSyncManaged, false); pref_service->RegisterStringPref(prefs::kEncryptionBootstrapToken, ""); + + pref_service->RegisterBooleanPref(prefs::kSyncAutofillProfile, + enable_by_default); } void ProfileSyncService::ClearPreferences() { @@ -549,6 +553,9 @@ const char* ProfileSyncService::GetPrefNameForDataType( return prefs::kSyncPreferences; case syncable::AUTOFILL: return prefs::kSyncAutofill; + case syncable::AUTOFILL_PROFILE: + return prefs::kSyncAutofillProfile; + break; case syncable::THEMES: return prefs::kSyncThemes; case syncable::TYPED_URLS: @@ -882,6 +889,10 @@ void ProfileSyncService::ChangePreferredDataTypes( continue; profile_->GetPrefs()->SetBoolean(pref_name, preferred_types.count(model_type) != 0); + if (syncable::AUTOFILL == model_type) { + profile_->GetPrefs()->SetBoolean(prefs::kSyncAutofillProfile, + preferred_types.count(model_type) != 0); + } } // If we haven't initialized yet, don't configure the DTM as it could cause @@ -893,23 +904,33 @@ void ProfileSyncService::ChangePreferredDataTypes( void ProfileSyncService::GetPreferredDataTypes( syncable::ModelTypeSet* preferred_types) const { preferred_types->clear(); - - // Filter out any datatypes which aren't registered, or for which - // the preference can't be read. - syncable::ModelTypeSet registered_types; - GetRegisteredDataTypes(®istered_types); if (profile_->GetPrefs()->GetBoolean(prefs::kKeepEverythingSynced)) { - *preferred_types = registered_types; + GetRegisteredDataTypes(preferred_types); } else { + // Filter out any datatypes which aren't registered, or for which + // the preference can't be read. + syncable::ModelTypeSet registered_types; + GetRegisteredDataTypes(®istered_types); for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) { syncable::ModelType model_type = syncable::ModelTypeFromInt(i); if (!registered_types.count(model_type)) continue; + if (model_type == syncable::AUTOFILL_PROFILE) + continue; const char* pref_name = GetPrefNameForDataType(model_type); if (!pref_name) continue; - if (profile_->GetPrefs()->GetBoolean(pref_name)) + + // We are trying to group autofill_profile tag with the same + // enabled/disabled state as autofill. Because the UI only shows autofill. + if (profile_->GetPrefs()->GetBoolean(pref_name)) { preferred_types->insert(model_type); + if (model_type == syncable::AUTOFILL) { + if (!registered_types.count(syncable::AUTOFILL_PROFILE)) + continue; + preferred_types->insert(syncable::AUTOFILL_PROFILE); + } + } } } } diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc index 2b20eda..30a4ed4 100644 --- a/chrome/browser/sync/sync_ui_util.cc +++ b/chrome/browser/sync/sync_ui_util.cc @@ -6,6 +6,8 @@ #include "app/l10n_util.h" #include "base/i18n/number_formatting.h" +#include "base/i18n/time_formatting.h" +#include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/profile_sync_service.h" @@ -215,6 +217,15 @@ void AddIntSyncDetail(ListValue* details, const std::string& stat_name, details->Append(val); } +std::wstring ConstructTime(int64 time_in_int) { + base::Time time = base::Time::FromInternalValue(time_in_int); + + // If time is null the format function returns a time in 1969. + if (time.is_null()) + return std::wstring(); + return base::TimeFormatFriendlyDateAndTime(time); +} + std::string MakeSyncAuthErrorText( const GoogleServiceAuthError::State& state) { switch (state) { @@ -323,6 +334,30 @@ void ConstructAboutInformation(ProfileSyncService* service, val->SetString("group", ModelSafeGroupToString(it->second)); routing_info->Append(val); } + + sync_ui_util::AddBoolSyncDetail(details, + "Autofill Migrated", + service->backend()->GetAutofillMigrationState() == + syncable::MIGRATED); + syncable::AutofillMigrationDebugInfo info = + service->backend()->GetAutofillMigrationDebugInfo(); + + sync_ui_util::AddIntSyncDetail(details, + "Bookmarks created during migration", + info.bookmarks_added_during_migration); + sync_ui_util::AddIntSyncDetail(details, + "Autofill entries created during migration", + info.autofill_entries_added_during_migration); + sync_ui_util::AddIntSyncDetail(details, + "Autofill Profiles created during migration", + info.autofill_profile_added_during_migration); + + DictionaryValue* val = new DictionaryValue; + val->SetString("stat_name", "Autofill Migration Time"); + val->SetString("stat_value", + WideToUTF16Hack( + ConstructTime(info.autofill_migration_time))); + details->Append(val); } } } diff --git a/chrome/browser/sync/syncable/autofill_migration.h b/chrome/browser/sync/syncable/autofill_migration.h new file mode 100644 index 0000000..81a16be --- /dev/null +++ b/chrome/browser/sync/syncable/autofill_migration.h @@ -0,0 +1,49 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SYNC_SYNCABLE_AUTOFILL_MIGRATION_H_ +#define CHROME_BROWSER_SYNC_SYNCABLE_AUTOFILL_MIGRATION_H_ +#pragma once + +namespace syncable { +enum AutofillMigrationState { + + // Indicates the default state. After first run the state would change to + // one of the following. + NOT_DETERMINED, + + // The autofill profile is not migrated. Current sync should migrate the data + // by syncing down the old autofill and syncing profiles back up to the server + // as new autofill. + NOT_MIGRATED, + + // We have migrated the autofill profile data. From now on autofill and + // autofill profiles are 2 seperate data types. + MIGRATED, + + // The autofill datatype is being synced new.(either because this is a new + // client or the user just enabled them for syncing). In which case if + // someother client had migrated the data already then our new state after + // first sync would be MIGRATED. Else we would be responsible for migrating + // the data. + INSUFFICIENT_INFO_TO_DETERMINE +}; + +struct AutofillMigrationDebugInfo { + enum PropertyToSet { + MIGRATION_TIME, + BOOKMARK_ADDED, + ENTRIES_ADDED, + PROFILES_ADDED + }; + int64 autofill_migration_time; + int bookmarks_added_during_migration; + int autofill_entries_added_during_migration; + int autofill_profile_added_during_migration; +}; + +} // namespace syncable + +#endif // CHROME_BROWSER_SYNC_SYNCABLE_AUTOFILL_MIGRATION_H_ + diff --git a/chrome/browser/sync/syncable/directory_backing_store.cc b/chrome/browser/sync/syncable/directory_backing_store.cc index c0036d3..feefd91 100644 --- a/chrome/browser/sync/syncable/directory_backing_store.cc +++ b/chrome/browser/sync/syncable/directory_backing_store.cc @@ -44,7 +44,7 @@ static const string::size_type kUpdateStatementBufferSize = 2048; // Increment this version whenever updating DB tables. extern const int32 kCurrentDBVersion; // Global visibility for our unittest. -const int32 kCurrentDBVersion = 73; +const int32 kCurrentDBVersion = 74; namespace { @@ -379,11 +379,28 @@ bool DirectoryBackingStore::SaveChanges( update.prepare(dbhandle, "UPDATE share_info " "SET store_birthday = ?, " "next_id = ?, " - "notification_state = ?"); + "notification_state = ?, " + "autofill_migration_state = ?, " + "bookmarks_added_during_autofill_migration = ?, " + "autofill_migration_time = ?, " + "autofill_entries_added_during_migration = ?, " + "autofill_profiles_added_during_migration = ? "); + + const syncable::AutofillMigrationDebugInfo& debug_info = + info.autofill_migration_debug_info; update.bind_string(0, info.store_birthday); update.bind_int64(1, info.next_id); update.bind_blob(2, info.notification_state.data(), info.notification_state.size()); + update.bind_int(3, info.autofill_migration_state); + update.bind_int(4, + debug_info.bookmarks_added_during_migration); + update.bind_int64(5, + debug_info.autofill_migration_time); + update.bind_int(6, + debug_info.autofill_entries_added_during_migration); + update.bind_int(7, + debug_info.autofill_profile_added_during_migration); if (!(SQLITE_DONE == update.step() && SQLITE_OK == update.reset() && @@ -456,6 +473,11 @@ DirOpenResult DirectoryBackingStore::InitializeTables() { version_on_disk = 73; } + if (version_on_disk == 73) { + if (MigrateVersion73To74()) + version_on_disk = 74; + } + // If one of the migrations requested it, drop columns that aren't current. // It's only safe to do this after migrating all the way to the current // version. @@ -556,13 +578,30 @@ bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) { SQLStatement query; query.prepare(load_dbhandle_, "SELECT store_birthday, next_id, cache_guid, " - "notification_state FROM share_info"); + "notification_state, autofill_migration_state, " + "bookmarks_added_during_autofill_migration, " + "autofill_migration_time, " + "autofill_entries_added_during_migration, " + "autofill_profiles_added_during_migration " + "FROM share_info"); if (SQLITE_ROW != query.step()) return false; info->kernel_info.store_birthday = query.column_string(0); info->kernel_info.next_id = query.column_int64(1); info->cache_guid = query.column_string(2); query.column_blob_as_string(3, &info->kernel_info.notification_state); + info->kernel_info.autofill_migration_state = + static_cast<AutofillMigrationState> (query.column_int(4)); + syncable::AutofillMigrationDebugInfo& debug_info = + info->kernel_info.autofill_migration_debug_info; + debug_info.bookmarks_added_during_migration = + query.column_int(5); + debug_info.autofill_migration_time = + query.column_int64(6); + debug_info.autofill_entries_added_during_migration = + query.column_int(7); + debug_info.autofill_profile_added_during_migration = + query.column_int(8); } { SQLStatement query; @@ -889,9 +928,9 @@ bool DirectoryBackingStore::MigrateVersion70To71() { // Drop the columns from the old share_info table via a temp table. const bool kCreateAsTempShareInfo = true; - const bool kWithNotificationState = false; + int result = - CreateShareInfoTable(kCreateAsTempShareInfo, kWithNotificationState); + CreateShareInfoTableVersion71(kCreateAsTempShareInfo); if (result != SQLITE_DONE) return false; ExecQuery(load_dbhandle_, @@ -926,6 +965,50 @@ bool DirectoryBackingStore::MigrateVersion72To73() { return true; } +bool DirectoryBackingStore::MigrateVersion73To74() { + int result = + ExecQuery(load_dbhandle_, + "ALTER TABLE share_info ADD COLUMN autofill_migration_state " + "INT default 0"); + if (result != SQLITE_DONE) + return false; + + result = ExecQuery(load_dbhandle_, + "ALTER TABLE share_info ADD COLUMN " + "bookmarks_added_during_autofill_migration " + "INT default 0"); + + if (result != SQLITE_DONE) + return false; + + result = ExecQuery(load_dbhandle_, + "ALTER TABLE share_info ADD COLUMN autofill_migration_time " + "INT default 0"); + + if (result != SQLITE_DONE) + return false; + + result = ExecQuery(load_dbhandle_, + "ALTER TABLE share_info ADD COLUMN " + "autofill_entries_added_during_migration " + "INT default 0"); + + if (result != SQLITE_DONE) + return false; + + result = ExecQuery(load_dbhandle_, + "ALTER TABLE share_info ADD COLUMN " + "autofill_profiles_added_during_migration " + "INT default 0"); + + if (result != SQLITE_DONE) + return false; + + SetVersion(74); + return true; +} + + int DirectoryBackingStore::CreateTables() { VLOG(1) << "First run, creating tables"; // Create two little tables share_version and share_info @@ -945,9 +1028,8 @@ int DirectoryBackingStore::CreateTables() { return result; const bool kCreateAsTempShareInfo = false; - const bool kWithNotificationState = true; result = - CreateShareInfoTable(kCreateAsTempShareInfo, kWithNotificationState); + CreateShareInfoTable(kCreateAsTempShareInfo); if (result != SQLITE_DONE) return result; { @@ -960,6 +1042,14 @@ int DirectoryBackingStore::CreateTables() { "?, " // db_create_time "-2, " // next_id "?, " // cache_guid + "?, " // autofill_migration_state + "?, " // bookmarks_added + // _during_autofill_migration + "?, " // autofill_migration_time + "?, " // autofill_entries + // _added_during_migration + "?, " // autofill_profiles_added + // _during_migration "?);"); // notification_state statement.bind_string(0, dir_name_); // id statement.bind_string(1, dir_name_); // name @@ -967,7 +1057,12 @@ int DirectoryBackingStore::CreateTables() { statement.bind_string(3, SYNC_ENGINE_VERSION_STRING); // db_create_version statement.bind_int(4, static_cast<int32>(time(0))); // db_create_time statement.bind_string(5, GenerateCacheGUID()); // cache_guid - statement.bind_blob(6, NULL, 0); // notification_state + statement.bind_int(6, 0); // autofill_migration_state + statement.bind_int(7, 0); // autofill_migration_time + statement.bind_int(8, 0); // bookmarks_added_during_autofill_migration + statement.bind_int(9, 0); // autofill_entries_added_during_migration + statement.bind_int(10, 0); // autofill_profiles_added_during_migration + statement.bind_blob(11, NULL, 0); // notification_state result = statement.step(); } if (result != SQLITE_DONE) @@ -1025,8 +1120,7 @@ int DirectoryBackingStore::CreateModelsTable() { "initial_sync_ended BOOLEAN default 0)"); } -int DirectoryBackingStore::CreateShareInfoTable( - bool is_temporary, bool with_notification_state) { +int DirectoryBackingStore::CreateShareInfoTable(bool is_temporary) { const char* name = is_temporary ? "temp_share_info" : "share_info"; string query = "CREATE TABLE "; query.append(name); @@ -1040,12 +1134,34 @@ int DirectoryBackingStore::CreateShareInfoTable( "db_create_version TEXT, " "db_create_time INT, " "next_id INT default -2, " - "cache_guid TEXT"); - if (with_notification_state) { - query.append(", notification_state BLOB"); - } + "cache_guid TEXT, " + "autofill_migration_state INT default 0, " + "bookmarks_added_during_autofill_migration INT default 0, " + "autofill_migration_time INT default 0, " + "autofill_entries_added_during_migration INT default 0, " + "autofill_profiles_added_during_migration INT default 0 "); + + query.append(", notification_state BLOB"); query.append(")"); return ExecQuery(load_dbhandle_, query.c_str()); } +int DirectoryBackingStore::CreateShareInfoTableVersion71( + bool is_temporary) { + const char* name = is_temporary ? "temp_share_info" : "share_info"; + string query = "CREATE TABLE "; + query.append(name); + // This is the current schema for the ShareInfo table, from version 71 + // onward. If you change the schema, you'll probably want to double-check + // the use of this function in the v70-v71 migration. + query.append(" (" + "id TEXT primary key, " + "name TEXT, " + "store_birthday TEXT, " + "db_create_version TEXT, " + "db_create_time INT, " + "next_id INT default -2, " + "cache_guid TEXT )"); + return ExecQuery(load_dbhandle_, query.c_str()); +} } // namespace syncable diff --git a/chrome/browser/sync/syncable/directory_backing_store.h b/chrome/browser/sync/syncable/directory_backing_store.h index f1a09dd..45187e7 100644 --- a/chrome/browser/sync/syncable/directory_backing_store.h +++ b/chrome/browser/sync/syncable/directory_backing_store.h @@ -80,6 +80,7 @@ class DirectoryBackingStore { FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion70To71); FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion71To72); FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion72To73); + FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion73To74); FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, ModelTypeIds); FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, Corruption); FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, DeleteEntries); @@ -92,10 +93,11 @@ class DirectoryBackingStore { int CreateTables(); // Create 'share_info' or 'temp_share_info' depending on value of - // is_temporary. If with_notification_state is true, creates the - // table with the notification_state column. Returns an sqlite + // is_temporary. Returns an sqlite // return code, SQLITE_DONE on success. - int CreateShareInfoTable(bool is_temporary, bool with_notification_state); + int CreateShareInfoTable(bool is_temporary); + + int CreateShareInfoTableVersion71(bool is_temporary); // Create 'metas' or 'temp_metas' depending on value of is_temporary. // Returns an sqlite return code, SQLITE_DONE on success. int CreateMetasTable(bool is_temporary); @@ -172,6 +174,7 @@ class DirectoryBackingStore { bool MigrateVersion70To71(); bool MigrateVersion71To72(); bool MigrateVersion72To73(); + bool MigrateVersion73To74(); // The handle to our sqlite on-disk store for initialization and loading, and // for saving changes periodically via SaveChanges, respectively. diff --git a/chrome/browser/sync/syncable/directory_backing_store_unittest.cc b/chrome/browser/sync/syncable/directory_backing_store_unittest.cc index 214690c..d80200f 100644 --- a/chrome/browser/sync/syncable/directory_backing_store_unittest.cc +++ b/chrome/browser/sync/syncable/directory_backing_store_unittest.cc @@ -48,6 +48,7 @@ class MigrationTest : public testing::TestWithParam<int> { void SetUpVersion70Database(); void SetUpVersion71Database(); void SetUpVersion72Database(); + void SetUpVersion73Database(); void SetUpCurrentDatabaseAndCheckVersion() { SetUpVersion70Database(); // Prepopulates data. @@ -643,7 +644,7 @@ void MigrationTest::SetUpVersion72Database() { ASSERT_TRUE(connection.BeginTransaction()); ASSERT_TRUE(connection.Execute( "CREATE TABLE share_version (id VARCHAR(128) primary key, data INT);" - "INSERT INTO 'share_version' VALUES('nick@chromium.org',71);" + "INSERT INTO 'share_version' VALUES('nick@chromium.org',72);" "CREATE TABLE metas(metahandle bigint primary key ON CONFLICT FAIL," "base_version bigint default -1,server_version bigint default 0," "mtime bigint default 0,server_mtime bigint default 0,ctime bigint " @@ -741,6 +742,111 @@ void MigrationTest::SetUpVersion72Database() { ASSERT_TRUE(connection.CommitTransaction()); } +void MigrationTest::SetUpVersion73Database() { + sql::Connection connection; + ASSERT_TRUE(connection.Open(GetDatabasePath())); + ASSERT_TRUE(connection.BeginTransaction()); + ASSERT_TRUE(connection.Execute( + "CREATE TABLE share_version (id VARCHAR(128) primary key, data INT);" + "INSERT INTO 'share_version' VALUES('nick@chromium.org',73);" + "CREATE TABLE metas(metahandle bigint primary key ON CONFLICT FAIL," + "base_version bigint default -1,server_version bigint default 0," + "mtime bigint default 0,server_mtime bigint default 0,ctime bigint " + "default 0,server_ctime bigint default 0,server_position_in_parent " + "bigint default 0,local_external_id bigint default 0,id varchar(255) " + "default 'r',parent_id varchar(255) default 'r',server_parent_id " + "varchar(255) default 'r',prev_id varchar(255) default 'r',next_id " + "varchar(255) default 'r',is_unsynced bit default 0," + "is_unapplied_update bit default 0,is_del bit default 0,is_dir bit " + "default 0,server_is_dir bit default 0,server_is_del bit default 0," + "non_unique_name varchar,server_non_unique_name varchar(255)," + "unique_server_tag varchar,unique_client_tag varchar,specifics blob," + "server_specifics blob);" + "INSERT INTO 'metas' VALUES(1,-1,0,129079956640320000,0," + "129079956640320000,0,0,0,'r','r','r','r','r',0,0,0,1,0,0,NULL,NULL," + "NULL,NULL,X'',X'');" + "INSERT INTO 'metas' VALUES(2,669,669,128976886618480000," + "128976886618480000,128976886618480000,128976886618480000,-2097152,4," + "'s_ID_2','s_ID_9','s_ID_9','s_ID_2','s_ID_2',0,0,1,0,0,1," + "'Deleted Item','Deleted Item',NULL,NULL,X'C28810220A16687474703A2F2F" + "7777772E676F6F676C652E636F6D2F12084141534741534741',X'C28810260A1768" + "7474703A2F2F7777772E676F6F676C652E636F6D2F32120B41534144474144474144" + "47');" + "INSERT INTO 'metas' VALUES(4,681,681,129002163642690000," + "129002163642690000,129002163642690000,129002163642690000,-3145728,3," + "'s_ID_4','s_ID_9','s_ID_9','s_ID_4','s_ID_4',0,0,1,0,0,1," + "'Welcome to Chromium','Welcome to Chromium',NULL,NULL,X'C28810350A31" + "687474703A2F2F7777772E676F6F676C652E636F6D2F6368726F6D652F696E746C2F" + "656E2F77656C636F6D652E68746D6C1200',X'C28810350A31687474703A2F2F7777" + "772E676F6F676C652E636F6D2F6368726F6D652F696E746C2F656E2F77656C636F6D" + "652E68746D6C1200');" + "INSERT INTO 'metas' VALUES(5,677,677,129001555500000000," + "129001555500000000,129001555500000000,129001555500000000,1048576,7," + "'s_ID_5','s_ID_9','s_ID_9','s_ID_5','s_ID_5',0,0,1,0,0,1,'Google'," + "'Google',NULL,NULL,X'C28810220A16687474703A2F2F7777772E676F6F676C652" + "E636F6D2F12084147415347415347',X'C28810220A16687474703A2F2F7777772E6" + "76F6F676C652E636F6D2F12084147464447415347');" + "INSERT INTO 'metas' VALUES(6,694,694,129053976170000000," + "129053976170000000,129053976170000000,129053976170000000,-4194304,6," + "'s_ID_6','s_ID_9','s_ID_9','r','r',0,0,0,1,1,0,'The Internet'," + "'The Internet',NULL,NULL,X'C2881000',X'C2881000');" + "INSERT INTO 'metas' VALUES(7,663,663,128976864758480000," + "128976864758480000,128976864758480000,128976864758480000,1048576,0," + "'s_ID_7','r','r','r','r',0,0,0,1,1,0,'Google Chrome','Google Chrome'" + ",'google_chrome',NULL,NULL,NULL);" + "INSERT INTO 'metas' VALUES(8,664,664,128976864758480000," + "128976864758480000,128976864758480000,128976864758480000,1048576,0," + "'s_ID_8','s_ID_7','s_ID_7','r','r',0,0,0,1,1,0,'Bookmarks'," + "'Bookmarks','google_chrome_bookmarks',NULL,X'C2881000',X'C2881000');" + "INSERT INTO 'metas' VALUES(9,665,665,128976864758480000," + "128976864758480000,128976864758480000,128976864758480000,1048576,1," + "'s_ID_9','s_ID_8','s_ID_8','r','s_ID_10',0,0,0,1,1,0,'Bookmark Bar'," + "'Bookmark Bar','bookmark_bar',NULL,X'C2881000',X'C2881000');" + "INSERT INTO 'metas' VALUES(10,666,666,128976864758480000," + "128976864758480000,128976864758480000,128976864758480000,2097152,2," + "'s_ID_10','s_ID_8','s_ID_8','s_ID_9','r',0,0,0,1,1,0," + "'Other Bookmarks','Other Bookmarks','other_bookmarks',NULL," + "X'C2881000',X'C2881000');" + "INSERT INTO 'metas' VALUES(11,683,683,129079956948440000," + "129079956948440000,129079956948440000,129079956948440000,-1048576,8," + "'s_ID_11','s_ID_6','s_ID_6','r','s_ID_13',0,0,0,0,0,0," + "'Home (The Chromium Projects)','Home (The Chromium Projects)',NULL," + "NULL,X'C28810220A18687474703A2F2F6465762E6368726F6D69756D2E6F72672F1" + "206414741545741',X'C28810290A1D687474703A2F2F6465762E6368726F6D69756" + "D2E6F72672F6F7468657212084146414756415346');" + "INSERT INTO 'metas' VALUES(12,685,685,129079957513650000," + "129079957513650000,129079957513650000,129079957513650000,0,9," + "'s_ID_12','s_ID_6','s_ID_6','s_ID_13','s_ID_14',0,0,0,1,1,0," + "'Extra Bookmarks','Extra Bookmarks',NULL,NULL,X'C2881000'," + "X'C2881000');" + "INSERT INTO 'metas' VALUES(13,687,687,129079957985300000," + "129079957985300000,129079957985300000,129079957985300000,-917504,10," + "'s_ID_13','s_ID_6','s_ID_6','s_ID_11','s_ID_12',0,0,0,0,0,0," + "'ICANN | Internet Corporation for Assigned Names and Numbers'," + "'ICANN | Internet Corporation for Assigned Names and Numbers',NULL," + "NULL,X'C28810240A15687474703A2F2F7777772E6963616E6E2E636F6D2F120B504" + "E474158463041414646',X'C28810200A15687474703A2F2F7777772E6963616E6E2" + "E636F6D2F120744414146415346');" + "INSERT INTO 'metas' VALUES(14,692,692,129079958383000000," + "129079958383000000,129079958383000000,129079958383000000,1048576,11," + "'s_ID_14','s_ID_6','s_ID_6','s_ID_12','r',0,0,0,0,0,0," + "'The WebKit Open Source Project','The WebKit Open Source Project'," + "NULL,NULL,""X'C288101A0A12687474703A2F2F7765626B69742E6F72672F120450" + "4E4758',X'C288101C0A13687474703A2F2F7765626B69742E6F72672F781205504E" + "473259');" + "CREATE TABLE models (model_id BLOB primary key, " + "last_download_timestamp INT, initial_sync_ended BOOLEAN default 0);" + "INSERT INTO 'models' VALUES(X'C2881000',694,1);" + "CREATE TABLE 'share_info' (id TEXT primary key, name TEXT, " + "store_birthday TEXT, db_create_version TEXT, db_create_time INT, " + "next_id INT default -2, cache_guid TEXT, " + "notification_state BLOB);" + "INSERT INTO 'share_info' VALUES('nick@chromium.org','nick@chromium.org'," + "'c27e9f59-08ca-46f8-b0cc-f16a2ed778bb','Unknown',1263522064,-65542," + "'9010788312004066376x-6609234393368420856x',X'C2881000');")); + ASSERT_TRUE(connection.CommitTransaction()); +} + TEST_F(DirectoryBackingStoreTest, MigrateVersion67To68) { SetUpVersion67Database(); @@ -937,6 +1043,56 @@ TEST_F(DirectoryBackingStoreTest, MigrateVersion72To73) { connection.DoesColumnExist("share_info", "notification_state")); } +TEST_F(DirectoryBackingStoreTest, MigrateVersion73To74) { + SetUpVersion73Database(); + + { + sql::Connection connection; + ASSERT_TRUE(connection.Open(GetDatabasePath())); + ASSERT_FALSE( + connection.DoesColumnExist("share_info", "autofill_migration_state")); + ASSERT_FALSE( + connection.DoesColumnExist("share_info", + "bookmarks_added_during_autofill_migration")); + ASSERT_FALSE( + connection.DoesColumnExist("share_info", "autofill_migration_time")); + ASSERT_FALSE( + connection.DoesColumnExist("share_info", + "autofill_entries_added_during_migration")); + + ASSERT_FALSE( + connection.DoesColumnExist("share_info", + "autofill_profiles_added_during_migration")); + } + + scoped_ptr<DirectoryBackingStore> dbs( + new DirectoryBackingStore(GetUsername(), GetDatabasePath())); + + dbs->BeginLoad(); + ASSERT_FALSE(dbs->needs_column_refresh_); + ASSERT_TRUE(dbs->MigrateVersion73To74()); + ASSERT_EQ(74, dbs->GetVersion()); + dbs->EndLoad(); + ASSERT_FALSE(dbs->needs_column_refresh_); + + sql::Connection connection; + ASSERT_TRUE(connection.Open(GetDatabasePath())); + ASSERT_TRUE( + connection.DoesColumnExist("share_info", "autofill_migration_state")); + ASSERT_TRUE( + connection.DoesColumnExist("share_info", + "bookmarks_added_during_autofill_migration")); + ASSERT_TRUE( + connection.DoesColumnExist("share_info", "autofill_migration_time")); + ASSERT_TRUE( + connection.DoesColumnExist("share_info", + "autofill_entries_added_during_migration")); + + ASSERT_TRUE( + connection.DoesColumnExist("share_info", + "autofill_profiles_added_during_migration")); +} + TEST_P(MigrationTest, ToCurrentVersion) { switch (GetParam()) { case 67: @@ -957,6 +1113,9 @@ TEST_P(MigrationTest, ToCurrentVersion) { case 72: SetUpVersion72Database(); break; + case 73: + SetUpVersion73Database(); + break; default: // If you see this error, it may mean that you've increased the // database version number but you haven't finished adding unit tests @@ -1015,6 +1174,10 @@ TEST_P(MigrationTest, ToCurrentVersion) { // Columns added in Version 73. ASSERT_TRUE(connection.DoesColumnExist( "share_info", "notification_state")); + + // Columns added in version 74. + ASSERT_TRUE(connection.DoesColumnExist("share_info", + "autofill_migration_state")); } MetahandlesIndex index; diff --git a/chrome/browser/sync/syncable/model_type.cc b/chrome/browser/sync/syncable/model_type.cc index c95daa8..7bbb29a 100644 --- a/chrome/browser/sync/syncable/model_type.cc +++ b/chrome/browser/sync/syncable/model_type.cc @@ -153,6 +153,9 @@ std::string ModelTypeToString(ModelType model_type) { return "Sessions"; case APPS: return "Apps"; + case AUTOFILL_PROFILE: + return "Autofill Profile"; + break; default: NOTREACHED() << "No known extension for model type."; return "INVALID"; @@ -269,7 +272,7 @@ const char kAppNotificationType[] = "APP"; const char kSessionNotificationType[] = "SESSION"; // TODO(lipalani) Bug 64111. // talk to akalin to make sure this is what I understand this to be. -const char kAutofillProfileType[] = "AUTOFILL_PROFILE"; +const char kAutofillProfileNotificationType[] = "AUTOFILL_PROFILE"; // TODO(akalin): This is a hack to make new sync data types work with // server-issued notifications. Remove this when it's not needed // anymore. @@ -310,7 +313,7 @@ bool RealModelTypeToNotificationType(ModelType model_type, *notification_type = kSessionNotificationType; return true; case AUTOFILL_PROFILE: - *notification_type = kAutofillProfileType; + *notification_type = kAutofillProfileNotificationType; return true; // TODO(akalin): This is a hack to make new sync data types work with // server-issued notifications. Remove this when it's not needed @@ -357,6 +360,9 @@ bool NotificationTypeToRealModelType(const std::string& notification_type, } else if (notification_type == kSessionNotificationType) { *model_type = SESSIONS; return true; + } else if (notification_type == kAutofillProfileNotificationType) { + *model_type = AUTOFILL_PROFILE; + return true; } else if (notification_type == kUnknownNotificationType) { // TODO(akalin): This is a hack to make new sync data types work with // server-issued notifications. Remove this when it's not needed diff --git a/chrome/browser/sync/syncable/model_type.h b/chrome/browser/sync/syncable/model_type.h index 442e462..2760fbe 100644 --- a/chrome/browser/sync/syncable/model_type.h +++ b/chrome/browser/sync/syncable/model_type.h @@ -49,10 +49,11 @@ enum ModelType { PREFERENCES, // A password folder or password object. PASSWORDS, + // An AutofillProfile Object + AUTOFILL_PROFILE, // An autofill folder or an autofill object. AUTOFILL, - // An autofill Profile Object - AUTOFILL_PROFILE, + // A themes folder or a themes object. THEMES, // A typed_url folder or a typed_url object. diff --git a/chrome/browser/sync/syncable/syncable.cc b/chrome/browser/sync/syncable/syncable.cc index 903b71d..2794efa 100644 --- a/chrome/browser/sync/syncable/syncable.cc +++ b/chrome/browser/sync/syncable/syncable.cc @@ -179,6 +179,7 @@ Directory::PersistedKernelInfo::PersistedKernelInfo() for (int i = 0; i < MODEL_TYPE_COUNT; ++i) { last_download_timestamp[i] = 0; } + autofill_migration_state = NOT_DETERMINED; } Directory::PersistedKernelInfo::~PersistedKernelInfo() {} @@ -720,6 +721,83 @@ bool Directory::initial_sync_ended_for_type(ModelType type) const { return kernel_->persisted_info.initial_sync_ended[type]; } +AutofillMigrationState Directory::get_autofill_migration_state() const { + ScopedKernelLock lock(this); + return kernel_->persisted_info.autofill_migration_state; +} + +AutofillMigrationDebugInfo + Directory::get_autofill_migration_debug_info() const { + ScopedKernelLock lock(this); + return kernel_->persisted_info.autofill_migration_debug_info; +} + +template <class T> void Directory::TestAndSet( + T* kernel_data, const T* data_to_set) { + if (*kernel_data != *data_to_set) { + *kernel_data = *data_to_set; + kernel_->info_status = KERNEL_SHARE_INFO_DIRTY; + } +} + +void Directory::set_autofill_migration_state_debug_info( + AutofillMigrationDebugInfo::PropertyToSet property_to_set, + const AutofillMigrationDebugInfo& info) { + + ScopedKernelLock lock(this); + switch (property_to_set) { + case AutofillMigrationDebugInfo::MIGRATION_TIME: { + syncable::AutofillMigrationDebugInfo& + debug_info = kernel_->persisted_info.autofill_migration_debug_info; + TestAndSet<int64>( + &debug_info.autofill_migration_time, + &info.autofill_migration_time); + break; + } + case AutofillMigrationDebugInfo::BOOKMARK_ADDED: { + AutofillMigrationDebugInfo& debug_info = + kernel_->persisted_info.autofill_migration_debug_info; + TestAndSet<int>( + &debug_info.bookmarks_added_during_migration, + &info.bookmarks_added_during_migration); + break; + } + case AutofillMigrationDebugInfo::ENTRIES_ADDED: { + AutofillMigrationDebugInfo& debug_info = + kernel_->persisted_info.autofill_migration_debug_info; + TestAndSet<int>( + &debug_info.autofill_entries_added_during_migration, + &info.autofill_entries_added_during_migration); + break; + } + case AutofillMigrationDebugInfo::PROFILES_ADDED: { + AutofillMigrationDebugInfo& debug_info = + kernel_->persisted_info.autofill_migration_debug_info; + TestAndSet<int>( + &debug_info.autofill_profile_added_during_migration, + &info.autofill_profile_added_during_migration); + break; + } + default: + NOTREACHED(); + } +} + +void Directory::set_autofill_migration_state(AutofillMigrationState state) { + ScopedKernelLock lock(this); + if (state == kernel_->persisted_info.autofill_migration_state) { + return; + } + kernel_->persisted_info.autofill_migration_state = state; + if (state == MIGRATED) { + syncable::AutofillMigrationDebugInfo& debug_info = + kernel_->persisted_info.autofill_migration_debug_info; + debug_info.autofill_migration_time = + base::Time::Now().ToInternalValue(); + } + kernel_->info_status = KERNEL_SHARE_INFO_DIRTY; +} + void Directory::set_initial_sync_ended_for_type(ModelType type, bool x) { ScopedKernelLock lock(this); set_initial_sync_ended_for_type_unsafe(type, x); diff --git a/chrome/browser/sync/syncable/syncable.h b/chrome/browser/sync/syncable/syncable.h index 19d98ee..cccf417 100644 --- a/chrome/browser/sync/syncable/syncable.h +++ b/chrome/browser/sync/syncable/syncable.h @@ -21,6 +21,7 @@ #include "base/lock.h" #include "base/time.h" #include "chrome/browser/sync/protocol/sync.pb.h" +#include "chrome/browser/sync/syncable/autofill_migration.h" #include "chrome/browser/sync/syncable/blob.h" #include "chrome/browser/sync/syncable/dir_open_result.h" #include "chrome/browser/sync/syncable/directory_event.h" @@ -660,6 +661,8 @@ class Directory { // Various data that the Directory::Kernel we are backing (persisting data // for) needs saved across runs of the application. struct PersistedKernelInfo { + AutofillMigrationDebugInfo autofill_migration_debug_info; + PersistedKernelInfo(); ~PersistedKernelInfo(); @@ -674,6 +677,8 @@ class Directory { int64 next_id; // The persisted notification state. std::string notification_state; + + AutofillMigrationState autofill_migration_state; }; // What the Directory needs on initialization to create itself and its Kernel. @@ -754,6 +759,15 @@ class Directory { bool initial_sync_ended_for_type(ModelType type) const; void set_initial_sync_ended_for_type(ModelType type, bool value); + AutofillMigrationState get_autofill_migration_state() const; + + AutofillMigrationDebugInfo get_autofill_migration_debug_info() const; + + void set_autofill_migration_state(AutofillMigrationState state); + + void set_autofill_migration_state_debug_info( + syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set, + const syncable::AutofillMigrationDebugInfo& info); const std::string& name() const { return kernel_->name; } @@ -804,6 +818,8 @@ class Directory { DirOpenResult OpenImpl(const FilePath& file_path, const std::string& name); + template <class T> void TestAndSet(T* kernel_data, const T* data_to_set); + struct DirectoryEventTraits { typedef DirectoryEvent EventType; static inline bool IsChannelShutdownEvent(const DirectoryEvent& event) { |