PackageManagerBackupAgent.java revision 5cbbf5652a78902ac3382dc4a3583bc5b0351027
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 606785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private List<ApplicationInfo> mAllApps; 616785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private PackageManager mPackageManager; 626aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate private HashMap<String, Metadata> mRestoredSignatures; 636aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate 646aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public class Metadata { 656aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public int versionCode; 666aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public Signature[] signatures; 676aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate 686aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate Metadata(int version, Signature[] sigs) { 696aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate versionCode = version; 706aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate signatures = sigs; 716aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate } 726aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate } 736785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 746785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // We're constructed with the set of applications that are participating 756785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // in backup. This set changes as apps are installed & removed. 766785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate PackageManagerBackupAgent(PackageManager packageMgr, List<ApplicationInfo> apps) { 776785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mPackageManager = packageMgr; 786785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mAllApps = apps; 796785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mRestoredSignatures = null; 806785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 826aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate public Metadata getRestoredMetadata(String packageName) { 836785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate if (mRestoredSignatures == null) { 843a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.w(TAG, "getRestoredMetadata() before metadata read!"); 856785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return mRestoredSignatures.get(packageName); 896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 906785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 916785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // The backed up data is the signature block for each app, keyed by 926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // the package name. 936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate ParcelFileDescriptor newState) { 956aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate if (DEBUG) Log.v(TAG, "onBackup()"); 963a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 976aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these 986aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate DataOutputStream outWriter = new DataOutputStream(bufStream); 993a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate HashSet<String> existing = parseStateFile(oldState); 1003a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1013a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 1023a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate /* 1033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * Global metadata: 1043a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * 1053a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * int version -- the SDK version of the OS itself on the device 1063a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * that produced this backup set. Used to reject 1073a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * backups from later OSes onto earlier ones. 1083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate */ 1093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (!existing.contains(GLOBAL_METADATA_KEY)) { 1103a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, "Storing global metadata key"); 1113a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate outWriter.writeInt(Build.VERSION.SDK_INT); 1123a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] metadata = bufStream.toByteArray(); 1133a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length); 1143a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityData(metadata, metadata.length); 1156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } else { 1163a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, "Global metadata key already stored"); 1173a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 1183a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // For each app we have on device, see if we've backed it up yet. If not, 1203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // write its signature block to the output, keyed on the package name. 1213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate for (ApplicationInfo app : mAllApps) { 1223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate String packName = app.packageName; 1233a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (!existing.contains(packName)) { 1243a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // We haven't stored this app's signatures yet, so we do that now 1253a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 1263a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate PackageInfo info = mPackageManager.getPackageInfo(packName, 1273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate PackageManager.GET_SIGNATURES); 1283a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate /* 1293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * Metadata for each package: 1303a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * 1313a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * int version -- [4] the package's versionCode 1323a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate * byte[] signatures -- [len] flattened Signature[] of the package 1333a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate */ 1343a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1353a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // marshall the version code in a canonical form 1363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate bufStream.reset(); 1373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate outWriter.writeInt(info.versionCode); 1383a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] versionBuf = bufStream.toByteArray(); 1393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] sigs = flattenSignatureArray(info.signatures); 1413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 1423a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // !!! TODO: take out this debugging 1433a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 1443a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.v(TAG, "+ metadata for " + packName 1453a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " version=" + info.versionCode 1463a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " versionLen=" + versionBuf.length 1473a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " sigsLen=" + sigs.length); 1483a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 1493a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Now we can write the backup entity for this package 1503a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(packName, versionBuf.length + sigs.length); 1513a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityData(versionBuf, versionBuf.length); 1523a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityData(sigs, sigs.length); 1533a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (NameNotFoundException e) { 1543a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Weird; we just found it, and now are told it doesn't exist. 1553a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Treat it as having been removed from the device. 1563a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate existing.add(packName); 1573a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 1583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } else { 1593a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // We've already backed up this app. Remove it from the set so 1603a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // we can tell at the end what has disappeared from the device. 1613a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // !!! TODO: take out the debugging message 1623a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, "= already backed up metadata for " + packName); 1633a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (!existing.remove(packName)) { 1643a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.d(TAG, "*** failed to remove " + packName + " from package set!"); 1653a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 1666785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 1676785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 1686785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 1693a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // At this point, the only entries in 'existing' are apps that were 1703a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // mentioned in the saved state file, but appear to no longer be present 1713a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // on the device. Write a deletion entity for them. 1723a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate for (String app : existing) { 1733a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // !!! TODO: take out this msg 1743a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app); 1753a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 1763a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.writeEntityHeader(app, -1); 1773a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 1783a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.e(TAG, "Unable to write package deletions!"); 1793a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 1803a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 1816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 1823a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 1833a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Real error writing data 1843a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.e(TAG, "Unable to write package backup data file!"); 1853a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 1866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 1876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 1886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Finally, write the new state blob -- just the list of all apps we handled 1896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate writeStateFile(mAllApps, newState); 1906785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 1916785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 1926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // "Restore" here is a misnomer. What we're really doing is reading back the 1936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // set of app signatures associated with each backed-up app in this restore 1946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // image. We'll use those later to determine what we can legitimately restore. 1955cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) 1966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate throws IOException { 1976785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>(); 1986aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>(); 1993a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, "onRestore()"); 2003a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate int storedSystemVersion = -1; 2016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate while (data.readNextHeader()) { 2033a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate String key = data.getKey(); 2046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int dataSize = data.getDataSize(); 2056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2063a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, " got key=" + key + " dataSize=" + dataSize); 2073a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2083a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // generic setup to parse any entity data 2093a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] dataBuf = new byte[dataSize]; 2103a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate data.readEntityData(dataBuf, 0, dataSize); 2113a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf); 2123a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate DataInputStream in = new DataInputStream(baStream); 2133a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2143a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (key.equals(GLOBAL_METADATA_KEY)) { 2153a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate storedSystemVersion = in.readInt(); 2163a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) Log.v(TAG, " storedSystemVersion = " + storedSystemVersion); 2173a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (storedSystemVersion > Build.VERSION.SDK_INT) { 2183a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // returning before setting the sig map means we rejected the restore set 2193a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.w(TAG, "Restore set was from a later version of Android; not restoring"); 2203a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 2213a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2223a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // !!! TODO: remove this debugging output 2233a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 2243a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.i(TAG, "Restore set version " + storedSystemVersion 2253a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " is compatible with OS version " + Build.VERSION.SDK_INT); 2263a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2273a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } else { 2283a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // it's a file metadata record 2293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate int versionCode = in.readInt(); 2303a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Signature[] sigs = unflattenSignatureArray(in); 2313a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate// !!! TODO: take out this debugging 2323a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate if (DEBUG) { 2333a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.i(TAG, " restored metadata for " + key 2343a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " dataSize=" + dataSize 2353a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate + " versionCode=" + versionCode + " sigs=" + sigs); 2363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 2383a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate ApplicationInfo app = new ApplicationInfo(); 2393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate app.packageName = key; 2403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate restoredApps.add(app); 2413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate sigMap.put(key, new Metadata(versionCode, sigs)); 2423a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2453a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // On successful completion, cache the signature map for the Backup Manager to use 2466785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate mRestoredSignatures = sigMap; 2476785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2486785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Util: convert an array of Signatures into a flattened byte buffer. The 2516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // flattened format contains enough info to reconstruct the signature array. 2526785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private byte[] flattenSignatureArray(Signature[] allSigs) { 2536785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate ByteArrayOutputStream outBuf = new ByteArrayOutputStream(); 2546785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataOutputStream out = new DataOutputStream(outBuf); 2556785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2566785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // build the set of subsidiary buffers 2576785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 2586785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // first the # of signatures in the array 2596785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.writeInt(allSigs.length); 2606785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2616785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // then the signatures themselves, length + flattened buffer 2626785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate for (Signature sig : allSigs) { 2636785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] flat = sig.toByteArray(); 2646785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.writeInt(flat.length); 2656785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.write(flat); 2666785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2676785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 2686785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // very strange; we're writing to memory here. abort. 2696785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 2706785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2716785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2726785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return outBuf.toByteArray(); 2736785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2746785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2756aa41f4c575479672661f7eb4c704ef59d26a629Christopher Tate private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) { 2766785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate Signature[] sigs = null; 2776785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2786785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 2796785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int num = in.readInt(); 2803a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.v(TAG, " ... unflatten read " + num); 2816785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate sigs = new Signature[num]; 2826785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate for (int i = 0; i < num; i++) { 2836785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int len = in.readInt(); 2846785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] flatSig = new byte[len]; 2856785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate in.read(flatSig); 2866785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate sigs[i] = new Signature(flatSig); 2876785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2886785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (EOFException e) { 2896785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // clean termination 2906785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate if (sigs == null) { 2916785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate Log.w(TAG, "Empty signature block found"); 2926785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2936785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 2946785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate Log.d(TAG, "Unable to unflatten sigs"); 2956785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 2966785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 2976785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 2986785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return sigs; 2996785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3006785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3016785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // Util: parse out an existing state file into a usable structure 3026785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private HashSet<String> parseStateFile(ParcelFileDescriptor stateFile) { 3036785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate HashSet<String> set = new HashSet<String>(); 3046785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // The state file is just the list of app names we have stored signatures for 3056785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor()); 3066785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataInputStream in = new DataInputStream(instream); 3076785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3086785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int bufSize = 256; 3096785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] buf = new byte[bufSize]; 3106785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate try { 3116785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate int nameSize = in.readInt(); 3126785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate if (bufSize < nameSize) { 3136785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate bufSize = nameSize + 32; 3146785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate buf = new byte[bufSize]; 3156785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3166785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate in.read(buf, 0, nameSize); 3176785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate String pkg = new String(buf, 0, nameSize); 3186785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate set.add(pkg); 3196785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (EOFException eof) { 3206785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // safe; we're done 3216785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } catch (IOException e) { 3226785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate // whoops, bad state file. abort. 3236785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate Log.e(TAG, "Unable to read Package Manager state file"); 3246785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return null; 3256785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3266785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate return set; 3276785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3286785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3293a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // Util: write out our new backup state file 3306785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate private void writeStateFile(List<ApplicationInfo> apps, ParcelFileDescriptor stateFile) { 3316785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); 3326785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate DataOutputStream out = new DataOutputStream(outstream); 3336785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate 3343a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate try { 3353a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // by the time we get here we know we've stored the global metadata record 3363a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate byte[] metaNameBuf = GLOBAL_METADATA_KEY.getBytes(); 3373a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate out.writeInt(metaNameBuf.length); 3383a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate out.write(metaNameBuf); 3393a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 3403a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate // now write all the app names too 3413a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate for (ApplicationInfo app : apps) { 3426785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate byte[] pkgNameBuf = app.packageName.getBytes(); 3436785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.writeInt(pkgNameBuf.length); 3446785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate out.write(pkgNameBuf); 3456785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3463a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } catch (IOException e) { 3473a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate Log.e(TAG, "Unable to write package manager state file!"); 3483a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate return; 3496785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3506785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate } 3516785dd842075889e5230d93ed9c0ab9c204ab432Christopher Tate} 352