diff options
| author | 2015-01-20 21:49:55 +0000 | |
|---|---|---|
| committer | 2015-01-20 21:49:55 +0000 | |
| commit | 0fa1d70ab1ea160842e59256819fe87e4bbff3ca (patch) | |
| tree | 2f97209496d5ca238b627401e1aaa0f0175d69a5 | |
| parent | 885e727ab4e55155d1735f78c8a0550f7f180c8a (diff) | |
| parent | a9c122af60621597f1d008c8a283074309383aac (diff) | |
am a9c122af: Merge "Don\'t write widget metadata to backup unless it\'s new/changed" into lmp-mr1-dev automerge: 7651dcb automerge: 5afc62c
* commit 'a9c122af60621597f1d008c8a283074309383aac':
Don't write widget metadata to backup unless it's new/changed
| -rw-r--r-- | services/backup/java/com/android/server/backup/BackupManagerService.java | 91 |
1 files changed, 80 insertions, 11 deletions
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 7d085a33f00b..289152b52b31 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -130,6 +130,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Random; import java.util.Set; import java.util.TreeMap; @@ -2695,6 +2696,84 @@ public class BackupManagerService { } } + // SHA-1 a byte array and return the result in hex + private String SHA1Checksum(byte[] input) { + final byte[] checksum; + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + checksum = md.digest(input); + } catch (NoSuchAlgorithmException e) { + Slog.e(TAG, "Unable to use SHA-1!"); + return "00"; + } + + StringBuffer sb = new StringBuffer(checksum.length * 2); + for (int i = 0; i < checksum.length; i++) { + sb.append(Integer.toHexString(checksum[i])); + } + return sb.toString(); + } + + private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName) + throws IOException { + byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName, + UserHandle.USER_OWNER); + // has the widget state changed since last time? + final File widgetFile = new File(mStateDir, pkgName + "_widget"); + final boolean priorStateExists = widgetFile.exists(); + + if (MORE_DEBUG) { + if (priorStateExists || widgetState != null) { + Slog.i(TAG, "Checking widget update: state=" + (widgetState != null) + + " prior=" + priorStateExists); + } + } + + if (!priorStateExists && widgetState == null) { + // no prior state, no new state => nothing to do + return; + } + + // if the new state is not null, we might need to compare checksums to + // determine whether to update the widget blob in the archive. If the + // widget state *is* null, we know a priori at this point that we simply + // need to commit a deletion for it. + String newChecksum = null; + if (widgetState != null) { + newChecksum = SHA1Checksum(widgetState); + if (priorStateExists) { + final String priorChecksum; + try ( + FileInputStream fin = new FileInputStream(widgetFile); + DataInputStream in = new DataInputStream(fin) + ) { + priorChecksum = in.readUTF(); + } + if (Objects.equals(newChecksum, priorChecksum)) { + // Same checksum => no state change => don't rewrite the widget data + return; + } + } + } // else widget state *became* empty, so we need to commit a deletion + + BackupDataOutput out = new BackupDataOutput(fd); + if (widgetState != null) { + try ( + FileOutputStream fout = new FileOutputStream(widgetFile); + DataOutputStream stateOut = new DataOutputStream(fout) + ) { + stateOut.writeUTF(newChecksum); + } + + out.writeEntityHeader(KEY_WIDGET_STATE, widgetState.length); + out.writeEntityData(widgetState, widgetState.length); + } else { + // Widget state for this app has been removed; commit a deletion + out.writeEntityHeader(KEY_WIDGET_STATE, -1); + widgetFile.delete(); + } + } + @Override public void operationComplete() { // Okay, the agent successfully reported back to us! @@ -2733,17 +2812,7 @@ public class BackupManagerService { } // Piggyback the widget state payload, if any - BackupDataOutput out = new BackupDataOutput(fd); - byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName, - UserHandle.USER_OWNER); - if (widgetState != null) { - out.writeEntityHeader(KEY_WIDGET_STATE, widgetState.length); - out.writeEntityData(widgetState, widgetState.length); - } else { - // No widget state for this app, but push a 'delete' operation for it - // in case they're trying to play games with the payload. - out.writeEntityHeader(KEY_WIDGET_STATE, -1); - } + writeWidgetPayloadIfAppropriate(fd, pkgName); } catch (IOException e) { // Hard disk error; recovery/failure policy TBD. For now roll back, // but we may want to consider this a transport-level failure (i.e. |