115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root/* 215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Copyright (C) 2009 The Android Open Source Project 315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * 415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * you may not use this file except in compliance with the License. 615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * You may obtain a copy of the License at 715a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * 815a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * http://www.apache.org/licenses/LICENSE-2.0 915a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * 1015a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Unless required by applicable law or agreed to in writing, software 1115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * distributed under the License is distributed on an "AS IS" BASIS, 1215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * See the License for the specific language governing permissions and 1415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * limitations under the License. 1515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root */ 1615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root 179bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tatepackage com.android.internal.backup; 189bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 194528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.BackupDataInput; 204528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.BackupDataOutput; 214528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.RestoreSet; 229bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.content.Context; 23a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tateimport android.content.Intent; 249bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.content.pm.PackageInfo; 259bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.content.pm.PackageManager; 269bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.content.pm.PackageManager.NameNotFoundException; 279bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.os.Environment; 289bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.os.ParcelFileDescriptor; 299bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.os.RemoteException; 30ebab0ae105f1a6df593a4bc2549fae3ee8b2ade4rpcraigimport android.os.SELinux; 319bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.util.Log; 329bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 334140faeebbfa23d56068c1862b2913fb62145f4fBrian Carlstromimport com.android.org.bouncycastle.util.encoders.Base64; 34e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate 359bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.File; 369bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileFilter; 379bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileInputStream; 389bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileOutputStream; 399bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.IOException; 409bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.util.ArrayList; 419bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 429bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate/** 439bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate * Backup transport for stashing stuff into a known location on disk, and 449bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate * later restoring from there. For testing only. 459bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate */ 469bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 479bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tatepublic class LocalTransport extends IBackupTransport.Stub { 489bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private static final String TAG = "LocalTransport"; 492fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate private static final boolean DEBUG = true; 509bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 515cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate private static final String TRANSPORT_DIR_NAME 525cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate = "com.android.internal.backup.LocalTransport"; 535cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 54a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate private static final String TRANSPORT_DESTINATION_STRING 55a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate = "Backing up to debug-only private cache"; 56a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate 5750c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate // The single hardcoded restore set always has the same (nonzero!) token 5850c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate private static final long RESTORE_TOKEN = 1; 5950c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate 609bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private Context mContext; 619bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup"); 62efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private PackageInfo[] mRestorePackages = null; 63efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private int mRestorePackage = -1; // Index into mRestorePackages 649bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 659bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 669bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate public LocalTransport(Context context) { 679bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate mContext = context; 68ebab0ae105f1a6df593a4bc2549fae3ee8b2ade4rpcraig mDataDir.mkdirs(); 69ebab0ae105f1a6df593a4bc2549fae3ee8b2ade4rpcraig if (!SELinux.restorecon(mDataDir)) { 70ebab0ae105f1a6df593a4bc2549fae3ee8b2ade4rpcraig Log.e(TAG, "SELinux restorecon failed for " + mDataDir); 71ebab0ae105f1a6df593a4bc2549fae3ee8b2ade4rpcraig } 729bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 739bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 74a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate public Intent configurationIntent() { 75a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate // The local transport is not user-configurable 76a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate return null; 77a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate } 78a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate 79a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate public String currentDestinationString() { 80a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate return TRANSPORT_DESTINATION_STRING; 81a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate } 825cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 830144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public String transportDirName() { 845cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate return TRANSPORT_DIR_NAME; 855cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate } 865cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 870144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public long requestBackupTime() { 889bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // any time is a good time for local backup 899bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate return 0; 909bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 919bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 920144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int initializeDevice() { 930144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor if (DEBUG) Log.v(TAG, "wiping all data"); 940144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor deleteContents(mDataDir); 950144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 960144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor } 970144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor 980144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) { 992fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName); 1009bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1012fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate File packageDir = new File(mDataDir, packageInfo.packageName); 1022fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate packageDir.mkdirs(); 1039bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1042fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // Each 'record' in the restore set is kept in its own file, named by 1052fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // the record key. Wind through the data file, extracting individual 1062fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // record operations and building a set of all the updates to apply 1072fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // in this update. 1082fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate BackupDataInput changeSet = new BackupDataInput(data.getFileDescriptor()); 1092fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate try { 1102fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate int bufSize = 512; 1112fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate byte[] buf = new byte[bufSize]; 1122fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate while (changeSet.readNextHeader()) { 1132fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate String key = changeSet.getKey(); 1145d605dc56b036232e885f6ec36b888b729673060Joe Onorato String base64Key = new String(Base64.encode(key.getBytes())); 1155d605dc56b036232e885f6ec36b888b729673060Joe Onorato File entityFile = new File(packageDir, base64Key); 1165d605dc56b036232e885f6ec36b888b729673060Joe Onorato 1172fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate int dataSize = changeSet.getDataSize(); 118e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate 119e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize 120e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate + " key64=" + base64Key); 1212fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate 1225d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (dataSize >= 0) { 1231afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn if (entityFile.exists()) { 1241afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn entityFile.delete(); 1251afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn } 1265d605dc56b036232e885f6ec36b888b729673060Joe Onorato FileOutputStream entity = new FileOutputStream(entityFile); 1275d605dc56b036232e885f6ec36b888b729673060Joe Onorato 1285d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (dataSize > bufSize) { 1295d605dc56b036232e885f6ec36b888b729673060Joe Onorato bufSize = dataSize; 1305d605dc56b036232e885f6ec36b888b729673060Joe Onorato buf = new byte[bufSize]; 1315d605dc56b036232e885f6ec36b888b729673060Joe Onorato } 1325d605dc56b036232e885f6ec36b888b729673060Joe Onorato changeSet.readEntityData(buf, 0, dataSize); 1335d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (DEBUG) Log.v(TAG, " data size " + dataSize); 1345d605dc56b036232e885f6ec36b888b729673060Joe Onorato 1355d605dc56b036232e885f6ec36b888b729673060Joe Onorato try { 1365d605dc56b036232e885f6ec36b888b729673060Joe Onorato entity.write(buf, 0, dataSize); 1375d605dc56b036232e885f6ec36b888b729673060Joe Onorato } catch (IOException e) { 138efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath()); 139d55e18acbe444b74dc9e71eff6ea2c3eaf25fbd0Christopher Tate return BackupConstants.TRANSPORT_ERROR; 1405d605dc56b036232e885f6ec36b888b729673060Joe Onorato } finally { 1415d605dc56b036232e885f6ec36b888b729673060Joe Onorato entity.close(); 1425d605dc56b036232e885f6ec36b888b729673060Joe Onorato } 1435d605dc56b036232e885f6ec36b888b729673060Joe Onorato } else { 1445d605dc56b036232e885f6ec36b888b729673060Joe Onorato entityFile.delete(); 1452fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 1462fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 147d55e18acbe444b74dc9e71eff6ea2c3eaf25fbd0Christopher Tate return BackupConstants.TRANSPORT_OK; 1482fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } catch (IOException e) { 1492fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // oops, something went wrong. abort the operation and return error. 150efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.v(TAG, "Exception reading backup input:", e); 151d55e18acbe444b74dc9e71eff6ea2c3eaf25fbd0Christopher Tate return BackupConstants.TRANSPORT_ERROR; 1522fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 153efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 154ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate 15525a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // Deletes the contents but not the given directory 15625a747f5c47f25c1a18961b03507f309b84924feChristopher Tate private void deleteContents(File dirname) { 15725a747f5c47f25c1a18961b03507f309b84924feChristopher Tate File[] contents = dirname.listFiles(); 15825a747f5c47f25c1a18961b03507f309b84924feChristopher Tate if (contents != null) { 15925a747f5c47f25c1a18961b03507f309b84924feChristopher Tate for (File f : contents) { 16025a747f5c47f25c1a18961b03507f309b84924feChristopher Tate if (f.isDirectory()) { 16125a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // delete the directory's contents then fall through 16225a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // and delete the directory itself. 16325a747f5c47f25c1a18961b03507f309b84924feChristopher Tate deleteContents(f); 16425a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 16525a747f5c47f25c1a18961b03507f309b84924feChristopher Tate f.delete(); 16625a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 16725a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 16825a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 16925a747f5c47f25c1a18961b03507f309b84924feChristopher Tate 1700144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int clearBackupData(PackageInfo packageInfo) { 171ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName); 172ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate 173ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate File packageDir = new File(mDataDir, packageInfo.packageName); 1740abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate final File[] fileset = packageDir.listFiles(); 1750abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate if (fileset != null) { 1760abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate for (File f : fileset) { 1770abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate f.delete(); 1780abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate } 1790abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate packageDir.delete(); 180ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate } 1810144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 182ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate } 1839bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1840144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int finishBackup() { 185efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, "finishBackup()"); 1860144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 1879bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 1889bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1899bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // Restore handling 1909bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException { 1919bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // one hardcoded restore set 19250c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate RestoreSet set = new RestoreSet("Local disk image", "flash", RESTORE_TOKEN); 193f68eb500f99361541049e09eb7f9ddd6f4ef4efaChristopher Tate RestoreSet[] array = { set }; 194f68eb500f99361541049e09eb7f9ddd6f4ef4efaChristopher Tate return array; 1959bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 1969bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 19750c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate public long getCurrentRestoreSet() { 19850c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate // The hardcoded restore set always has the same token 19950c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate return RESTORE_TOKEN; 20050c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate } 20150c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate 2020144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int startRestore(long token, PackageInfo[] packages) { 203efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, "start restore " + token); 204efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mRestorePackages = packages; 205efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mRestorePackage = -1; 2060144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 207efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 2089bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 209efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor public String nextRestorePackage() { 210efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); 211efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor while (++mRestorePackage < mRestorePackages.length) { 212efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String name = mRestorePackages[mRestorePackage].packageName; 213efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (new File(mDataDir, name).isDirectory()) { 214efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " nextRestorePackage() = " + name); 215efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor return name; 2162fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2179bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 2189bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 219efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " no more packages to restore"); 220efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor return ""; 2219bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 2229bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 2230144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int getRestoreData(ParcelFileDescriptor outFd) { 224efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); 225efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called"); 226efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor File packageDir = new File(mDataDir, mRestorePackages[mRestorePackage].packageName); 2279bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 2282fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // The restore set is the concatenation of the individual record blobs, 2292fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // each of which is a file in the package's directory 2302fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate File[] blobs = packageDir.listFiles(); 2310144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor if (blobs == null) { // nextRestorePackage() ensures the dir exists, so this is an error 232efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Error listing directory: " + packageDir); 2330144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_ERROR; 234efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 235efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor 236efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor // We expect at least some data if the directory exists in the first place 237efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " getRestoreData() found " + blobs.length + " key files"); 238efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor()); 239efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor try { 240efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (File f : blobs) { 241efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor FileInputStream in = new FileInputStream(f); 242efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor try { 243efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor int size = (int) f.length(); 244efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor byte[] buf = new byte[size]; 245efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor in.read(buf); 246efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String key = new String(Base64.decode(f.getName())); 247efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " ... key=" + key + " size=" + size); 248efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor out.writeEntityHeader(key, size); 249efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor out.writeEntityData(buf, size); 250efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } finally { 251efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor in.close(); 2528e55eac96d768a4de68a091f57487deadf6d0a87Christopher Tate } 2532fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2540144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 255efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } catch (IOException e) { 256efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Unable to read backup records", e); 2570144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_ERROR; 2582fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2599bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 2603a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 261efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor public void finishRestore() { 262efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, "finishRestore()"); 2633a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2649bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate} 265