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