PackageManagerBackupAgent.java revision 4528186e0d65fc68ef0dd1941aa2ac8aefcd55a3
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 194528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.BackupAgent; 204528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.BackupDataInput; 214528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.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; 298a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog; 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; 43b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tateimport java.util.Set; 446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 456785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate/** 466785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * We back up the signatures of each package so that during a system restore, 476785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * we can verify that the app whose data we think we have matches the app 486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * actually resident on the device. 496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * 506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Since the Package Manager isn't a proper "application" we just provide a 516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * direct IBackupAgent implementation and hand-construct it at need. 526785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate */ 536785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tatepublic class PackageManagerBackupAgent extends BackupAgent { 546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private static final String TAG = "PMBA"; 55b808a939328b935592d9259e06c66b433a13c1a9Christopher Tate private static final boolean DEBUG = false; 566785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 573a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // key under which we store global metadata (individual app metadata 583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // is stored using the package name as a key) 593a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate private static final String GLOBAL_METADATA_KEY = "@meta@"; 603a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 61efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private List<PackageInfo> mAllPackages; 626785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private PackageManager mPackageManager; 6372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // version & signature info of each app in a restore set 646aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate private HashMap<String, Metadata> mRestoredSignatures; 6572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // The version info of each backed-up app as read from the state file 6672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private HashMap<String, Metadata> mStateVersions = new HashMap<String, Metadata>(); 6772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 6872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private final HashSet<String> mExisting = new HashSet<String>(); 6972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private int mStoredSdkVersion; 7072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private String mStoredIncrementalVersion; 713d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate private boolean mHasMetadata; 726aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate 736aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public class Metadata { 746aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public int versionCode; 756aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public Signature[] signatures; 766aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate 776aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate Metadata(int version, Signature[] sigs) { 786aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate versionCode = version; 796aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate signatures = sigs; 806aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate } 816aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate } 826785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 836785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // We're constructed with the set of applications that are participating 846785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // in backup. This set changes as apps are installed & removed. 85efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) { 866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mPackageManager = packageMgr; 87efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mAllPackages = packages; 886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mRestoredSignatures = null; 893d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate mHasMetadata = false; 903d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate } 913d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate 923d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate public boolean hasMetadata() { 933d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate return mHasMetadata; 946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 956785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 966aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public Metadata getRestoredMetadata(String packageName) { 976785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate if (mRestoredSignatures == null) { 988a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.w(TAG, "getRestoredMetadata() before metadata read!"); 996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 1006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 1016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 1026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return mRestoredSignatures.get(packageName); 1036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 104b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate 105b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate public Set<String> getRestoredPackages() { 106b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate if (mRestoredSignatures == null) { 1078a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.w(TAG, "getRestoredPackages() before metadata read!"); 108b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate return null; 109b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate } 110b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate 111b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // This is technically the set of packages on the originating handset 112b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // that had backup agents at all, not limited to the set of packages 113b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // that had actually contributed a restore dataset, but it's a 114b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // close enough approximation for our purposes and does not require any 115b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // additional involvement by the transport to obtain. 116b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate return mRestoredSignatures.keySet(); 117b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate } 1186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 1196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // The backed up data is the signature block for each app, keyed by 1206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // the package name. 1216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 1226785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate ParcelFileDescriptor newState) { 1238a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "onBackup()"); 1243a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1256aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these 1266aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate DataOutputStream outWriter = new DataOutputStream(bufStream); 12772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate parseStateFile(oldState); 12872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 12972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // If the stored version string differs, we need to re-backup all 13072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // of the metadata. We force this by removing everything from the 13172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // "already backed up" map built by parseStateFile(). 13272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (mStoredIncrementalVersion == null 13372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate || !mStoredIncrementalVersion.equals(Build.VERSION.INCREMENTAL)) { 1348a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.i(TAG, "Previous metadata " + mStoredIncrementalVersion + " mismatch vs " 13572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + Build.VERSION.INCREMENTAL + " - rewriting"); 13672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.clear(); 13772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 1383a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 1403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate /* 1413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * Global metadata: 1423a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * 14372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * int SDKversion -- the SDK version of the OS itself on the device 14472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * that produced this backup set. Used to reject 14572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * backups from later OSes onto earlier ones. 14672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * String incremental -- the incremental release name of the OS stored in 14772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * the backup set. 1483a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate */ 14972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (!mExisting.contains(GLOBAL_METADATA_KEY)) { 1508a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "Storing global metadata key"); 1513a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate outWriter.writeInt(Build.VERSION.SDK_INT); 15272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate outWriter.writeUTF(Build.VERSION.INCREMENTAL); 1533a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] metadata = bufStream.toByteArray(); 1543a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length); 1553a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityData(metadata, metadata.length); 1566785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } else { 1578a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "Global metadata key already stored"); 15872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // don't consider it to have been skipped/deleted 15972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.remove(GLOBAL_METADATA_KEY); 1603a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 1613a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1623a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // For each app we have on device, see if we've backed it up yet. If not, 1633a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // write its signature block to the output, keyed on the package name. 164efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (PackageInfo pkg : mAllPackages) { 165efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String packName = pkg.packageName; 1666f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate if (packName.equals(GLOBAL_METADATA_KEY)) { 1676f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate // We've already handled the metadata key; skip it here 1686f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate continue; 16972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 17072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate PackageInfo info = null; 1713a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 17272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate info = mPackageManager.getPackageInfo(packName, 1733a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate PackageManager.GET_SIGNATURES); 17472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } catch (NameNotFoundException e) { 17572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // Weird; we just found it, and now are told it doesn't exist. 17672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // Treat it as having been removed from the device. 17772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(packName); 17872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate continue; 17972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 18072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 18172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate boolean doBackup = false; 18272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (!mExisting.contains(packName)) { 18372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // We haven't backed up this app before 18472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate doBackup = true; 18572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 18672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // We *have* backed this one up before. Check whether the version 18772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // of the backup matches the version of the current app; if they 18872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // don't match, the app has been updated and we need to store its 18972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // metadata again. In either case, take it out of mExisting so that 19072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // we don't consider it deleted later. 19172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (info.versionCode != mStateVersions.get(packName).versionCode) { 19272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate doBackup = true; 19372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 19472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.remove(packName); 19572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 19672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 19772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (doBackup) { 19872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // We need to store this app's metadata 1993a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate /* 2003a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * Metadata for each package: 2013a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * 2023a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * int version -- [4] the package's versionCode 2033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * byte[] signatures -- [len] flattened Signature[] of the package 2043a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate */ 2053a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 20672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // marshal the version code in a canonical form 2073a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate bufStream.reset(); 2083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate outWriter.writeInt(info.versionCode); 2093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] versionBuf = bufStream.toByteArray(); 2103a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2113a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] sigs = flattenSignatureArray(info.signatures); 2123a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2133a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 2148a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.v(TAG, "+ metadata for " + packName 2153a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " version=" + info.versionCode 2163a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " versionLen=" + versionBuf.length 2173a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " sigsLen=" + sigs.length); 2183a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Now we can write the backup entity for this package 2203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(packName, versionBuf.length + sigs.length); 2213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityData(versionBuf, versionBuf.length); 2223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityData(sigs, sigs.length); 2233a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // At this point, the only entries in 'existing' are apps that were 2283a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // mentioned in the saved state file, but appear to no longer be present 2293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // on the device. Write a deletion entity for them. 23072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate for (String app : mExisting) { 2318a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "- removing metadata for deleted pkg " + app); 2323a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 2333a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(app, -1); 2343a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 2358a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to write package deletions!"); 2363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 2403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Real error writing data 2418a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to write package backup data file!"); 2423a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2456785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Finally, write the new state blob -- just the list of all apps we handled 246efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor writeStateFile(mAllPackages, newState); 2476785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // "Restore" here is a misnomer. What we're really doing is reading back the 2506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // set of app signatures associated with each backed-up app in this restore 2516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // image. We'll use those later to determine what we can legitimately restore. 2525cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) 2536785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate throws IOException { 2546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); 2556aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); 2568a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "onRestore()"); 2573a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate int storedSystemVersion = -1; 2586785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2596785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate while (data.readNextHeader()) { 2603a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate String key = data.getKey(); 2616785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int dataSize = data.getDataSize(); 2626785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2638a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); 2643a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2653a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // generic setup to parse any entity data 2663a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] dataBuf = new byte[dataSize]; 2673a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.readEntityData(dataBuf, 0, dataSize); 2683a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf); 2693a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate DataInputStream in = new DataInputStream(baStream); 2703a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2713a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (key.equals(GLOBAL_METADATA_KEY)) { 27272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate int storedSdkVersion = in.readInt(); 2738a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); 2743a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (storedSystemVersion > Build.VERSION.SDK_INT) { 2753a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // returning before setting the sig map means we rejected the restore set 2768a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.w(TAG, "Restore set was from a later version of Android; not restoring"); 2773a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2783a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 27972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = storedSdkVersion; 28072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = in.readUTF(); 2813d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate mHasMetadata = true; 2823a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 2838a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.i(TAG, "Restore set version " + storedSystemVersion 28472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + " is compatible with OS version " + Build.VERSION.SDK_INT 28572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + " (" + mStoredIncrementalVersion + " vs " 28672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + Build.VERSION.INCREMENTAL + ")"); 2873a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2883a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } else { 2893a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // it's a file metadata record 2903a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate int versionCode = in.readInt(); 2913a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Signature[] sigs = unflattenSignatureArray(in); 2923a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 2938a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.i(TAG, " restored metadata for " + key 2943a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " dataSize=" + dataSize 2953a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " versionCode=" + versionCode + " sigs=" + sigs); 2963a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2973a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2983a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate ApplicationInfo app = new ApplicationInfo(); 2993a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate app.packageName = key; 3003a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate restoredApps.add(app); 3013a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate sigMap.put(key, new Metadata(versionCode, sigs)); 3023a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 3036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3053a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // On successful completion, cache the signature map for the Backup Manager to use 3066785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mRestoredSignatures = sigMap; 3076785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3086785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3096785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Util: convert an array of Signatures into a flattened byte buffer. The 3116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // flattened format contains enough info to reconstruct the signature array. 3126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private byte[] flattenSignatureArray(Signature[] allSigs) { 3136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate ByteArrayOutputStream outBuf = new ByteArrayOutputStream(); 3146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataOutputStream out = new DataOutputStream(outBuf); 3156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3166785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // build the set of subsidiary buffers 3176785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 3186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // first the # of signatures in the array 3196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.writeInt(allSigs.length); 3206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // then the signatures themselves, length + flattened buffer 3226785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate for (Signature sig : allSigs) { 3236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] flat = sig.toByteArray(); 3246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.writeInt(flat.length); 3256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.write(flat); 3266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3276785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 3286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // very strange; we're writing to memory here. abort. 3296785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 3306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return outBuf.toByteArray(); 3336785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3346785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3356aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) { 3366785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate Signature[] sigs = null; 3376785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 3396785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int num = in.readInt(); 3408a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, " ... unflatten read " + num); 3415a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate 3425a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate // Sensical? 3435a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate if (num > 20) { 3448a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Suspiciously large sig count in restore data; aborting"); 3455a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate throw new IllegalStateException("Bad restore state"); 3465a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate } 3475a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate 3486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate sigs = new Signature[num]; 3496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate for (int i = 0; i < num; i++) { 3506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int len = in.readInt(); 3516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] flatSig = new byte[len]; 3526785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate in.read(flatSig); 3536785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate sigs[i] = new Signature(flatSig); 3546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3556785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (EOFException e) { 3566785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // clean termination 3576785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate if (sigs == null) { 3588a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.w(TAG, "Empty signature block found"); 3596785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3606785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 3618a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to unflatten sigs"); 3626785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 3636785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3646785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3656785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return sigs; 3666785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3676785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3686785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Util: parse out an existing state file into a usable structure 36972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private void parseStateFile(ParcelFileDescriptor stateFile) { 37072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.clear(); 37172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStateVersions.clear(); 37272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = 0; 37372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = null; 37472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 3756785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // The state file is just the list of app names we have stored signatures for 37672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // with the exception of the metadata block, to which is also appended the 37772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // version numbers corresponding with the last time we wrote this PM block. 37872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // If they mismatch the current system, we'll re-store the metadata key. 3796785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor()); 3806785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataInputStream in = new DataInputStream(instream); 3816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3826785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int bufSize = 256; 3836785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] buf = new byte[bufSize]; 3846785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 38572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate String pkg = in.readUTF(); 38672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (pkg.equals(GLOBAL_METADATA_KEY)) { 38772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = in.readInt(); 38872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = in.readUTF(); 38972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(GLOBAL_METADATA_KEY); 39072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 3918a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "No global metadata in state file!"); 39272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate return; 39372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 39472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 39572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // The global metadata was first; now read all the apps 39672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate while (true) { 39772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate pkg = in.readUTF(); 39872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate int versionCode = in.readInt(); 39972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(pkg); 40072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStateVersions.put(pkg, new Metadata(versionCode, null)); 4016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (EOFException eof) { 4036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // safe; we're done 4046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 4056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // whoops, bad state file. abort. 4068a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to read Package Manager state file: " + e); 4076785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4086785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4096785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 4103a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Util: write out our new backup state file 411efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) { 4126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); 4136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataOutputStream out = new DataOutputStream(outstream); 4146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 4153a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 4163a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // by the time we get here we know we've stored the global metadata record 41772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(GLOBAL_METADATA_KEY); 41872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeInt(Build.VERSION.SDK_INT); 41972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(Build.VERSION.INCREMENTAL); 4203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 4213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // now write all the app names too 422efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (PackageInfo pkg : pkgs) { 42372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(pkg.packageName); 42472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeInt(pkg.versionCode); 4256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4263a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 4278a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to write package manager state file!"); 4283a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 4296785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate} 432