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 125e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream(); // we'll reuse these 126e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown DataOutputStream outputBufferStream = new DataOutputStream(outputBuffer); 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"); 151e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown outputBufferStream.writeInt(Build.VERSION.SDK_INT); 152e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown outputBufferStream.writeUTF(Build.VERSION.INCREMENTAL); 153e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown writeEntity(data, GLOBAL_METADATA_KEY, outputBuffer.toByteArray()); 1546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } else { 1558a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "Global metadata key already stored"); 15672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // don't consider it to have been skipped/deleted 15772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.remove(GLOBAL_METADATA_KEY); 1583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 1593a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1603a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // For each app we have on device, see if we've backed it up yet. If not, 1613a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // write its signature block to the output, keyed on the package name. 162efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (PackageInfo pkg : mAllPackages) { 163efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String packName = pkg.packageName; 1646f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate if (packName.equals(GLOBAL_METADATA_KEY)) { 1656f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate // We've already handled the metadata key; skip it here 1666f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate continue; 16772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 16872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate PackageInfo info = null; 1693a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 17072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate info = mPackageManager.getPackageInfo(packName, 1713a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate PackageManager.GET_SIGNATURES); 17272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } catch (NameNotFoundException e) { 17372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // Weird; we just found it, and now are told it doesn't exist. 17472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // Treat it as having been removed from the device. 17572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(packName); 17672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate continue; 17772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 17872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 179e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (mExisting.contains(packName)) { 180e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // We have backed up this app before. Check whether the version 18172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // of the backup matches the version of the current app; if they 18272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // don't match, the app has been updated and we need to store its 18372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // metadata again. In either case, take it out of mExisting so that 18472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // we don't consider it deleted later. 18572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.remove(packName); 186e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (info.versionCode == mStateVersions.get(packName).versionCode) { 187e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown continue; 188e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 189e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 190e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 191e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (info.signatures == null || info.signatures.length == 0) 192e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown { 193e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.w(TAG, "Not backing up package " + packName 194e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown + " since it appears to have no signatures."); 195e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown continue; 19672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 19772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 198e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // We need to store this app's metadata 199e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown /* 200e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown * Metadata for each package: 201e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown * 202e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown * int version -- [4] the package's versionCode 203e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown * byte[] signatures -- [len] flattened Signature[] of the package 204e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown */ 205e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 206e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // marshal the version code in a canonical form 207e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown outputBuffer.reset(); 208e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown outputBufferStream.writeInt(info.versionCode); 209e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown writeSignatureArray(outputBufferStream, info.signatures); 210e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 211e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (DEBUG) { 212e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.v(TAG, "+ writing metadata for " + packName 213e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown + " version=" + info.versionCode 214e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown + " entityLen=" + outputBuffer.size()); 2153a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 216e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 217e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // Now we can write the backup entity for this package 218e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown writeEntity(data, packName, outputBuffer.toByteArray()); 2196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // At this point, the only entries in 'existing' are apps that were 2233a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // mentioned in the saved state file, but appear to no longer be present 2243a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // on the device. Write a deletion entity for them. 22572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate for (String app : mExisting) { 2268a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "- removing metadata for deleted pkg " + app); 2273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 2283a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(app, -1); 2293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 2308a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to write package deletions!"); 2313a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2323a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2336785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2343a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 2353a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Real error writing data 2368a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to write package backup data file!"); 2373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2396785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2406785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Finally, write the new state blob -- just the list of all apps we handled 241efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor writeStateFile(mAllPackages, newState); 2426785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 243e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 244e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown private static void writeEntity(BackupDataOutput data, String key, byte[] bytes) 245e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown throws IOException { 246e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown data.writeEntityHeader(key, bytes.length); 247e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown data.writeEntityData(bytes, bytes.length); 248e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 2496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // "Restore" here is a misnomer. What we're really doing is reading back the 2516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // set of app signatures associated with each backed-up app in this restore 2526785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // image. We'll use those later to determine what we can legitimately restore. 2535cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) 2546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate throws IOException { 2556785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); 2566aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); 2578a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "onRestore()"); 2583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate int storedSystemVersion = -1; 2596785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2606785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate while (data.readNextHeader()) { 2613a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate String key = data.getKey(); 2626785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int dataSize = data.getDataSize(); 2636785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2648a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); 2653a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2663a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // generic setup to parse any entity data 267e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown byte[] inputBytes = new byte[dataSize]; 268e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown data.readEntityData(inputBytes, 0, dataSize); 269e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes); 270e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown DataInputStream inputBufferStream = new DataInputStream(inputBuffer); 2713a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2723a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (key.equals(GLOBAL_METADATA_KEY)) { 273e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown int storedSdkVersion = inputBufferStream.readInt(); 2748a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); 2753a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (storedSystemVersion > Build.VERSION.SDK_INT) { 2763a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // returning before setting the sig map means we rejected the restore set 2778a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.w(TAG, "Restore set was from a later version of Android; not restoring"); 2783a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2793a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 28072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = storedSdkVersion; 281e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown mStoredIncrementalVersion = inputBufferStream.readUTF(); 2823d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate mHasMetadata = true; 2833a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 2848a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.i(TAG, "Restore set version " + storedSystemVersion 28572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + " is compatible with OS version " + Build.VERSION.SDK_INT 28672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + " (" + mStoredIncrementalVersion + " vs " 28772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + Build.VERSION.INCREMENTAL + ")"); 2883a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2893a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } else { 2903a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // it's a file metadata record 291e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown int versionCode = inputBufferStream.readInt(); 292e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Signature[] sigs = readSignatureArray(inputBufferStream); 2933a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 294e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.i(TAG, " read metadata for " + key 2953a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " dataSize=" + dataSize 2963a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " versionCode=" + versionCode + " sigs=" + sigs); 2973a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 298e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 299e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (sigs == null || sigs.length == 0) { 300e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.w(TAG, "Not restoring package " + key 301e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown + " since it appears to have no signatures."); 302e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown continue; 303e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 3043a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 3053a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate ApplicationInfo app = new ApplicationInfo(); 3063a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate app.packageName = key; 3073a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate restoredApps.add(app); 3083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate sigMap.put(key, new Metadata(versionCode, sigs)); 3093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 3106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3123a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // On successful completion, cache the signature map for the Backup Manager to use 3136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mRestoredSignatures = sigMap; 3146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 316e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown private static void writeSignatureArray(DataOutputStream out, Signature[] sigs) 317e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown throws IOException { 318e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // write the number of signatures in the array 319e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown out.writeInt(sigs.length); 320e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 321e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // write the signatures themselves, length + flattened buffer 322e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown for (Signature sig : sigs) { 323e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown byte[] flat = sig.toByteArray(); 324e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown out.writeInt(flat.length); 325e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown out.write(flat); 3266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3276785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 329e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown private static Signature[] readSignatureArray(DataInputStream in) { 3306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 331e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown int num; 332e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown try { 333e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown num = in.readInt(); 334e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } catch (EOFException e) { 335e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // clean termination 336e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.w(TAG, "Read empty signature block"); 337e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown return null; 338e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 339e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 3408a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, " ... unflatten read " + num); 341e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 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 } 347e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 348e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Signature[] 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 } 355e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown return sigs; 3566785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 357e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.e(TAG, "Unable to read signatures"); 3586785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 3596785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3606785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3616785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3626785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Util: parse out an existing state file into a usable structure 36372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private void parseStateFile(ParcelFileDescriptor stateFile) { 36472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.clear(); 36572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStateVersions.clear(); 36672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = 0; 36772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = null; 36872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 3696785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // The state file is just the list of app names we have stored signatures for 37072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // with the exception of the metadata block, to which is also appended the 37172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // version numbers corresponding with the last time we wrote this PM block. 37272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // If they mismatch the current system, we'll re-store the metadata key. 3736785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor()); 3746785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataInputStream in = new DataInputStream(instream); 3756785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3766785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int bufSize = 256; 3776785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] buf = new byte[bufSize]; 3786785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 37972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate String pkg = in.readUTF(); 38072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (pkg.equals(GLOBAL_METADATA_KEY)) { 38172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = in.readInt(); 38272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = in.readUTF(); 38372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(GLOBAL_METADATA_KEY); 38472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 3858a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "No global metadata in state file!"); 38672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate return; 38772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 38872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 38972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // The global metadata was first; now read all the apps 39072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate while (true) { 39172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate pkg = in.readUTF(); 39272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate int versionCode = in.readInt(); 39372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(pkg); 39472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStateVersions.put(pkg, new Metadata(versionCode, null)); 3956785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (EOFException eof) { 3976785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // safe; we're done 3986785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 3996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // whoops, bad state file. abort. 4008a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to read Package Manager state file: " + e); 4016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 4043a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Util: write out our new backup state file 405efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) { 4066785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); 4076785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataOutputStream out = new DataOutputStream(outstream); 4086785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 4093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 4103a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // by the time we get here we know we've stored the global metadata record 41172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(GLOBAL_METADATA_KEY); 41272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeInt(Build.VERSION.SDK_INT); 41372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(Build.VERSION.INCREMENTAL); 4143a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 4153a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // now write all the app names too 416efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (PackageInfo pkg : pkgs) { 41772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(pkg.packageName); 41872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeInt(pkg.versionCode); 4196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 4218a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to write package manager state file!"); 4223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 4236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate} 426