PackageManagerBackupAgent.java revision 72d19aa51e90d45c7895629db78e548da2f6d469
16785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate/* 26785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Copyright (C) 2009 The Android Open Source Project 36785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * 46785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Licensed under the Apache License, Version 2.0 (the "License"); 56785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * you may not use this file except in compliance with the License. 66785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * You may obtain a copy of the License at 76785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * 86785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * http://www.apache.org/licenses/LICENSE-2.0 96785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * 106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Unless required by applicable law or agreed to in writing, software 116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * distributed under the License is distributed on an "AS IS" BASIS, 126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * See the License for the specific language governing permissions and 146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * limitations under the License. 156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate */ 166785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 176785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tatepackage com.android.server; 186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.app.BackupAgent; 206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.backup.BackupDataInput; 216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.backup.BackupDataOutput; 226785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.ApplicationInfo; 236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.PackageInfo; 246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.PackageManager; 256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.PackageManager.NameNotFoundException; 266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.content.pm.Signature; 273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tateimport android.os.Build; 286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.os.ParcelFileDescriptor; 296785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport android.util.Log; 306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.ByteArrayInputStream; 326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.ByteArrayOutputStream; 336785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.DataInputStream; 346785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.DataOutputStream; 356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.EOFException; 366785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.FileInputStream; 376785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.FileOutputStream; 386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.io.IOException; 396785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.ArrayList; 406785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.HashMap; 416785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.HashSet; 426785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tateimport java.util.List; 436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate/** 456785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * We back up the signatures of each package so that during a system restore, 466785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * we can verify that the app whose data we think we have matches the app 476785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * actually resident on the device. 486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * 496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * Since the Package Manager isn't a proper "application" we just provide a 506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate * direct IBackupAgent implementation and hand-construct it at need. 516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate */ 526785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tatepublic class PackageManagerBackupAgent extends BackupAgent { 536785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private static final String TAG = "PMBA"; 546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private static final boolean DEBUG = true; 556785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 563a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // key under which we store global metadata (individual app metadata 573a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // is stored using the package name as a key) 583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate private static final String GLOBAL_METADATA_KEY = "@meta@"; 593a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 60efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private List<PackageInfo> mAllPackages; 616785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private PackageManager mPackageManager; 6272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // version & signature info of each app in a restore set 636aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate private HashMap<String, Metadata> mRestoredSignatures; 6472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // The version info of each backed-up app as read from the state file 6572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private HashMap<String, Metadata> mStateVersions = new HashMap<String, Metadata>(); 6672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 6772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private final HashSet<String> mExisting = new HashSet<String>(); 6872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private int mStoredSdkVersion; 6972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private String mStoredIncrementalVersion; 706aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate 716aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public class Metadata { 726aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public int versionCode; 736aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public Signature[] signatures; 746aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate 756aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate Metadata(int version, Signature[] sigs) { 766aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate versionCode = version; 776aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate signatures = sigs; 786aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate } 796aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate } 806785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // We're constructed with the set of applications that are participating 826785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // in backup. This set changes as apps are installed & removed. 83efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) { 846785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mPackageManager = packageMgr; 85efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mAllPackages = packages; 866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mRestoredSignatures = null; 876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 896aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public Metadata getRestoredMetadata(String packageName) { 906785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate if (mRestoredSignatures == null) { 913a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.w(TAG, "getRestoredMetadata() before metadata read!"); 926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 956785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return mRestoredSignatures.get(packageName); 966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 976785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 986785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // The backed up data is the signature block for each app, keyed by 996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // the package name. 1006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 1016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate ParcelFileDescriptor newState) { 1026aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate if (DEBUG) Log.v(TAG, "onBackup()"); 1033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1046aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these 1056aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate DataOutputStream outWriter = new DataOutputStream(bufStream); 10672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate parseStateFile(oldState); 10772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 10872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // If the stored version string differs, we need to re-backup all 10972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // of the metadata. We force this by removing everything from the 11072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // "already backed up" map built by parseStateFile(). 11172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (mStoredIncrementalVersion == null 11272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate || !mStoredIncrementalVersion.equals(Build.VERSION.INCREMENTAL)) { 11372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate Log.i(TAG, "Previous metadata " + mStoredIncrementalVersion + " mismatch vs " 11472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + Build.VERSION.INCREMENTAL + " - rewriting"); 11572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.clear(); 11672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 1173a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1183a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 1193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate /* 1203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * Global metadata: 1213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * 12272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * int SDKversion -- the SDK version of the OS itself on the device 12372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * that produced this backup set. Used to reject 12472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * backups from later OSes onto earlier ones. 12572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * String incremental -- the incremental release name of the OS stored in 12672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate * the backup set. 1273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate */ 12872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (!mExisting.contains(GLOBAL_METADATA_KEY)) { 1293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, "Storing global metadata key"); 1303a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate outWriter.writeInt(Build.VERSION.SDK_INT); 13172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate outWriter.writeUTF(Build.VERSION.INCREMENTAL); 1323a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] metadata = bufStream.toByteArray(); 1333a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length); 1343a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityData(metadata, metadata.length); 1356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } else { 1363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, "Global metadata key already stored"); 13772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // don't consider it to have been skipped/deleted 13872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.remove(GLOBAL_METADATA_KEY); 1393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 1403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // For each app we have on device, see if we've backed it up yet. If not, 1423a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // write its signature block to the output, keyed on the package name. 143efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (PackageInfo pkg : mAllPackages) { 144efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String packName = pkg.packageName; 1456f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate if (packName.equals(GLOBAL_METADATA_KEY)) { 1466f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate // We've already handled the metadata key; skip it here 1476f317426e49e73ef3e50d8839877504039cd2fcaChristopher Tate continue; 14872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 14972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate PackageInfo info = null; 1503a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 15172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate info = mPackageManager.getPackageInfo(packName, 1523a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate PackageManager.GET_SIGNATURES); 15372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } catch (NameNotFoundException e) { 15472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // Weird; we just found it, and now are told it doesn't exist. 15572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // Treat it as having been removed from the device. 15672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(packName); 15772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate continue; 15872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 15972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 16072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate boolean doBackup = false; 16172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (!mExisting.contains(packName)) { 16272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // We haven't backed up this app before 16372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate doBackup = true; 16472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 16572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // We *have* backed this one up before. Check whether the version 16672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // of the backup matches the version of the current app; if they 16772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // don't match, the app has been updated and we need to store its 16872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // metadata again. In either case, take it out of mExisting so that 16972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // we don't consider it deleted later. 17072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (info.versionCode != mStateVersions.get(packName).versionCode) { 17172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate doBackup = true; 17272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 17372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.remove(packName); 17472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 17572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 17672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (doBackup) { 17772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // We need to store this app's metadata 1783a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate /* 1793a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * Metadata for each package: 1803a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * 1813a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * int version -- [4] the package's versionCode 1823a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * byte[] signatures -- [len] flattened Signature[] of the package 1833a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate */ 1843a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 18572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // marshal the version code in a canonical form 1863a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate bufStream.reset(); 1873a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate outWriter.writeInt(info.versionCode); 1883a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] versionBuf = bufStream.toByteArray(); 1893a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1903a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] sigs = flattenSignatureArray(info.signatures); 1913a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1923a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // !!! TODO: take out this debugging 1933a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 1943a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.v(TAG, "+ metadata for " + packName 1953a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " version=" + info.versionCode 1963a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " versionLen=" + versionBuf.length 1973a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " sigsLen=" + sigs.length); 1983a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 1993a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Now we can write the backup entity for this package 2003a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(packName, versionBuf.length + sigs.length); 2013a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityData(versionBuf, versionBuf.length); 2023a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityData(sigs, sigs.length); 2033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2066785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2073a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // At this point, the only entries in 'existing' are apps that were 2083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // mentioned in the saved state file, but appear to no longer be present 2093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // on the device. Write a deletion entity for them. 21072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate for (String app : mExisting) { 2113a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // !!! TODO: take out this msg 2123a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app); 2133a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 2143a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(app, -1); 2153a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 2163a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.e(TAG, "Unable to write package deletions!"); 2173a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2183a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 2213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Real error writing data 2223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.e(TAG, "Unable to write package backup data file!"); 2233a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Finally, write the new state blob -- just the list of all apps we handled 227efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor writeStateFile(mAllPackages, newState); 2286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2296785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // "Restore" here is a misnomer. What we're really doing is reading back the 2316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // set of app signatures associated with each backed-up app in this restore 2326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // image. We'll use those later to determine what we can legitimately restore. 2335cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) 2346785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate throws IOException { 2356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); 2366aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); 2373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, "onRestore()"); 2383a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate int storedSystemVersion = -1; 2396785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2406785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate while (data.readNextHeader()) { 2413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate String key = data.getKey(); 2426785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int dataSize = data.getDataSize(); 2436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2443a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, " got key=" + key + " dataSize=" + dataSize); 2453a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2463a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // generic setup to parse any entity data 2473a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] dataBuf = new byte[dataSize]; 2483a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.readEntityData(dataBuf, 0, dataSize); 2493a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf); 2503a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate DataInputStream in = new DataInputStream(baStream); 2513a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2523a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (key.equals(GLOBAL_METADATA_KEY)) { 25372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate int storedSdkVersion = in.readInt(); 2543a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, " storedSystemVersion = " + storedSystemVersion); 2553a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (storedSystemVersion > Build.VERSION.SDK_INT) { 2563a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // returning before setting the sig map means we rejected the restore set 2573a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.w(TAG, "Restore set was from a later version of Android; not restoring"); 2583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2593a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 26072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = storedSdkVersion; 26172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = in.readUTF(); 2623a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // !!! TODO: remove this debugging output 2633a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 2643a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.i(TAG, "Restore set version " + storedSystemVersion 26572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + " is compatible with OS version " + Build.VERSION.SDK_INT 26672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + " (" + mStoredIncrementalVersion + " vs " 26772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate + Build.VERSION.INCREMENTAL + ")"); 2683a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2693a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } else { 2703a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // it's a file metadata record 2713a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate int versionCode = in.readInt(); 2723a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Signature[] sigs = unflattenSignatureArray(in); 2733a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate// !!! TODO: take out this debugging 2743a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 2753a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.i(TAG, " restored metadata for " + key 2763a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " dataSize=" + dataSize 2773a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " versionCode=" + versionCode + " sigs=" + sigs); 2783a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2793a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2803a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate ApplicationInfo app = new ApplicationInfo(); 2813a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate app.packageName = key; 2823a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate restoredApps.add(app); 2833a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate sigMap.put(key, new Metadata(versionCode, sigs)); 2843a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2856785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2873a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // On successful completion, cache the signature map for the Backup Manager to use 2886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mRestoredSignatures = sigMap; 2896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2906785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2916785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Util: convert an array of Signatures into a flattened byte buffer. The 2936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // flattened format contains enough info to reconstruct the signature array. 2946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private byte[] flattenSignatureArray(Signature[] allSigs) { 2956785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate ByteArrayOutputStream outBuf = new ByteArrayOutputStream(); 2966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataOutputStream out = new DataOutputStream(outBuf); 2976785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2986785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // build the set of subsidiary buffers 2996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 3006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // first the # of signatures in the array 3016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.writeInt(allSigs.length); 3026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // then the signatures themselves, length + flattened buffer 3046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate for (Signature sig : allSigs) { 3056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] flat = sig.toByteArray(); 3066785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.writeInt(flat.length); 3076785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.write(flat); 3086785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3096785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 3106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // very strange; we're writing to memory here. abort. 3116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 3126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return outBuf.toByteArray(); 3156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3166785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3176aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) { 3186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate Signature[] sigs = null; 3196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 3216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int num = in.readInt(); 3223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.v(TAG, " ... unflatten read " + num); 3236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate sigs = new Signature[num]; 3246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate for (int i = 0; i < num; i++) { 3256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int len = in.readInt(); 3266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] flatSig = new byte[len]; 3276785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate in.read(flatSig); 3286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate sigs[i] = new Signature(flatSig); 3296785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (EOFException e) { 3316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // clean termination 3326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate if (sigs == null) { 3336785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate Log.w(TAG, "Empty signature block found"); 3346785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3356785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 3366785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate Log.d(TAG, "Unable to unflatten sigs"); 3376785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 3386785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3396785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3406785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return sigs; 3416785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3426785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Util: parse out an existing state file into a usable structure 34472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate private void parseStateFile(ParcelFileDescriptor stateFile) { 34572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.clear(); 34672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStateVersions.clear(); 34772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = 0; 34872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = null; 34972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 3506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // The state file is just the list of app names we have stored signatures for 35172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // with the exception of the metadata block, to which is also appended the 35272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // version numbers corresponding with the last time we wrote this PM block. 35372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // If they mismatch the current system, we'll re-store the metadata key. 3546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor()); 3556785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataInputStream in = new DataInputStream(instream); 3566785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3576785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int bufSize = 256; 3586785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] buf = new byte[bufSize]; 3596785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 36072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate String pkg = in.readUTF(); 36172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate if (pkg.equals(GLOBAL_METADATA_KEY)) { 36272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredSdkVersion = in.readInt(); 36372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStoredIncrementalVersion = in.readUTF(); 36472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(GLOBAL_METADATA_KEY); 36572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } else { 36672d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate Log.e(TAG, "No global metadata in state file!"); 36772d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate return; 36872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate } 36972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate 37072d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate // The global metadata was first; now read all the apps 37172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate while (true) { 37272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate pkg = in.readUTF(); 37372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate int versionCode = in.readInt(); 37472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mExisting.add(pkg); 37572d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate mStateVersions.put(pkg, new Metadata(versionCode, null)); 3766785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3776785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (EOFException eof) { 3786785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // safe; we're done 3796785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 3806785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // whoops, bad state file. abort. 38172d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate Log.e(TAG, "Unable to read Package Manager state file: " + e); 3826785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3836785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3846785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3853a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Util: write out our new backup state file 386efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) { 3876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); 3886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataOutputStream out = new DataOutputStream(outstream); 3896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3903a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 3913a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // by the time we get here we know we've stored the global metadata record 39272d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(GLOBAL_METADATA_KEY); 39372d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeInt(Build.VERSION.SDK_INT); 39472d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(Build.VERSION.INCREMENTAL); 3953a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 3963a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // now write all the app names too 397efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (PackageInfo pkg : pkgs) { 39872d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeUTF(pkg.packageName); 39972d19aa51e90d45c7895629db78e548da2f6d469Christopher Tate out.writeInt(pkg.versionCode); 4006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4013a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 4023a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.e(TAG, "Unable to write package manager state file!"); 4033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 4046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 4066785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate} 407