| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/glue/generic_change_processor.h" | 5 #include "chrome/browser/sync/glue/generic_change_processor.h" |
| 6 | 6 |
| 7 #include "base/location.h" | 7 #include "base/location.h" |
| 8 #include "base/string_number_conversions.h" | 8 #include "base/string_number_conversions.h" |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "content/public/browser/browser_thread.h" | 10 #include "content/public/browser/browser_thread.h" |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 } | 72 } |
| 73 } | 73 } |
| 74 | 74 |
| 75 void GenericChangeProcessor::CommitChangesFromSyncModel() { | 75 void GenericChangeProcessor::CommitChangesFromSyncModel() { |
| 76 DCHECK(CalledOnValidThread()); | 76 DCHECK(CalledOnValidThread()); |
| 77 if (!running()) | 77 if (!running()) |
| 78 return; | 78 return; |
| 79 if (syncer_changes_.empty()) | 79 if (syncer_changes_.empty()) |
| 80 return; | 80 return; |
| 81 if (!local_service_) { | 81 if (!local_service_) { |
| 82 syncable::ModelType type = syncer_changes_[0].sync_data().GetDataType(); | 82 syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType(); |
| 83 syncer::SyncError error(FROM_HERE, "Local service destroyed.", type); | 83 syncer::SyncError error(FROM_HERE, "Local service destroyed.", type); |
| 84 error_handler()->OnSingleDatatypeUnrecoverableError(error.location(), | 84 error_handler()->OnSingleDatatypeUnrecoverableError(error.location(), |
| 85 error.message()); | 85 error.message()); |
| 86 return; | 86 return; |
| 87 } | 87 } |
| 88 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE, | 88 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE, |
| 89 syncer_changes_); | 89 syncer_changes_); |
| 90 syncer_changes_.clear(); | 90 syncer_changes_.clear(); |
| 91 if (error.IsSet()) { | 91 if (error.IsSet()) { |
| 92 error_handler()->OnSingleDatatypeUnrecoverableError( | 92 error_handler()->OnSingleDatatypeUnrecoverableError( |
| 93 error.location(), error.message()); | 93 error.location(), error.message()); |
| 94 } | 94 } |
| 95 } | 95 } |
| 96 | 96 |
| 97 syncer::SyncError GenericChangeProcessor::GetSyncDataForType( | 97 syncer::SyncError GenericChangeProcessor::GetSyncDataForType( |
| 98 syncable::ModelType type, | 98 syncer::ModelType type, |
| 99 syncer::SyncDataList* current_sync_data) { | 99 syncer::SyncDataList* current_sync_data) { |
| 100 DCHECK(CalledOnValidThread()); | 100 DCHECK(CalledOnValidThread()); |
| 101 std::string type_name = syncable::ModelTypeToString(type); | 101 std::string type_name = syncer::ModelTypeToString(type); |
| 102 syncer::ReadTransaction trans(FROM_HERE, share_handle()); | 102 syncer::ReadTransaction trans(FROM_HERE, share_handle()); |
| 103 syncer::ReadNode root(&trans); | 103 syncer::ReadNode root(&trans); |
| 104 if (root.InitByTagLookup(syncable::ModelTypeToRootTag(type)) != | 104 if (root.InitByTagLookup(syncer::ModelTypeToRootTag(type)) != |
| 105 syncer::BaseNode::INIT_OK) { | 105 syncer::BaseNode::INIT_OK) { |
| 106 syncer::SyncError error(FROM_HERE, | 106 syncer::SyncError error(FROM_HERE, |
| 107 "Server did not create the top-level " + type_name + | 107 "Server did not create the top-level " + type_name + |
| 108 " node. We might be running against an out-of-date server.", | 108 " node. We might be running against an out-of-date server.", |
| 109 type); | 109 type); |
| 110 return error; | 110 return error; |
| 111 } | 111 } |
| 112 | 112 |
| 113 // TODO(akalin): We'll have to do a tree traversal for bookmarks. | 113 // TODO(akalin): We'll have to do a tree traversal for bookmarks. |
| 114 DCHECK_NE(type, syncable::BOOKMARKS); | 114 DCHECK_NE(type, syncer::BOOKMARKS); |
| 115 | 115 |
| 116 int64 sync_child_id = root.GetFirstChildId(); | 116 int64 sync_child_id = root.GetFirstChildId(); |
| 117 while (sync_child_id != syncer::kInvalidId) { | 117 while (sync_child_id != syncer::kInvalidId) { |
| 118 syncer::ReadNode sync_child_node(&trans); | 118 syncer::ReadNode sync_child_node(&trans); |
| 119 if (sync_child_node.InitByIdLookup(sync_child_id) != | 119 if (sync_child_node.InitByIdLookup(sync_child_id) != |
| 120 syncer::BaseNode::INIT_OK) { | 120 syncer::BaseNode::INIT_OK) { |
| 121 syncer::SyncError error(FROM_HERE, | 121 syncer::SyncError error(FROM_HERE, |
| 122 "Failed to fetch child node for type " + type_name + ".", | 122 "Failed to fetch child node for type " + type_name + ".", |
| 123 type); | 123 type); |
| 124 return error; | 124 return error; |
| 125 } | 125 } |
| 126 current_sync_data->push_back(syncer::SyncData::CreateRemoteData( | 126 current_sync_data->push_back(syncer::SyncData::CreateRemoteData( |
| 127 sync_child_node.GetId(), sync_child_node.GetEntitySpecifics())); | 127 sync_child_node.GetId(), sync_child_node.GetEntitySpecifics())); |
| 128 sync_child_id = sync_child_node.GetSuccessorId(); | 128 sync_child_id = sync_child_node.GetSuccessorId(); |
| 129 } | 129 } |
| 130 return syncer::SyncError(); | 130 return syncer::SyncError(); |
| 131 } | 131 } |
| 132 | 132 |
| 133 namespace { | 133 namespace { |
| 134 | 134 |
| 135 // TODO(isherman): Investigating http://crbug.com/121592 | 135 // TODO(isherman): Investigating http://crbug.com/121592 |
| 136 // WARNING: this code is sensitive to compiler optimizations. Be careful | 136 // WARNING: this code is sensitive to compiler optimizations. Be careful |
| 137 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else | 137 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else |
| 138 // the compiler attempts to merge it with other calls, losing useful information | 138 // the compiler attempts to merge it with other calls, losing useful information |
| 139 // in breakpad uploads. | 139 // in breakpad uploads. |
| 140 syncer::SyncError LogLookupFailure( | 140 syncer::SyncError LogLookupFailure( |
| 141 syncer::BaseNode::InitByLookupResult lookup_result, | 141 syncer::BaseNode::InitByLookupResult lookup_result, |
| 142 const tracked_objects::Location& from_here, | 142 const tracked_objects::Location& from_here, |
| 143 const std::string& error_prefix, | 143 const std::string& error_prefix, |
| 144 syncable::ModelType type, | 144 syncer::ModelType type, |
| 145 DataTypeErrorHandler* error_handler) { | 145 DataTypeErrorHandler* error_handler) { |
| 146 switch (lookup_result) { | 146 switch (lookup_result) { |
| 147 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: { | 147 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: { |
| 148 syncer::SyncError error; | 148 syncer::SyncError error; |
| 149 error.Reset(from_here, | 149 error.Reset(from_here, |
| 150 error_prefix + | 150 error_prefix + |
| 151 "could not find entry matching the lookup criteria.", | 151 "could not find entry matching the lookup criteria.", |
| 152 type); | 152 type); |
| 153 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 153 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 154 error.message()); | 154 error.message()); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 // Should have listed all the possible error cases above. | 186 // Should have listed all the possible error cases above. |
| 187 error.Reset(from_here, error_prefix + "unknown error", type); | 187 error.Reset(from_here, error_prefix + "unknown error", type); |
| 188 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 188 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 189 error.message()); | 189 error.message()); |
| 190 LOG(ERROR) << "Delete: Unknown error."; | 190 LOG(ERROR) << "Delete: Unknown error."; |
| 191 return error; | 191 return error; |
| 192 } | 192 } |
| 193 } | 193 } |
| 194 } | 194 } |
| 195 | 195 |
| 196 syncer::SyncError AttemptDelete(const syncer::SyncChange& change, | 196 syncer::SyncError AttemptDelete( |
| 197 syncable::ModelType type, | 197 const syncer::SyncChange& change, |
| 198 const std::string& type_str, | 198 syncer::ModelType type, |
| 199 syncer::WriteNode* node, | 199 const std::string& type_str, |
| 200 DataTypeErrorHandler* error_handler) { | 200 syncer::WriteNode* node, |
| 201 DataTypeErrorHandler* error_handler) { |
| 201 DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE); | 202 DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE); |
| 202 if (change.sync_data().IsLocal()) { | 203 if (change.sync_data().IsLocal()) { |
| 203 const std::string& tag = change.sync_data().GetTag(); | 204 const std::string& tag = change.sync_data().GetTag(); |
| 204 if (tag.empty()) { | 205 if (tag.empty()) { |
| 205 syncer::SyncError error( | 206 syncer::SyncError error( |
| 206 FROM_HERE, | 207 FROM_HERE, |
| 207 "Failed to delete " + type_str + " node. Local data, empty tag.", | 208 "Failed to delete " + type_str + " node. Local data, empty tag.", |
| 208 type); | 209 type); |
| 209 error_handler->OnSingleDatatypeUnrecoverableError(error.location(), | 210 error_handler->OnSingleDatatypeUnrecoverableError(error.location(), |
| 210 error.message()); | 211 error.message()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges( | 244 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges( |
| 244 const tracked_objects::Location& from_here, | 245 const tracked_objects::Location& from_here, |
| 245 const syncer::SyncChangeList& list_of_changes) { | 246 const syncer::SyncChangeList& list_of_changes) { |
| 246 DCHECK(CalledOnValidThread()); | 247 DCHECK(CalledOnValidThread()); |
| 247 syncer::WriteTransaction trans(from_here, share_handle()); | 248 syncer::WriteTransaction trans(from_here, share_handle()); |
| 248 | 249 |
| 249 for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin(); | 250 for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin(); |
| 250 iter != list_of_changes.end(); | 251 iter != list_of_changes.end(); |
| 251 ++iter) { | 252 ++iter) { |
| 252 const syncer::SyncChange& change = *iter; | 253 const syncer::SyncChange& change = *iter; |
| 253 DCHECK_NE(change.sync_data().GetDataType(), syncable::UNSPECIFIED); | 254 DCHECK_NE(change.sync_data().GetDataType(), syncer::UNSPECIFIED); |
| 254 syncable::ModelType type = change.sync_data().GetDataType(); | 255 syncer::ModelType type = change.sync_data().GetDataType(); |
| 255 std::string type_str = syncable::ModelTypeToString(type); | 256 std::string type_str = syncer::ModelTypeToString(type); |
| 256 syncer::WriteNode sync_node(&trans); | 257 syncer::WriteNode sync_node(&trans); |
| 257 if (change.change_type() == syncer::SyncChange::ACTION_DELETE) { | 258 if (change.change_type() == syncer::SyncChange::ACTION_DELETE) { |
| 258 syncer::SyncError error = | 259 syncer::SyncError error = |
| 259 AttemptDelete(change, type, type_str, &sync_node, | 260 AttemptDelete(change, type, type_str, &sync_node, |
| 260 error_handler()); | 261 error_handler()); |
| 261 if (error.IsSet()) { | 262 if (error.IsSet()) { |
| 262 NOTREACHED(); | 263 NOTREACHED(); |
| 263 return error; | 264 return error; |
| 264 } | 265 } |
| 265 } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) { | 266 } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) { |
| 266 // TODO(sync): Handle other types of creation (custom parents, folders, | 267 // TODO(sync): Handle other types of creation (custom parents, folders, |
| 267 // etc.). | 268 // etc.). |
| 268 syncer::ReadNode root_node(&trans); | 269 syncer::ReadNode root_node(&trans); |
| 269 if (root_node.InitByTagLookup( | 270 if (root_node.InitByTagLookup( |
| 270 syncable::ModelTypeToRootTag(change.sync_data().GetDataType())) != | 271 syncer::ModelTypeToRootTag(change.sync_data().GetDataType())) != |
| 271 syncer::BaseNode::INIT_OK) { | 272 syncer::BaseNode::INIT_OK) { |
| 272 syncer::SyncError error(FROM_HERE, | 273 syncer::SyncError error(FROM_HERE, |
| 273 "Failed to look up root node for type " + type_str, | 274 "Failed to look up root node for type " + type_str, |
| 274 type); | 275 type); |
| 275 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 276 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 276 error.message()); | 277 error.message()); |
| 277 NOTREACHED(); | 278 NOTREACHED(); |
| 278 LOG(ERROR) << "Create: no root node."; | 279 LOG(ERROR) << "Create: no root node."; |
| 279 return error; | 280 return error; |
| 280 } | 281 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 syncer::SyncError error; | 360 syncer::SyncError error; |
| 360 error.Reset(FROM_HERE, | 361 error.Reset(FROM_HERE, |
| 361 "Failed to load deleted entry for " + type_str + ".", | 362 "Failed to load deleted entry for " + type_str + ".", |
| 362 type); | 363 type); |
| 363 error_handler()->OnSingleDatatypeUnrecoverableError( | 364 error_handler()->OnSingleDatatypeUnrecoverableError( |
| 364 FROM_HERE, error.message()); | 365 FROM_HERE, error.message()); |
| 365 LOG(ERROR) << "Update: deleted entry."; | 366 LOG(ERROR) << "Update: deleted entry."; |
| 366 return error; | 367 return error; |
| 367 } else { | 368 } else { |
| 368 syncer::Cryptographer* crypto = trans.GetCryptographer(); | 369 syncer::Cryptographer* crypto = trans.GetCryptographer(); |
| 369 syncable::ModelTypeSet encrypted_types(crypto->GetEncryptedTypes()); | 370 syncer::ModelTypeSet encrypted_types(crypto->GetEncryptedTypes()); |
| 370 const sync_pb::EntitySpecifics& specifics = | 371 const sync_pb::EntitySpecifics& specifics = |
| 371 sync_node.GetEntry()->Get(syncer::syncable::SPECIFICS); | 372 sync_node.GetEntry()->Get(syncer::syncable::SPECIFICS); |
| 372 CHECK(specifics.has_encrypted()); | 373 CHECK(specifics.has_encrypted()); |
| 373 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted()); | 374 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted()); |
| 374 const bool agreement = encrypted_types.Has(type); | 375 const bool agreement = encrypted_types.Has(type); |
| 375 if (!agreement && !can_decrypt) { | 376 if (!agreement && !can_decrypt) { |
| 376 syncer::SyncError error; | 377 syncer::SyncError error; |
| 377 error.Reset(FROM_HERE, | 378 error.Reset(FROM_HERE, |
| 378 "Failed to load encrypted entry, missing key and " | 379 "Failed to load encrypted entry, missing key and " |
| 379 "nigori mismatch for " + type_str + ".", | 380 "nigori mismatch for " + type_str + ".", |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 error.message()); | 430 error.message()); |
| 430 NOTREACHED(); | 431 NOTREACHED(); |
| 431 LOG(ERROR) << "Unset sync change."; | 432 LOG(ERROR) << "Unset sync change."; |
| 432 return error; | 433 return error; |
| 433 } | 434 } |
| 434 } | 435 } |
| 435 return syncer::SyncError(); | 436 return syncer::SyncError(); |
| 436 } | 437 } |
| 437 | 438 |
| 438 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes( | 439 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes( |
| 439 syncable::ModelType type, | 440 syncer::ModelType type, |
| 440 bool* has_nodes) { | 441 bool* has_nodes) { |
| 441 DCHECK(CalledOnValidThread()); | 442 DCHECK(CalledOnValidThread()); |
| 442 DCHECK(has_nodes); | 443 DCHECK(has_nodes); |
| 443 DCHECK_NE(type, syncable::UNSPECIFIED); | 444 DCHECK_NE(type, syncer::UNSPECIFIED); |
| 444 std::string type_name = syncable::ModelTypeToString(type); | 445 std::string type_name = syncer::ModelTypeToString(type); |
| 445 std::string err_str = "Server did not create the top-level " + type_name + | 446 std::string err_str = "Server did not create the top-level " + type_name + |
| 446 " node. We might be running against an out-of-date server."; | 447 " node. We might be running against an out-of-date server."; |
| 447 *has_nodes = false; | 448 *has_nodes = false; |
| 448 syncer::ReadTransaction trans(FROM_HERE, share_handle()); | 449 syncer::ReadTransaction trans(FROM_HERE, share_handle()); |
| 449 syncer::ReadNode type_root_node(&trans); | 450 syncer::ReadNode type_root_node(&trans); |
| 450 if (type_root_node.InitByTagLookup(syncable::ModelTypeToRootTag(type)) != | 451 if (type_root_node.InitByTagLookup(syncer::ModelTypeToRootTag(type)) != |
| 451 syncer::BaseNode::INIT_OK) { | 452 syncer::BaseNode::INIT_OK) { |
| 452 LOG(ERROR) << err_str; | 453 LOG(ERROR) << err_str; |
| 453 return false; | 454 return false; |
| 454 } | 455 } |
| 455 | 456 |
| 456 // The sync model has user created nodes if the type's root node has any | 457 // The sync model has user created nodes if the type's root node has any |
| 457 // children. | 458 // children. |
| 458 *has_nodes = type_root_node.HasChildren(); | 459 *has_nodes = type_root_node.HasChildren(); |
| 459 return true; | 460 return true; |
| 460 } | 461 } |
| 461 | 462 |
| 462 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncable::ModelType type) { | 463 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncer::ModelType type) { |
| 463 DCHECK(CalledOnValidThread()); | 464 DCHECK(CalledOnValidThread()); |
| 464 DCHECK_NE(type, syncable::UNSPECIFIED); | 465 DCHECK_NE(type, syncer::UNSPECIFIED); |
| 465 // We only access the cryptographer while holding a transaction. | 466 // We only access the cryptographer while holding a transaction. |
| 466 syncer::ReadTransaction trans(FROM_HERE, share_handle()); | 467 syncer::ReadTransaction trans(FROM_HERE, share_handle()); |
| 467 const syncable::ModelTypeSet encrypted_types = GetEncryptedTypes(&trans); | 468 const syncer::ModelTypeSet encrypted_types = GetEncryptedTypes(&trans); |
| 468 return !encrypted_types.Has(type) || | 469 return !encrypted_types.Has(type) || |
| 469 trans.GetCryptographer()->is_ready(); | 470 trans.GetCryptographer()->is_ready(); |
| 470 } | 471 } |
| 471 | 472 |
| 472 void GenericChangeProcessor::StartImpl(Profile* profile) { | 473 void GenericChangeProcessor::StartImpl(Profile* profile) { |
| 473 DCHECK(CalledOnValidThread()); | 474 DCHECK(CalledOnValidThread()); |
| 474 } | 475 } |
| 475 | 476 |
| 476 void GenericChangeProcessor::StopImpl() { | 477 void GenericChangeProcessor::StopImpl() { |
| 477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 478 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 478 } | 479 } |
| 479 | 480 |
| 480 syncer::UserShare* GenericChangeProcessor::share_handle() const { | 481 syncer::UserShare* GenericChangeProcessor::share_handle() const { |
| 481 DCHECK(CalledOnValidThread()); | 482 DCHECK(CalledOnValidThread()); |
| 482 return share_handle_; | 483 return share_handle_; |
| 483 } | 484 } |
| 484 | 485 |
| 485 } // namespace browser_sync | 486 } // namespace browser_sync |
| OLD | NEW |