Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5196d12a authored by Christopher Tate's avatar Christopher Tate Committed by The Android Open Source Project
Browse files

am 3a31a93b: Add some global metadata to the restore set

Merge commit '3a31a93b'

* commit '3a31a93b':
  Add some global metadata to the restore set
parents cb85ef6a 3a31a93b
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
@@ -170,18 +170,13 @@ public class LocalTransport extends IBackupTransport.Stub {
        // The restore set is the concatenation of the individual record blobs,
        // each of which is a file in the package's directory
        File[] blobs = packageDir.listFiles();
        if (DEBUG) Log.v(TAG, "   found " + blobs.length + " key files");
        int err = 0;
        if (blobs != null && blobs.length > 0) {
            BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor());
            try {
                for (File f : blobs) {
                    FileInputStream in = new FileInputStream(f);
                    int size = (int) f.length();
                    byte[] buf = new byte[size];
                    in.read(buf);
                    String key = new String(Base64.decode(f.getName()));
                    out.writeEntityHeader(key, size);
                    out.writeEntityData(buf, size);
                    copyToRestoreData(f, out);
                }
            } catch (Exception e) {
                Log.e(TAG, "Unable to read backup records");
@@ -190,4 +185,16 @@ public class LocalTransport extends IBackupTransport.Stub {
        }
        return err;
    }

    private void copyToRestoreData(File f, BackupDataOutput out) throws IOException {
        FileInputStream in = new FileInputStream(f);
        int size = (int) f.length();
        byte[] buf = new byte[size];
        in.read(buf);
        String key = new String(Base64.decode(f.getName()));
        if (DEBUG) Log.v(TAG, "   ... copy to stream: key=" + key
                + " size=" + size);
        out.writeEntityHeader(key, size);
        out.writeEntityData(buf, size);
    }
}
+19 −9
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -850,18 +851,27 @@ class BackupManagerService extends IBackupManager.Stub {
                            if (app != null) {
                                // Validate against the backed-up signature block, too
                                Metadata info = pmAgent.getRestoredMetadata(app.packageName);
                                if (info != null) {
                                    if (app.versionCode >= info.versionCode) {
                                    if (DEBUG) Log.v(TAG, "Restore version " + info.versionCode
                                            + " compatible with app version " + app.versionCode);
                                        if (DEBUG) Log.v(TAG, "Restore version "
                                                + info.versionCode
                                                + " compatible with app version "
                                                + app.versionCode);
                                        if (signaturesMatch(info.signatures, app.signatures)) {
                                            appsToRestore.add(app);
                                        } else {
                                        Log.w(TAG, "Sig mismatch restoring " + app.packageName);
                                            Log.w(TAG, "Sig mismatch restoring "
                                                    + app.packageName);
                                        }
                                    } else {
                                        Log.i(TAG, "Restore set for " + app.packageName
                                                + " is too new [" + info.versionCode
                                            + "] for installed app version " + app.versionCode);
                                                + "] for installed app version "
                                                + app.versionCode);
                                    }
                                } else {
                                    Log.d(TAG, "Unable to get metadata for "
                                            + app.packageName);
                                }
                            }
                        }
+143 −84
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.util.Log;

