PackageManagerBackupAgent.java revision 5cbbf5652a78902ac3382dc4a3583bc5b0351027
16785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate/*
26785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Copyright (C) 2009 The Android Open Source Project
36785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate *
46785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Licensed under the Apache License, Version 2.0 (the "License");
56785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * you may not use this file except in compliance with the License.
66785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * You may obtain a copy of the License at
76785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate *
86785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate *      http://www.apache.org/licenses/LICENSE-2.0
96785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate *
106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Unless required by applicable law or agreed to in writing, software
116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * distributed under the License is distributed on an "AS IS" BASIS,
126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * See the License for the specific language governing permissions and
146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * limitations under the License.
156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate */
166785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
176785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tatepackage com.android.server;
186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.app.BackupAgent;
206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.backup.BackupDataInput;
216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.backup.BackupDataOutput;
226785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.ApplicationInfo;
236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.PackageInfo;
246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.PackageManager;
256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.PackageManager.NameNotFoundException;
266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.Signature;
273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tateimport android.os.Build;
286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.os.ParcelFileDescriptor;
296785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.util.Log;
306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.ByteArrayInputStream;
326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.ByteArrayOutputStream;
336785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.DataInputStream;
346785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.DataOutputStream;
356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.EOFException;
366785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.FileInputStream;
376785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.FileOutputStream;
386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.IOException;
396785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.ArrayList;
406785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.HashMap;
416785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.HashSet;
426785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.List;
436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate/**
456785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * We back up the signatures of each package so that during a system restore,
466785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * we can verify that the app whose data we think we have matches the app
476785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * actually resident on the device.
486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate *
496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Since the Package Manager isn't a proper "application" we just provide a
506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * direct IBackupAgent implementation and hand-construct it at need.
516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate */
526785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tatepublic class PackageManagerBackupAgent extends BackupAgent {
536785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    private static final String TAG = "PMBA";
546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    private static final boolean DEBUG = true;
556785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
563a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate    // key under which we store global metadata (individual app metadata
573a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate    // is stored using the package name as a key)
583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate    private static final String GLOBAL_METADATA_KEY = "@meta@";
593a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
606785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    private List<ApplicationInfo> mAllApps;
616785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    private PackageManager mPackageManager;
626aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    private HashMap<String, Metadata> mRestoredSignatures;
636aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate
646aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    public class Metadata {
656aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        public int versionCode;
666aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        public Signature[] signatures;
676aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate
686aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        Metadata(int version, Signature[] sigs) {
696aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate            versionCode = version;
706aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate            signatures = sigs;
716aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        }
726aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    }
736785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
746785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // We're constructed with the set of applications that are participating
756785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // in backup.  This set changes as apps are installed & removed.
766785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    PackageManagerBackupAgent(PackageManager packageMgr, List<ApplicationInfo> apps) {
776785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        mPackageManager = packageMgr;
786785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        mAllApps = apps;
796785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        mRestoredSignatures = null;
806785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
826aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    public Metadata getRestoredMetadata(String packageName) {
836785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        if (mRestoredSignatures == null) {
843a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            Log.w(TAG, "getRestoredMetadata() before metadata read!");
856785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            return null;
866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        return mRestoredSignatures.get(packageName);
896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
906785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
916785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // The backed up data is the signature block for each app, keyed by
926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // the package name.
936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            ParcelFileDescriptor newState) {
956aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        if (DEBUG) Log.v(TAG, "onBackup()");
963a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
976aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        ByteArrayOutputStream bufStream = new ByteArrayOutputStream();  // we'll reuse these
986aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        DataOutputStream outWriter = new DataOutputStream(bufStream);
993a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        HashSet<String> existing = parseStateFile(oldState);
1003a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1013a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        try {
1023a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            /*
1033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate             * Global metadata:
1043a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate             *
1053a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate             * int version -- the SDK version of the OS itself on the device
1063a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate             *                that produced this backup set.  Used to reject
1073a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate             *                backups from later OSes onto earlier ones.
1083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate             */
1093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            if (!existing.contains(GLOBAL_METADATA_KEY)) {
1103a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) Log.v(TAG, "Storing global metadata key");
1113a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                outWriter.writeInt(Build.VERSION.SDK_INT);
1123a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                byte[] metadata = bufStream.toByteArray();
1133a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length);
1143a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                data.writeEntityData(metadata, metadata.length);
1156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            } else {
1163a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) Log.v(TAG, "Global metadata key already stored");
1173a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            }
1183a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // For each app we have on device, see if we've backed it up yet.  If not,
1203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // write its signature block to the output, keyed on the package name.
1213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            for (ApplicationInfo app : mAllApps) {
1223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                String packName = app.packageName;
1233a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (!existing.contains(packName)) {
1243a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    // We haven't stored this app's signatures yet, so we do that now
1253a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    try {
1263a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        PackageInfo info = mPackageManager.getPackageInfo(packName,
1273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                                PackageManager.GET_SIGNATURES);
1283a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        /*
1293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         * Metadata for each package:
1303a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         *
1313a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         * int version       -- [4] the package's versionCode
1323a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         * byte[] signatures -- [len] flattened Signature[] of the package
1333a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         */
1343a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1353a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        // marshall the version code in a canonical form
1363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        bufStream.reset();
1373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        outWriter.writeInt(info.versionCode);
1383a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        byte[] versionBuf = bufStream.toByteArray();
1393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        byte[] sigs = flattenSignatureArray(info.signatures);
1413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1423a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        // !!! TODO: take out this debugging
1433a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        if (DEBUG) {
1443a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                            Log.v(TAG, "+ metadata for " + packName
1453a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                                    + " version=" + info.versionCode
1463a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                                    + " versionLen=" + versionBuf.length
1473a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                                    + " sigsLen=" + sigs.length);
1483a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        }
1493a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        // Now we can write the backup entity for this package
1503a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        data.writeEntityHeader(packName, versionBuf.length + sigs.length);
1513a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        data.writeEntityData(versionBuf, versionBuf.length);
1523a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        data.writeEntityData(sigs, sigs.length);
1533a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    } catch (NameNotFoundException e) {
1543a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        // Weird; we just found it, and now are told it doesn't exist.
1553a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        // Treat it as having been removed from the device.
1563a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        existing.add(packName);
1573a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    }
1583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                } else {
1593a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    // We've already backed up this app.  Remove it from the set so
1603a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    // we can tell at the end what has disappeared from the device.
1613a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    // !!! TODO: take out the debugging message
1623a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    if (DEBUG) Log.v(TAG, "= already backed up metadata for " + packName);
1633a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    if (!existing.remove(packName)) {
1643a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        Log.d(TAG, "*** failed to remove " + packName + " from package set!");
1653a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    }
1666785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                }
1676785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
1686785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
1693a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // At this point, the only entries in 'existing' are apps that were
1703a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // mentioned in the saved state file, but appear to no longer be present
1713a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // on the device.  Write a deletion entity for them.
1723a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            for (String app : existing) {
1733a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                // !!! TODO: take out this msg
1743a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app);
1753a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                try {
1763a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    data.writeEntityHeader(app, -1);
1773a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                } catch (IOException e) {
1783a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    Log.e(TAG, "Unable to write package deletions!");
1793a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    return;
1803a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                }
1816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
1823a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        } catch (IOException e) {
1833a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // Real error writing data
1843a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            Log.e(TAG, "Unable to write package backup data file!");
1853a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            return;
1866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
1876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
1886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        // Finally, write the new state blob -- just the list of all apps we handled
1896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        writeStateFile(mAllApps, newState);
1906785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
1916785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
1926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // "Restore" here is a misnomer.  What we're really doing is reading back the
1936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // set of app signatures associated with each backed-up app in this restore
1946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // image.  We'll use those later to determine what we can legitimately restore.
1955cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
1966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            throws IOException {
1976785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
1986aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
1993a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        if (DEBUG) Log.v(TAG, "onRestore()");
2003a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        int storedSystemVersion = -1;
2016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        while (data.readNextHeader()) {
2033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            String key = data.getKey();
2046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            int dataSize = data.getDataSize();
2056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2063a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            if (DEBUG) Log.v(TAG, "   got key=" + key + " dataSize=" + dataSize);
2073a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
2083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // generic setup to parse any entity data
2093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            byte[] dataBuf = new byte[dataSize];
2103a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            data.readEntityData(dataBuf, 0, dataSize);
2113a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
2123a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            DataInputStream in = new DataInputStream(baStream);
2133a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
2143a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            if (key.equals(GLOBAL_METADATA_KEY)) {
2153a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                storedSystemVersion = in.readInt();
2163a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) Log.v(TAG, "   storedSystemVersion = " + storedSystemVersion);
2173a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (storedSystemVersion > Build.VERSION.SDK_INT) {
2183a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    // returning before setting the sig map means we rejected the restore set
2193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    Log.w(TAG, "Restore set was from a later version of Android; not restoring");
2203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    return;
2213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                }
2223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                // !!! TODO: remove this debugging output
2233a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) {
2243a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    Log.i(TAG, "Restore set version " + storedSystemVersion
2253a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                            + " is compatible with OS version " + Build.VERSION.SDK_INT);
2263a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                }
2273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            } else {
2283a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                // it's a file metadata record
2293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                int versionCode = in.readInt();
2303a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                Signature[] sigs = unflattenSignatureArray(in);
2313a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate//              !!! TODO: take out this debugging
2323a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) {
2333a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    Log.i(TAG, "   restored metadata for " + key
2343a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                            + " dataSize=" + dataSize
2353a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                            + " versionCode=" + versionCode + " sigs=" + sigs);
2363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                }
2373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
2383a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                ApplicationInfo app = new ApplicationInfo();
2393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                app.packageName = key;
2403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                restoredApps.add(app);
2413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                sigMap.put(key, new Metadata(versionCode, sigs));
2423a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            }
2436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
2446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2453a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        // On successful completion, cache the signature map for the Backup Manager to use
2466785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        mRestoredSignatures = sigMap;
2476785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
2486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // Util: convert an array of Signatures into a flattened byte buffer.  The
2516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // flattened format contains enough info to reconstruct the signature array.
2526785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    private byte[] flattenSignatureArray(Signature[] allSigs) {
2536785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        ByteArrayOutputStream outBuf = new ByteArrayOutputStream();
2546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        DataOutputStream out = new DataOutputStream(outBuf);
2556785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2566785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        // build the set of subsidiary buffers
2576785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        try {
2586785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // first the # of signatures in the array
2596785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            out.writeInt(allSigs.length);
2606785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2616785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // then the signatures themselves, length + flattened buffer
2626785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            for (Signature sig : allSigs) {
2636785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                byte[] flat = sig.toByteArray();
2646785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                out.writeInt(flat.length);
2656785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                out.write(flat);
2666785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
2676785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (IOException e) {
2686785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // very strange; we're writing to memory here.  abort.
2696785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            return null;
2706785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
2716785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2726785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        return outBuf.toByteArray();
2736785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
2746785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2756aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) {
2766785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        Signature[] sigs = null;
2776785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2786785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        try {
2796785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            int num = in.readInt();
2803a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            Log.v(TAG, " ... unflatten read " + num);
2816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            sigs = new Signature[num];
2826785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            for (int i = 0; i < num; i++) {
2836785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                int len = in.readInt();
2846785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                byte[] flatSig = new byte[len];
2856785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                in.read(flatSig);
2866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                sigs[i] = new Signature(flatSig);
2876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
2886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (EOFException e) {
2896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // clean termination
2906785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            if (sigs == null) {
2916785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                Log.w(TAG, "Empty signature block found");
2926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
2936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (IOException e) {
2946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            Log.d(TAG, "Unable to unflatten sigs");
2956785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            return null;
2966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
2976785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2986785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        return sigs;
2996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
3006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // Util: parse out an existing state file into a usable structure
3026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    private HashSet<String> parseStateFile(ParcelFileDescriptor stateFile) {
3036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        HashSet<String> set = new HashSet<String>();
3046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        // The state file is just the list of app names we have stored signatures for
3056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor());
3066785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        DataInputStream in = new DataInputStream(instream);
3076785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3086785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        int bufSize = 256;
3096785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        byte[] buf = new byte[bufSize];
3106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        try {
3116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            int nameSize = in.readInt();
3126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            if (bufSize < nameSize) {
3136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                bufSize = nameSize + 32;
3146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                buf = new byte[bufSize];
3156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
3166785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            in.read(buf, 0, nameSize);
3176785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            String pkg = new String(buf, 0, nameSize);
3186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            set.add(pkg);
3196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (EOFException eof) {
3206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // safe; we're done
3216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (IOException e) {
3226785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // whoops, bad state file.  abort.
3236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            Log.e(TAG, "Unable to read Package Manager state file");
3246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            return null;
3256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
3266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        return set;
3276785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
3286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate    // Util: write out our new backup state file
3306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    private void writeStateFile(List<ApplicationInfo> apps, ParcelFileDescriptor stateFile) {
3316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
3326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        DataOutputStream out = new DataOutputStream(outstream);
3336785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3343a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        try {
3353a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // by the time we get here we know we've stored the global metadata record
3363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            byte[] metaNameBuf = GLOBAL_METADATA_KEY.getBytes();
3373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            out.writeInt(metaNameBuf.length);
3383a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            out.write(metaNameBuf);
3393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
3403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // now write all the app names too
3413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            for (ApplicationInfo app : apps) {
3426785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                byte[] pkgNameBuf = app.packageName.getBytes();
3436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                out.writeInt(pkgNameBuf.length);
3446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                out.write(pkgNameBuf);
3456785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
3463a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        } catch (IOException e) {
3473a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            Log.e(TAG, "Unable to write package manager state file!");
3483a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            return;
3496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
3506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
3516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate}
352