Merge "Don't write widget metadata to backup unless it's new/changed" into lmp-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
7651dcb921
@@ -130,6 +130,7 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
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
|
@Override
|
||||||
public void operationComplete() {
|
public void operationComplete() {
|
||||||
// Okay, the agent successfully reported back to us!
|
// Okay, the agent successfully reported back to us!
|
||||||
@@ -2733,17 +2812,7 @@ public class BackupManagerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Piggyback the widget state payload, if any
|
// Piggyback the widget state payload, if any
|
||||||
BackupDataOutput out = new BackupDataOutput(fd);
|
writeWidgetPayloadIfAppropriate(fd, pkgName);
|
||||||
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);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Hard disk error; recovery/failure policy TBD. For now roll back,
|
// Hard disk error; recovery/failure policy TBD. For now roll back,
|
||||||
// but we may want to consider this a transport-level failure (i.e.
|
// but we may want to consider this a transport-level failure (i.e.
|
||||||
|
|||||||
Reference in New Issue
Block a user