@@ -52,6 +53,10 @@ public class PackageManagerBackupAgent extends BackupAgent {
    private static final String TAG = "PMBA";
    private static final boolean DEBUG = true;

    // key under which we store global metadata (individual app metadata
    // is stored using the package name as a key)
    private static final String GLOBAL_METADATA_KEY = "@meta@";

    private List<ApplicationInfo> mAllApps;
    private PackageManager mPackageManager;
    private HashMap<String, Metadata> mRestoredSignatures;
@@ -76,6 +81,7 @@ public class PackageManagerBackupAgent extends BackupAgent {

    public Metadata getRestoredMetadata(String packageName) {
        if (mRestoredSignatures == null) {
            Log.w(TAG, "getRestoredMetadata() before metadata read!");
            return null;
        }

@@ -86,13 +92,32 @@ public class PackageManagerBackupAgent extends BackupAgent {
    // the package name.
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
            ParcelFileDescriptor newState) {
        if (DEBUG) Log.v(TAG, "onBackup()");

        ByteArrayOutputStream bufStream = new ByteArrayOutputStream();  // we'll reuse these
        DataOutputStream outWriter = new DataOutputStream(bufStream);
        HashSet<String> existing = parseStateFile(oldState);

        try {
            /*
             * Global metadata:
             *
             * int version -- the SDK version of the OS itself on the device
             *                that produced this backup set.  Used to reject
             *                backups from later OSes onto earlier ones.
             */
            if (!existing.contains(GLOBAL_METADATA_KEY)) {
                if (DEBUG) Log.v(TAG, "Storing global metadata key");
                outWriter.writeInt(Build.VERSION.SDK_INT);
                byte[] metadata = bufStream.toByteArray();
                data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length);
                data.writeEntityData(metadata, metadata.length);
            } else {
                if (DEBUG) Log.v(TAG, "Global metadata key already stored");
            }

            // For each app we have on device, see if we've backed it up yet.  If not,
            // write its signature block to the output, keyed on the package name.
        if (DEBUG) Log.v(TAG, "onBackup()");
        ByteArrayOutputStream bufStream = new ByteArrayOutputStream();  // we'll reuse these
        DataOutputStream outWriter = new DataOutputStream(bufStream);
            for (ApplicationInfo app : mAllApps) {
                String packName = app.packageName;
                if (!existing.contains(packName)) {
@@ -116,7 +141,10 @@ public class PackageManagerBackupAgent extends BackupAgent {

                        // !!! TODO: take out this debugging
                        if (DEBUG) {
                        Log.v(TAG, "+ metadata for " + packName + " version=" + info.versionCode);
                            Log.v(TAG, "+ metadata for " + packName
                                    + " version=" + info.versionCode
                                    + " versionLen=" + versionBuf.length
                                    + " sigsLen=" + sigs.length);
                        }
                        // Now we can write the backup entity for this package
                        data.writeEntityHeader(packName, versionBuf.length + sigs.length);
@@ -126,10 +154,6 @@ public class PackageManagerBackupAgent extends BackupAgent {
                        // Weird; we just found it, and now are told it doesn't exist.
                        // Treat it as having been removed from the device.
                        existing.add(packName);
                } catch (IOException e) {
                    // Real error writing data
                    Log.e(TAG, "Unable to write package backup data file!");
                    return;
                    }
                } else {
                    // We've already backed up this app.  Remove it from the set so
@@ -155,6 +179,11 @@ public class PackageManagerBackupAgent extends BackupAgent {
                    return;
                }
            }
        } catch (IOException e) {
            // Real error writing data
            Log.e(TAG, "Unable to write package backup data file!");
            return;
        }

        // Finally, write the new state blob -- just the list of all apps we handled
        writeStateFile(mAllApps, newState);
@@ -167,30 +196,53 @@ public class PackageManagerBackupAgent extends BackupAgent {
            throws IOException {
        List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
        HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
        if (DEBUG) Log.v(TAG, "onRestore()");
        int storedSystemVersion = -1;

        while (data.readNextHeader()) {
            String key = data.getKey();
            int dataSize = data.getDataSize();
            byte[] buf = new byte[dataSize];
            data.readEntityData(buf, 0, dataSize);

            ByteArrayInputStream bufStream = new ByteArrayInputStream(buf);
            DataInputStream in = new DataInputStream(bufStream);
            int versionCode = in.readInt();
            if (DEBUG) Log.v(TAG, "   got key=" + key + " dataSize=" + dataSize);

            // generic setup to parse any entity data
            byte[] dataBuf = new byte[dataSize];
            data.readEntityData(dataBuf, 0, dataSize);
            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
            DataInputStream in = new DataInputStream(baStream);

            if (key.equals(GLOBAL_METADATA_KEY)) {
                storedSystemVersion = in.readInt();
                if (DEBUG) Log.v(TAG, "   storedSystemVersion = " + storedSystemVersion);
                if (storedSystemVersion > Build.VERSION.SDK_INT) {
                    // returning before setting the sig map means we rejected the restore set
                    Log.w(TAG, "Restore set was from a later version of Android; not restoring");
                    return;
                }
                // !!! TODO: remove this debugging output
                if (DEBUG) {
                    Log.i(TAG, "Restore set version " + storedSystemVersion
                            + " is compatible with OS version " + Build.VERSION.SDK_INT);
                }
            } else {
                // it's a file metadata record
                int versionCode = in.readInt();
                Signature[] sigs = unflattenSignatureArray(in);
            String pkg = data.getKey();
//              !!! TODO: take out this debugging
                if (DEBUG) {
                Log.i(TAG, "+ restored metadata for " + pkg
                    Log.i(TAG, "   restored metadata for " + key
                            + " dataSize=" + dataSize
                            + " versionCode=" + versionCode + " sigs=" + sigs);
                }

                ApplicationInfo app = new ApplicationInfo();
            app.packageName = pkg;
                app.packageName = key;
                restoredApps.add(app);
            sigMap.put(pkg, new Metadata(versionCode, sigs));
                sigMap.put(key, new Metadata(versionCode, sigs));
            }
        }

        // On successful completion, cache the signature map for the Backup Manager to use
        mRestoredSignatures = sigMap;
    }

@@ -225,6 +277,7 @@ public class PackageManagerBackupAgent extends BackupAgent {

        try {
            int num = in.readInt();
            Log.v(TAG, " ... unflatten read " + num);
            sigs = new Signature[num];
            for (int i = 0; i < num; i++) {
                int len = in.readInt();
@@ -273,20 +326,26 @@ public class PackageManagerBackupAgent extends BackupAgent {
        return set;
    }

    // Util: write a set of names into a new state file
    // Util: write out our new backup state file
    private void writeStateFile(List<ApplicationInfo> apps, ParcelFileDescriptor stateFile) {
        FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
        DataOutputStream out = new DataOutputStream(outstream);

        for (ApplicationInfo app : apps) {
        try {
            // by the time we get here we know we've stored the global metadata record
            byte[] metaNameBuf = GLOBAL_METADATA_KEY.getBytes();
            out.writeInt(metaNameBuf.length);
            out.write(metaNameBuf);

            // now write all the app names too
            for (ApplicationInfo app : apps) {
                byte[] pkgNameBuf = app.packageName.getBytes();
                out.writeInt(pkgNameBuf.length);
                out.write(pkgNameBuf);
            }
        } catch (IOException e) {
            Log.e(TAG, "Unable to write package manager state file!");
            return;
        }
    }
}
}