PackageManagerBackupAgent.java revision 3d7cd13e772bde1c4a72fa4e740baa03cb042e6c
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
60efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor    private List<PackageInfo> mAllPackages;
616785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    private PackageManager mPackageManager;
6272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate    // version & signature info of each app in a restore set
636aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    private HashMap<String, Metadata> mRestoredSignatures;
6472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate    // The version info of each backed-up app as read from the state file
6572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate    private HashMap<String, Metadata> mStateVersions = new HashMap<String, Metadata>();
6672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate
6772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate    private final HashSet<String> mExisting = new HashSet<String>();
6872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate    private int mStoredSdkVersion;
6972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate    private String mStoredIncrementalVersion;
703d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate    private boolean mHasMetadata;
716aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate
726aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    public class Metadata {
736aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        public int versionCode;
746aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        public Signature[] signatures;
756aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate
766aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        Metadata(int version, Signature[] sigs) {
776aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate            versionCode = version;
786aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate            signatures = sigs;
796aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        }
806aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    }
816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
826785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // We're constructed with the set of applications that are participating
836785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // in backup.  This set changes as apps are installed & removed.
84efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor    PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) {
856785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        mPackageManager = packageMgr;
86efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor        mAllPackages = packages;
876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        mRestoredSignatures = null;
883d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate        mHasMetadata = false;
893d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate    }
903d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate
913d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate    public boolean hasMetadata() {
923d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate        return mHasMetadata;
936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
956aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    public Metadata getRestoredMetadata(String packageName) {
966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        if (mRestoredSignatures == null) {
973a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            Log.w(TAG, "getRestoredMetadata() before metadata read!");
986785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            return null;
996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
1006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
1016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        return mRestoredSignatures.get(packageName);
1026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
1036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
1046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // The backed up data is the signature block for each app, keyed by
1056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // the package name.
1066785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
1076785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            ParcelFileDescriptor newState) {
1086aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        if (DEBUG) Log.v(TAG, "onBackup()");
1093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1106aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        ByteArrayOutputStream bufStream = new ByteArrayOutputStream();  // we'll reuse these
1116aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        DataOutputStream outWriter = new DataOutputStream(bufStream);
11272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        parseStateFile(oldState);
11372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate
11472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        // If the stored version string differs, we need to re-backup all
11572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        // of the metadata.  We force this by removing everything from the
11672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        // "already backed up" map built by parseStateFile().
11772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        if (mStoredIncrementalVersion == null
11872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                || !mStoredIncrementalVersion.equals(Build.VERSION.INCREMENTAL)) {
11972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            Log.i(TAG, "Previous metadata " + mStoredIncrementalVersion + " mismatch vs "
12072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                    + Build.VERSION.INCREMENTAL + " - rewriting");
12172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            mExisting.clear();
12272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        }
1233a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1243a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        try {
1253a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            /*
1263a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate             * Global metadata:
1273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate             *
12872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate             * int SDKversion -- the SDK version of the OS itself on the device
12972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate             *                   that produced this backup set.  Used to reject
13072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate             *                   backups from later OSes onto earlier ones.
13172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate             * String incremental -- the incremental release name of the OS stored in
13272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate             *                       the backup set.
1333a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate             */
13472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            if (!mExisting.contains(GLOBAL_METADATA_KEY)) {
1353a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) Log.v(TAG, "Storing global metadata key");
1363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                outWriter.writeInt(Build.VERSION.SDK_INT);
13772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                outWriter.writeUTF(Build.VERSION.INCREMENTAL);
1383a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                byte[] metadata = bufStream.toByteArray();
1393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length);
1403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                data.writeEntityData(metadata, metadata.length);
1416785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            } else {
1423a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) Log.v(TAG, "Global metadata key already stored");
14372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                // don't consider it to have been skipped/deleted
14472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                mExisting.remove(GLOBAL_METADATA_KEY);
1453a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            }
1463a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1473a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // For each app we have on device, see if we've backed it up yet.  If not,
1483a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // write its signature block to the output, keyed on the package name.
149efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor            for (PackageInfo pkg : mAllPackages) {
150efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor                String packName = pkg.packageName;
1516f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate                if (packName.equals(GLOBAL_METADATA_KEY)) {
1526f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate                    // We've already handled the metadata key; skip it here
1536f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate                    continue;
15472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                } else {
15572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                    PackageInfo info = null;
1563a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    try {
15772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        info = mPackageManager.getPackageInfo(packName,
1583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                                PackageManager.GET_SIGNATURES);
15972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                    } catch (NameNotFoundException e) {
16072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // Weird; we just found it, and now are told it doesn't exist.
16172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // Treat it as having been removed from the device.
16272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        mExisting.add(packName);
16372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        continue;
16472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                    }
16572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate
16672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                    boolean doBackup = false;
16772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                    if (!mExisting.contains(packName)) {
16872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // We haven't backed up this app before
16972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        doBackup = true;
17072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                    } else {
17172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // We *have* backed this one up before.  Check whether the version
17272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // of the backup matches the version of the current app; if they
17372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // don't match, the app has been updated and we need to store its
17472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // metadata again.  In either case, take it out of mExisting so that
17572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // we don't consider it deleted later.
17672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        if (info.versionCode != mStateVersions.get(packName).versionCode) {
17772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                            doBackup = true;
17872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        }
17972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        mExisting.remove(packName);
18072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                    }
18172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate
18272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                    if (doBackup) {
18372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // We need to store this app's metadata
1843a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        /*
1853a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         * Metadata for each package:
1863a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         *
1873a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         * int version       -- [4] the package's versionCode
1883a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         * byte[] signatures -- [len] flattened Signature[] of the package
1893a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                         */
1903a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
19172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                        // marshal the version code in a canonical form
1923a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        bufStream.reset();
1933a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        outWriter.writeInt(info.versionCode);
1943a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        byte[] versionBuf = bufStream.toByteArray();
1953a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1963a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        byte[] sigs = flattenSignatureArray(info.signatures);
1973a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
1983a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        // !!! TODO: take out this debugging
1993a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        if (DEBUG) {
2003a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                            Log.v(TAG, "+ metadata for " + packName
2013a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                                    + " version=" + info.versionCode
2023a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                                    + " versionLen=" + versionBuf.length
2033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                                    + " sigsLen=" + sigs.length);
2043a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        }
2053a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        // Now we can write the backup entity for this package
2063a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        data.writeEntityHeader(packName, versionBuf.length + sigs.length);
2073a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        data.writeEntityData(versionBuf, versionBuf.length);
2083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                        data.writeEntityData(sigs, sigs.length);
2093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    }
2106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                }
2116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
2126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2133a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // At this point, the only entries in 'existing' are apps that were
2143a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // mentioned in the saved state file, but appear to no longer be present
2153a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // on the device.  Write a deletion entity for them.
21672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            for (String app : mExisting) {
2173a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                // !!! TODO: take out this msg
2183a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app);
2193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                try {
2203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    data.writeEntityHeader(app, -1);
2213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                } catch (IOException e) {
2223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    Log.e(TAG, "Unable to write package deletions!");
2233a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    return;
2243a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                }
2256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
2263a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        } catch (IOException e) {
2273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // Real error writing data
2283a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            Log.e(TAG, "Unable to write package backup data file!");
2293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            return;
2306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
2316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        // Finally, write the new state blob -- just the list of all apps we handled
233efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor        writeStateFile(mAllPackages, newState);
2346785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
2356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2366785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // "Restore" here is a misnomer.  What we're really doing is reading back the
2376785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // set of app signatures associated with each backed-up app in this restore
2386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // image.  We'll use those later to determine what we can legitimately restore.
2395cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
2406785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            throws IOException {
2416785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
2426aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate        HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
2433a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        if (DEBUG) Log.v(TAG, "onRestore()");
2443a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        int storedSystemVersion = -1;
2456785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2466785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        while (data.readNextHeader()) {
2473a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            String key = data.getKey();
2486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            int dataSize = data.getDataSize();
2496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2503a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            if (DEBUG) Log.v(TAG, "   got key=" + key + " dataSize=" + dataSize);
2513a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
2523a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // generic setup to parse any entity data
2533a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            byte[] dataBuf = new byte[dataSize];
2543a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            data.readEntityData(dataBuf, 0, dataSize);
2553a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
2563a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            DataInputStream in = new DataInputStream(baStream);
2573a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
2583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            if (key.equals(GLOBAL_METADATA_KEY)) {
25972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                int storedSdkVersion = in.readInt();
2603a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) Log.v(TAG, "   storedSystemVersion = " + storedSystemVersion);
2613a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (storedSystemVersion > Build.VERSION.SDK_INT) {
2623a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    // returning before setting the sig map means we rejected the restore set
2633a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    Log.w(TAG, "Restore set was from a later version of Android; not restoring");
2643a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    return;
2653a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                }
26672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                mStoredSdkVersion = storedSdkVersion;
26772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                mStoredIncrementalVersion = in.readUTF();
2683d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate                mHasMetadata = true;
2693a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                // !!! TODO: remove this debugging output
2703a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) {
2713a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    Log.i(TAG, "Restore set version " + storedSystemVersion
27272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                            + " is compatible with OS version " + Build.VERSION.SDK_INT
27372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                            + " (" + mStoredIncrementalVersion + " vs "
27472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                            + Build.VERSION.INCREMENTAL + ")");
2753a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                }
2763a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            } else {
2773a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                // it's a file metadata record
2783a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                int versionCode = in.readInt();
2793a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                Signature[] sigs = unflattenSignatureArray(in);
2803a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate//              !!! TODO: take out this debugging
2813a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                if (DEBUG) {
2823a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                    Log.i(TAG, "   restored metadata for " + key
2833a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                            + " dataSize=" + dataSize
2843a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                            + " versionCode=" + versionCode + " sigs=" + sigs);
2853a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                }
2863a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
2873a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                ApplicationInfo app = new ApplicationInfo();
2883a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                app.packageName = key;
2893a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                restoredApps.add(app);
2903a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate                sigMap.put(key, new Metadata(versionCode, sigs));
2913a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            }
2926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
2936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2943a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        // On successful completion, cache the signature map for the Backup Manager to use
2956785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        mRestoredSignatures = sigMap;
2966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
2976785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2986785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
2996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // Util: convert an array of Signatures into a flattened byte buffer.  The
3006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // flattened format contains enough info to reconstruct the signature array.
3016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    private byte[] flattenSignatureArray(Signature[] allSigs) {
3026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        ByteArrayOutputStream outBuf = new ByteArrayOutputStream();
3036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        DataOutputStream out = new DataOutputStream(outBuf);
3046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        // build the set of subsidiary buffers
3066785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        try {
3076785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // first the # of signatures in the array
3086785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            out.writeInt(allSigs.length);
3096785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // then the signatures themselves, length + flattened buffer
3116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            for (Signature sig : allSigs) {
3126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                byte[] flat = sig.toByteArray();
3136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                out.writeInt(flat.length);
3146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                out.write(flat);
3156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
3166785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (IOException e) {
3176785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // very strange; we're writing to memory here.  abort.
3186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            return null;
3196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
3206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        return outBuf.toByteArray();
3226785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
3236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3246aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate    private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) {
3256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        Signature[] sigs = null;
3266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3276785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        try {
3286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            int num = in.readInt();
3293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            Log.v(TAG, " ... unflatten read " + num);
3306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            sigs = new Signature[num];
3316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            for (int i = 0; i < num; i++) {
3326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                int len = in.readInt();
3336785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                byte[] flatSig = new byte[len];
3346785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                in.read(flatSig);
3356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                sigs[i] = new Signature(flatSig);
3366785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
3376785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (EOFException e) {
3386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // clean termination
3396785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            if (sigs == null) {
3406785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate                Log.w(TAG, "Empty signature block found");
3416785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
3426785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (IOException e) {
3436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            Log.d(TAG, "Unable to unflatten sigs");
3446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            return null;
3456785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
3466785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3476785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        return sigs;
3486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
3496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    // Util: parse out an existing state file into a usable structure
35172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate    private void parseStateFile(ParcelFileDescriptor stateFile) {
35272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        mExisting.clear();
35372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        mStateVersions.clear();
35472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        mStoredSdkVersion = 0;
35572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        mStoredIncrementalVersion = null;
35672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate
3576785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        // The state file is just the list of app names we have stored signatures for
35872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        // with the exception of the metadata block, to which is also appended the
35972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        // version numbers corresponding with the last time we wrote this PM block.
36072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate        // If they mismatch the current system, we'll re-store the metadata key.
3616785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor());
3626785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        DataInputStream in = new DataInputStream(instream);
3636785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3646785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        int bufSize = 256;
3656785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        byte[] buf = new byte[bufSize];
3666785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        try {
36772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            String pkg = in.readUTF();
36872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            if (pkg.equals(GLOBAL_METADATA_KEY)) {
36972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                mStoredSdkVersion = in.readInt();
37072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                mStoredIncrementalVersion = in.readUTF();
37172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                mExisting.add(GLOBAL_METADATA_KEY);
37272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            } else {
37372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                Log.e(TAG, "No global metadata in state file!");
37472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                return;
37572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            }
37672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate
37772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            // The global metadata was first; now read all the apps
37872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            while (true) {
37972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                pkg = in.readUTF();
38072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                int versionCode = in.readInt();
38172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                mExisting.add(pkg);
38272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                mStateVersions.put(pkg, new Metadata(versionCode, null));
3836785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
3846785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (EOFException eof) {
3856785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // safe; we're done
3866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        } catch (IOException e) {
3876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            // whoops, bad state file.  abort.
38872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            Log.e(TAG, "Unable to read Package Manager state file: " + e);
3896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
3906785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
3916785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3923a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate    // Util: write out our new backup state file
393efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor    private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) {
3946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
3956785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        DataOutputStream out = new DataOutputStream(outstream);
3966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate
3973a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        try {
3983a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // by the time we get here we know we've stored the global metadata record
39972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            out.writeUTF(GLOBAL_METADATA_KEY);
40072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            out.writeInt(Build.VERSION.SDK_INT);
40172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate            out.writeUTF(Build.VERSION.INCREMENTAL);
4023a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate
4033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            // now write all the app names too
404efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor            for (PackageInfo pkg : pkgs) {
40572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                out.writeUTF(pkg.packageName);
40672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate                out.writeInt(pkg.versionCode);
4076785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate            }
4083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate        } catch (IOException e) {
4093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            Log.e(TAG, "Unable to write package manager state file!");
4103a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate            return;
4116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate        }
4126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate    }
4136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate}
414