PackageManagerBackupAgent.java revision a99d02170bc0e54f729b2b735571c8eea8d5034d
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 1709e9cdceceb722643e2c80c6544d44a43d7f95f0Amith Yamasanipackage com.android.server.backup; 186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 194528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.BackupAgent; 204528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.BackupDataInput; 214528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.BackupDataOutput; 22a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tateimport android.content.ComponentName; 236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.ApplicationInfo; 246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.PackageInfo; 256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.PackageManager; 26a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tateimport android.content.pm.ResolveInfo; 276785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.PackageManager.NameNotFoundException; 286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.Signature; 293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tateimport android.os.Build; 306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.os.ParcelFileDescriptor; 318a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog; 326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 33a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tateimport java.io.BufferedInputStream; 34a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tateimport java.io.BufferedOutputStream; 356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.ByteArrayInputStream; 366785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.ByteArrayOutputStream; 376785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.DataInputStream; 386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.DataOutputStream; 396785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.EOFException; 406785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.FileInputStream; 416785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.FileOutputStream; 426785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.IOException; 436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.ArrayList; 446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.HashMap; 456785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.HashSet; 466785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.List; 47b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tateimport java.util.Set; 486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 49a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tateimport java.util.Objects; 50a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate/** 526785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * We back up the signatures of each package so that during a system restore, 536785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * we can verify that the app whose data we think we have matches the app 546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * actually resident on the device. 556785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * 566785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Since the Package Manager isn't a proper "application" we just provide a 576785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * direct IBackupAgent implementation and hand-construct it at need. 586785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate */ 596785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tatepublic class PackageManagerBackupAgent extends BackupAgent { 606785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private static final String TAG = "PMBA"; 61b808a939328b935592d9259e06c66b433a13c1a9Christopher Tate private static final boolean DEBUG = false; 626785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 633a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // key under which we store global metadata (individual app metadata 643a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // is stored using the package name as a key) 653a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate private static final String GLOBAL_METADATA_KEY = "@meta@"; 663a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 67a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // key under which we store the identity of the user's chosen default home app 68a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private static final String DEFAULT_HOME_KEY = "@home@"; 69a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 70efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private List<PackageInfo> mAllPackages; 716785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private PackageManager mPackageManager; 7272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // version & signature info of each app in a restore set 736aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate private HashMap<String, Metadata> mRestoredSignatures; 7472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // The version info of each backed-up app as read from the state file 7572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private HashMap<String, Metadata> mStateVersions = new HashMap<String, Metadata>(); 7672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 7772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private final HashSet<String> mExisting = new HashSet<String>(); 7872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private int mStoredSdkVersion; 7972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private String mStoredIncrementalVersion; 80a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private ComponentName mStoredHomeComponent; 81a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private long mStoredHomeVersion; 82a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private Signature[] mStoredHomeSigs; 83a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 843d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate private boolean mHasMetadata; 85a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private ComponentName mRestoredHome; 86a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private long mRestoredHomeVersion; 87a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private String mRestoredHomeInstaller; 88a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private Signature[] mRestoredHomeSignatures; 896aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate 906aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public class Metadata { 916aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public int versionCode; 926aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public Signature[] signatures; 936aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate 946aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate Metadata(int version, Signature[] sigs) { 956aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate versionCode = version; 966aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate signatures = sigs; 976aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate } 986aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate } 996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 1006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // We're constructed with the set of applications that are participating 1016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // in backup. This set changes as apps are installed & removed. 102efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) { 1036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mPackageManager = packageMgr; 104efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mAllPackages = packages; 1056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mRestoredSignatures = null; 1063d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate mHasMetadata = false; 1073d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate } 1083d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate 1093d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate public boolean hasMetadata() { 1103d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate return mHasMetadata; 1116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 1126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 1136aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public Metadata getRestoredMetadata(String packageName) { 1146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate if (mRestoredSignatures == null) { 1158a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.w(TAG, "getRestoredMetadata() before metadata read!"); 1166785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 1176785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 1186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 1196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return mRestoredSignatures.get(packageName); 1206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 121b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate 122b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate public Set<String> getRestoredPackages() { 123b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate if (mRestoredSignatures == null) { 1248a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.w(TAG, "getRestoredPackages() before metadata read!"); 125b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate return null; 126b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate } 127b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate 128b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // This is technically the set of packages on the originating handset 129b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // that had backup agents at all, not limited to the set of packages 130b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // that had actually contributed a restore dataset, but it's a 131b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // close enough approximation for our purposes and does not require any 132b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate // additional involvement by the transport to obtain. 133b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate return mRestoredSignatures.keySet(); 134b49ceb3b8b17656984fd969d548dc912e7d2c7c1Christopher Tate } 1356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 1366785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // The backed up data is the signature block for each app, keyed by 1376785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // the package name. 1386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 1396785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate ParcelFileDescriptor newState) { 1408a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "onBackup()"); 1413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 142e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream(); // we'll reuse these 143e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown DataOutputStream outputBufferStream = new DataOutputStream(outputBuffer); 14472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate parseStateFile(oldState); 14572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 14672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // If the stored version string differs, we need to re-backup all 14772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // of the metadata. We force this by removing everything from the 14872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // "already backed up" map built by parseStateFile(). 14972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (mStoredIncrementalVersion == null 15072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate || !mStoredIncrementalVersion.equals(Build.VERSION.INCREMENTAL)) { 1518a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.i(TAG, "Previous metadata " + mStoredIncrementalVersion + " mismatch vs " 15272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + Build.VERSION.INCREMENTAL + " - rewriting"); 15372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.clear(); 15472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 1553a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 156a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate long homeVersion = 0; 157a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate Signature[] homeSigs = null; 158a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate PackageInfo homeInfo = null; 159a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate String homeInstaller = null; 160a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate ComponentName home = getPreferredHomeComponent(); 161a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate if (home != null) { 162a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate try { 163a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate homeInfo = mPackageManager.getPackageInfo(home.getPackageName(), 164a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate PackageManager.GET_SIGNATURES); 165a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName()); 166a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate homeVersion = homeInfo.versionCode; 167a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate homeSigs = homeInfo.signatures; 168a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } catch (NameNotFoundException e) { 169a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate Slog.w(TAG, "Can't access preferred home info"); 170a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // proceed as though there were no preferred home set 171a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate home = null; 172a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } 173a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } 174a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 1753a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 176a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // We need to push a new preferred-home-app record if: 177a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // 1. the version of the home app has changed since our last backup; 178a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // 2. the home app [or absence] we now use differs from the prior state, 179a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // OR 3. it looks like we use the same home app + version as before, but 180a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // the signatures don't match so we treat them as different apps. 181a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate final boolean needHomeBackup = (homeVersion != mStoredHomeVersion) 182a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate || Objects.equals(home, mStoredHomeComponent) 183a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate || (home != null 184a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate && !BackupManagerService.signaturesMatch(mStoredHomeSigs, homeInfo)); 185a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate if (needHomeBackup) { 186a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate if (DEBUG) { 187a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate Slog.i(TAG, "Home preference changed; backing up new state " + home); 188a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } 189a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate if (home != null) { 190a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate outputBufferStream.writeUTF(home.flattenToString()); 191a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate outputBufferStream.writeLong(homeVersion); 192a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate outputBufferStream.writeUTF(homeInstaller); 193a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate writeSignatureArray(outputBufferStream, homeSigs); 194a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate writeEntity(data, DEFAULT_HOME_KEY, outputBuffer.toByteArray()); 195a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } else { 196a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate data.writeEntityHeader(DEFAULT_HOME_KEY, -1); 197a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } 198a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } 199a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 2003a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate /* 2013a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * Global metadata: 2023a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * 20372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * int SDKversion -- the SDK version of the OS itself on the device 20472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * that produced this backup set. Used to reject 20572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * backups from later OSes onto earlier ones. 20672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * String incremental -- the incremental release name of the OS stored in 20772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * the backup set. 2083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate */ 209a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate outputBuffer.reset(); 21072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (!mExisting.contains(GLOBAL_METADATA_KEY)) { 2118a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "Storing global metadata key"); 212e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown outputBufferStream.writeInt(Build.VERSION.SDK_INT); 213e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown outputBufferStream.writeUTF(Build.VERSION.INCREMENTAL); 214e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown writeEntity(data, GLOBAL_METADATA_KEY, outputBuffer.toByteArray()); 2156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } else { 2168a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "Global metadata key already stored"); 21772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // don't consider it to have been skipped/deleted 21872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.remove(GLOBAL_METADATA_KEY); 2193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // For each app we have on device, see if we've backed it up yet. If not, 2223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // write its signature block to the output, keyed on the package name. 223efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (PackageInfo pkg : mAllPackages) { 224efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String packName = pkg.packageName; 2256f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate if (packName.equals(GLOBAL_METADATA_KEY)) { 2266f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate // We've already handled the metadata key; skip it here 2276f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate continue; 22872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 22972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate PackageInfo info = null; 2303a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 23172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate info = mPackageManager.getPackageInfo(packName, 2323a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate PackageManager.GET_SIGNATURES); 23372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } catch (NameNotFoundException e) { 23472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // Weird; we just found it, and now are told it doesn't exist. 23572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // Treat it as having been removed from the device. 23672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(packName); 23772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate continue; 23872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 23972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 240e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (mExisting.contains(packName)) { 241e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // We have backed up this app before. Check whether the version 24272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // of the backup matches the version of the current app; if they 24372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // don't match, the app has been updated and we need to store its 24472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // metadata again. In either case, take it out of mExisting so that 24572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // we don't consider it deleted later. 24672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.remove(packName); 247e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (info.versionCode == mStateVersions.get(packName).versionCode) { 248e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown continue; 249e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 250e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 251e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 252e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (info.signatures == null || info.signatures.length == 0) 253e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown { 254e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.w(TAG, "Not backing up package " + packName 255e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown + " since it appears to have no signatures."); 256e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown continue; 25772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 25872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 259e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // We need to store this app's metadata 260e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown /* 261e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown * Metadata for each package: 262e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown * 263e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown * int version -- [4] the package's versionCode 264e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown * byte[] signatures -- [len] flattened Signature[] of the package 265e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown */ 266e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 267e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // marshal the version code in a canonical form 268e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown outputBuffer.reset(); 269e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown outputBufferStream.writeInt(info.versionCode); 270e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown writeSignatureArray(outputBufferStream, info.signatures); 271e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 272e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (DEBUG) { 273e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.v(TAG, "+ writing metadata for " + packName 274e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown + " version=" + info.versionCode 275e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown + " entityLen=" + outputBuffer.size()); 2763a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 277e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 278e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // Now we can write the backup entity for this package 279e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown writeEntity(data, packName, outputBuffer.toByteArray()); 2806785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2826785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2833a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // At this point, the only entries in 'existing' are apps that were 2843a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // mentioned in the saved state file, but appear to no longer be present 2853a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // on the device. Write a deletion entity for them. 28672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate for (String app : mExisting) { 2878a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "- removing metadata for deleted pkg " + app); 2883a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 2893a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(app, -1); 2903a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 2918a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to write package deletions!"); 2923a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2933a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2953a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 2963a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Real error writing data 2978a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to write package backup data file!"); 2983a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Finally, write the new state blob -- just the list of all apps we handled 302a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate writeStateFile(mAllPackages, home, homeVersion, homeSigs, newState); 3036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 304e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 305e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown private static void writeEntity(BackupDataOutput data, String key, byte[] bytes) 306e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown throws IOException { 307e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown data.writeEntityHeader(key, bytes.length); 308e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown data.writeEntityData(bytes, bytes.length); 309e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 3106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // "Restore" here is a misnomer. What we're really doing is reading back the 3126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // set of app signatures associated with each backed-up app in this restore 3136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // image. We'll use those later to determine what we can legitimately restore. 3145cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) 3156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate throws IOException { 3166785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); 3176aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); 3188a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, "onRestore()"); 3193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate int storedSystemVersion = -1; 3206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate while (data.readNextHeader()) { 3223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate String key = data.getKey(); 3236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int dataSize = data.getDataSize(); 3246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3258a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize); 3263a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 3273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // generic setup to parse any entity data 328e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown byte[] inputBytes = new byte[dataSize]; 329e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown data.readEntityData(inputBytes, 0, dataSize); 330e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes); 331e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown DataInputStream inputBufferStream = new DataInputStream(inputBuffer); 3323a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 3333a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (key.equals(GLOBAL_METADATA_KEY)) { 334e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown int storedSdkVersion = inputBufferStream.readInt(); 3358a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion); 3363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (storedSystemVersion > Build.VERSION.SDK_INT) { 3373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // returning before setting the sig map means we rejected the restore set 3388a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.w(TAG, "Restore set was from a later version of Android; not restoring"); 3393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 3403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 34172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = storedSdkVersion; 342e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown mStoredIncrementalVersion = inputBufferStream.readUTF(); 3433d7cd13e772bde1c4a72fa4e740baa03cb042e6cChristopher Tate mHasMetadata = true; 3443a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 3458a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.i(TAG, "Restore set version " + storedSystemVersion 34672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + " is compatible with OS version " + Build.VERSION.SDK_INT 34772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + " (" + mStoredIncrementalVersion + " vs " 34872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + Build.VERSION.INCREMENTAL + ")"); 3493a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 350a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } else if (key.equals(DEFAULT_HOME_KEY)) { 351a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate String cn = inputBufferStream.readUTF(); 352a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mRestoredHome = ComponentName.unflattenFromString(cn); 353a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mRestoredHomeVersion = inputBufferStream.readLong(); 354a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mRestoredHomeInstaller = inputBufferStream.readUTF(); 355a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mRestoredHomeSignatures = readSignatureArray(inputBufferStream); 356a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate if (DEBUG) { 357a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate Slog.i(TAG, " read preferred home app " + mRestoredHome 358a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate + " version=" + mRestoredHomeVersion 359a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate + " installer=" + mRestoredHomeVersion 360a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate + " sig=" + mRestoredHomeVersion); 361a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } 362a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 3633a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } else { 3643a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // it's a file metadata record 365e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown int versionCode = inputBufferStream.readInt(); 366e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Signature[] sigs = readSignatureArray(inputBufferStream); 3673a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 368e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.i(TAG, " read metadata for " + key 3693a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " dataSize=" + dataSize 3703a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " versionCode=" + versionCode + " sigs=" + sigs); 3713a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 372e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 373e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown if (sigs == null || sigs.length == 0) { 374e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.w(TAG, "Not restoring package " + key 375e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown + " since it appears to have no signatures."); 376e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown continue; 377e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 3783a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 3793a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate ApplicationInfo app = new ApplicationInfo(); 3803a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate app.packageName = key; 3813a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate restoredApps.add(app); 3823a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate sigMap.put(key, new Metadata(versionCode, sigs)); 3833a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 3846785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3856785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3863a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // On successful completion, cache the signature map for the Backup Manager to use 3876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mRestoredSignatures = sigMap; 3886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 390e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown private static void writeSignatureArray(DataOutputStream out, Signature[] sigs) 391e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown throws IOException { 392e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // write the number of signatures in the array 393e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown out.writeInt(sigs.length); 394e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 395e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // write the signatures themselves, length + flattened buffer 396e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown for (Signature sig : sigs) { 397e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown byte[] flat = sig.toByteArray(); 398e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown out.writeInt(flat.length); 399e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown out.write(flat); 4006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 403e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown private static Signature[] readSignatureArray(DataInputStream in) { 4046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 405e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown int num; 406e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown try { 407e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown num = in.readInt(); 408e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } catch (EOFException e) { 409e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown // clean termination 410e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.w(TAG, "Read empty signature block"); 411e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown return null; 412e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown } 413e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 4148a9b22056b13477f59df934928c00c58b5871c95Joe Onorato if (DEBUG) Slog.v(TAG, " ... unflatten read " + num); 415e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 4165a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate // Sensical? 4175a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate if (num > 20) { 4188a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Suspiciously large sig count in restore data; aborting"); 4195a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate throw new IllegalStateException("Bad restore state"); 4205a8a1151e267b29978f219f9569fdfc5e74cc210Christopher Tate } 421e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown 422e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Signature[] sigs = new Signature[num]; 4236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate for (int i = 0; i < num; i++) { 4246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int len = in.readInt(); 4256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] flatSig = new byte[len]; 4266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate in.read(flatSig); 4276785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate sigs[i] = new Signature(flatSig); 4286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 429e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown return sigs; 4306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 431e684d9582cedf9bd5cc6c6fe47c600a79a13d816Jeff Brown Slog.e(TAG, "Unable to read signatures"); 4326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 4336785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4346785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 4366785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Util: parse out an existing state file into a usable structure 43772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private void parseStateFile(ParcelFileDescriptor stateFile) { 43872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.clear(); 43972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStateVersions.clear(); 44072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = 0; 44172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = null; 442a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mStoredHomeComponent = null; 443a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mStoredHomeVersion = 0; 444a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mStoredHomeSigs = null; 44572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 4466785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // The state file is just the list of app names we have stored signatures for 44772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // with the exception of the metadata block, to which is also appended the 44872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // version numbers corresponding with the last time we wrote this PM block. 44972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // If they mismatch the current system, we'll re-store the metadata key. 4506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor()); 451a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate BufferedInputStream inbuffer = new BufferedInputStream(instream); 452a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate DataInputStream in = new DataInputStream(inbuffer); 4536785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 4546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 45572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate String pkg = in.readUTF(); 456a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 457a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // First comes the preferred home app data, if any, headed by the DEFAULT_HOME_KEY tag 458a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate if (pkg.equals(DEFAULT_HOME_KEY)) { 459a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // flattened component name, version, signature of the home app 460a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mStoredHomeComponent = ComponentName.unflattenFromString(in.readUTF()); 461a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mStoredHomeVersion = in.readLong(); 462a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate mStoredHomeSigs = readSignatureArray(in); 463a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 464a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate pkg = in.readUTF(); // set up for the next block of state 465a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } else { 466a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // else no preferred home app on the ancestral device - fall through to the rest 467a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } 468a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 469a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // After (possible) home app data comes the global metadata block 47072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (pkg.equals(GLOBAL_METADATA_KEY)) { 47172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = in.readInt(); 47272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = in.readUTF(); 47372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(GLOBAL_METADATA_KEY); 47472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 4758a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "No global metadata in state file!"); 47672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate return; 47772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 47872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 479a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // The global metadata was last; now read all the apps 48072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate while (true) { 48172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate pkg = in.readUTF(); 48272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate int versionCode = in.readInt(); 48372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(pkg); 48472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStateVersions.put(pkg, new Metadata(versionCode, null)); 4856785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (EOFException eof) { 4876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // safe; we're done 4886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 4896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // whoops, bad state file. abort. 4908a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to read Package Manager state file: " + e); 4916785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 494a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private ComponentName getPreferredHomeComponent() { 495a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate return mPackageManager.getHomeActivities(new ArrayList<ResolveInfo>()); 496a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } 497a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 4983a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Util: write out our new backup state file 499a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate private void writeStateFile(List<PackageInfo> pkgs, ComponentName preferredHome, 500a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate long homeVersion, Signature[] homeSignatures, ParcelFileDescriptor stateFile) { 5016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); 502a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate BufferedOutputStream outbuf = new BufferedOutputStream(outstream); 503a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate DataOutputStream out = new DataOutputStream(outbuf); 5046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 505a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // by the time we get here we know we've done all our backing up 5063a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 507a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // If we remembered a preferred home app, record that 508a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate if (preferredHome != null) { 509a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate out.writeUTF(DEFAULT_HOME_KEY); 510a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate out.writeUTF(preferredHome.flattenToString()); 511a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate out.writeLong(homeVersion); 512a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate writeSignatureArray(out, homeSignatures); 513a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate } 514a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 515a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate // Conclude with the metadata block 51672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(GLOBAL_METADATA_KEY); 51772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeInt(Build.VERSION.SDK_INT); 51872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(Build.VERSION.INCREMENTAL); 5193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 5203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // now write all the app names too 521efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (PackageInfo pkg : pkgs) { 52272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(pkg.packageName); 52372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeInt(pkg.versionCode); 5246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 525a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate 526a99d02170bc0e54f729b2b735571c8eea8d5034dChristopher Tate out.flush(); 5273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 5288a9b22056b13477f59df934928c00c58b5871c95Joe Onorato Slog.e(TAG, "Unable to write package manager state file!"); 5296785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 5306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 5316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate} 532