Index: sync/engine/conflict_resolver.cc |
diff --git a/sync/engine/conflict_resolver.cc b/sync/engine/conflict_resolver.cc |
index 0af30977c331e8840fe7ef27a77362114de875af..d32460c5f29a67810871ed2b8cf1cac76f6e21e7 100644 |
--- a/sync/engine/conflict_resolver.cc |
+++ b/sync/engine/conflict_resolver.cc |
@@ -116,6 +116,8 @@ void ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans, |
// f) Otherwise, it's in general safer to ignore local changes, with the |
// exception of deletion conflicts (choose to undelete) and conflicts |
// where the non_unique_name or parent don't match. |
+ // e) Except for the case of extensions and apps, where we want uninstalls to |
+ // win over local modifications to avoid "back from the dead" reinstalls. |
if (!entry.GetServerIsDel()) { |
// TODO(nick): The current logic is arbitrary; instead, it ought to be made |
// consistent with the ModelAssociator behavior for a datatype. It would |
@@ -228,28 +230,42 @@ void ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans, |
// specifics. |
entry.PutBaseServerSpecifics(sync_pb::EntitySpecifics()); |
} else { // SERVER_IS_DEL is true |
- if (entry.GetIsDir()) { |
- Directory::Metahandles children; |
- trans->directory()->GetChildHandlesById(trans, |
- entry.GetId(), |
- &children); |
- // If a server deleted folder has local contents it should be a hierarchy |
- // conflict. Hierarchy conflicts should not be processed by this |
- // function. |
- DCHECK(children.empty()); |
- } |
+ ModelType type = entry.GetModelType(); |
+ if (type == EXTENSIONS || type == APPS) { |
+ // Ignore local changes for extensions/apps when server had a delete, to |
+ // avoid unwanted reinstall of an uninstalled extension. |
+ DVLOG(1) << "Resolving simple conflict, ignoring local changes for " |
+ << "extension/app: " << entry; |
+ conflict_util::IgnoreLocalChanges(&entry); |
+ status->increment_num_local_overwrites(); |
+ counters->num_local_overwrites++; |
+ UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", |
+ OVERWRITE_LOCAL, |
+ CONFLICT_RESOLUTION_SIZE); |
+ } else { |
+ if (entry.GetIsDir()) { |
+ Directory::Metahandles children; |
+ trans->directory()->GetChildHandlesById(trans, |
+ entry.GetId(), |
+ &children); |
+ // If a server deleted folder has local contents it should be a |
+ // hierarchy conflict. Hierarchy conflicts should not be processed by |
+ // this function. |
+ DCHECK(children.empty()); |
+ } |
- // The entry is deleted on the server but still exists locally. |
- // We undelete it by overwriting the server's tombstone with the local |
- // data. |
- conflict_util::OverwriteServerChanges(&entry); |
- status->increment_num_server_overwrites(); |
- counters->num_server_overwrites++; |
- DVLOG(1) << "Resolving simple conflict, undeleting server entry: " |
- << entry; |
- UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", |
- UNDELETE, |
- CONFLICT_RESOLUTION_SIZE); |
+ // The entry is deleted on the server but still exists locally. |
+ // We undelete it by overwriting the server's tombstone with the local |
+ // data. |
+ conflict_util::OverwriteServerChanges(&entry); |
+ status->increment_num_server_overwrites(); |
+ counters->num_server_overwrites++; |
+ DVLOG(1) << "Resolving simple conflict, undeleting server entry: " |
+ << entry; |
+ UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", |
+ UNDELETE, |
+ CONFLICT_RESOLUTION_SIZE); |
+ } |
} |
} |