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; 309bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.util.Log; 319bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 324140faeebbfa23d56068c1862b2913fb62145f4fBrian Carlstromimport com.android.org.bouncycastle.util.encoders.Base64; 33e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate 349bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.File; 359bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileFilter; 369bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileInputStream; 379bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileOutputStream; 389bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.IOException; 399bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.util.ArrayList; 409bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 419bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate/** 429bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate * Backup transport for stashing stuff into a known location on disk, and 439bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate * later restoring from there. For testing only. 449bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate */ 459bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 469bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tatepublic class LocalTransport extends IBackupTransport.Stub { 479bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private static final String TAG = "LocalTransport"; 482fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate private static final boolean DEBUG = true; 499bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 505cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate private static final String TRANSPORT_DIR_NAME 515cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate = "com.android.internal.backup.LocalTransport"; 525cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 53a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate private static final String TRANSPORT_DESTINATION_STRING 54a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate = "Backing up to debug-only private cache"; 55a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate 5650c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate // The single hardcoded restore set always has the same (nonzero!) token 5750c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate private static final long RESTORE_TOKEN = 1; 5850c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate 599bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private Context mContext; 609bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup"); 61efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private PackageInfo[] mRestorePackages = null; 62efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private int mRestorePackage = -1; // Index into mRestorePackages 639bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 649bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 659bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate public LocalTransport(Context context) { 669bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate mContext = context; 679bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 689bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 69a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate public Intent configurationIntent() { 70a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate // The local transport is not user-configurable 71a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate return null; 72a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate } 73a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate 74a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate public String currentDestinationString() { 75a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate return TRANSPORT_DESTINATION_STRING; 76a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate } 775cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 780144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public String transportDirName() { 795cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate return TRANSPORT_DIR_NAME; 805cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate } 815cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 820144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public long requestBackupTime() { 839bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // any time is a good time for local backup 849bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate return 0; 859bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 869bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 870144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int initializeDevice() { 880144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor if (DEBUG) Log.v(TAG, "wiping all data"); 890144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor deleteContents(mDataDir); 900144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 910144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor } 920144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor 930144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) { 942fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName); 959bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 962fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate File packageDir = new File(mDataDir, packageInfo.packageName); 972fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate packageDir.mkdirs(); 989bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 992fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // Each 'record' in the restore set is kept in its own file, named by 1002fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // the record key. Wind through the data file, extracting individual 1012fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // record operations and building a set of all the updates to apply 1022fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // in this update. 1032fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate BackupDataInput changeSet = new BackupDataInput(data.getFileDescriptor()); 1042fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate try { 1052fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate int bufSize = 512; 1062fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate byte[] buf = new byte[bufSize]; 1072fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate while (changeSet.readNextHeader()) { 1082fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate String key = changeSet.getKey(); 1095d605dc56b036232e885f6ec36b888b729673060Joe Onorato String base64Key = new String(Base64.encode(key.getBytes())); 1105d605dc56b036232e885f6ec36b888b729673060Joe Onorato File entityFile = new File(packageDir, base64Key); 1115d605dc56b036232e885f6ec36b888b729673060Joe Onorato 1122fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate int dataSize = changeSet.getDataSize(); 113e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate 114e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize 115e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate + " key64=" + base64Key); 1162fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate 1175d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (dataSize >= 0) { 1181afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn if (entityFile.exists()) { 1191afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn entityFile.delete(); 1201afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn } 1215d605dc56b036232e885f6ec36b888b729673060Joe Onorato FileOutputStream entity = new FileOutputStream(entityFile); 1225d605dc56b036232e885f6ec36b888b729673060Joe Onorato 1235d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (dataSize > bufSize) { 1245d605dc56b036232e885f6ec36b888b729673060Joe Onorato bufSize = dataSize; 1255d605dc56b036232e885f6ec36b888b729673060Joe Onorato buf = new byte[bufSize]; 1265d605dc56b036232e885f6ec36b888b729673060Joe Onorato } 1275d605dc56b036232e885f6ec36b888b729673060Joe Onorato changeSet.readEntityData(buf, 0, dataSize); 1285d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (DEBUG) Log.v(TAG, " data size " + dataSize); 1295d605dc56b036232e885f6ec36b888b729673060Joe Onorato 1305d605dc56b036232e885f6ec36b888b729673060Joe Onorato try { 1315d605dc56b036232e885f6ec36b888b729673060Joe Onorato entity.write(buf, 0, dataSize); 1325d605dc56b036232e885f6ec36b888b729673060Joe Onorato } catch (IOException e) { 133efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath()); 134d55e18acbe444b74dc9e71eff6ea2c3eaf25fbd0Christopher Tate return BackupConstants.TRANSPORT_ERROR; 1355d605dc56b036232e885f6ec36b888b729673060Joe Onorato } finally { 1365d605dc56b036232e885f6ec36b888b729673060Joe Onorato entity.close(); 1375d605dc56b036232e885f6ec36b888b729673060Joe Onorato } 1385d605dc56b036232e885f6ec36b888b729673060Joe Onorato } else { 1395d605dc56b036232e885f6ec36b888b729673060Joe Onorato entityFile.delete(); 1402fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 1412fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 142d55e18acbe444b74dc9e71eff6ea2c3eaf25fbd0Christopher Tate return BackupConstants.TRANSPORT_OK; 1432fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } catch (IOException e) { 1442fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // oops, something went wrong. abort the operation and return error. 145efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.v(TAG, "Exception reading backup input:", e); 146d55e18acbe444b74dc9e71eff6ea2c3eaf25fbd0Christopher Tate return BackupConstants.TRANSPORT_ERROR; 1472fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 148efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 149ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate 15025a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // Deletes the contents but not the given directory 15125a747f5c47f25c1a18961b03507f309b84924feChristopher Tate private void deleteContents(File dirname) { 15225a747f5c47f25c1a18961b03507f309b84924feChristopher Tate File[] contents = dirname.listFiles(); 15325a747f5c47f25c1a18961b03507f309b84924feChristopher Tate if (contents != null) { 15425a747f5c47f25c1a18961b03507f309b84924feChristopher Tate for (File f : contents) { 15525a747f5c47f25c1a18961b03507f309b84924feChristopher Tate if (f.isDirectory()) { 15625a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // delete the directory's contents then fall through 15725a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // and delete the directory itself. 15825a747f5c47f25c1a18961b03507f309b84924feChristopher Tate deleteContents(f); 15925a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 16025a747f5c47f25c1a18961b03507f309b84924feChristopher Tate f.delete(); 16125a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 16225a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 16325a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 16425a747f5c47f25c1a18961b03507f309b84924feChristopher Tate 1650144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int clearBackupData(PackageInfo packageInfo) { 166ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName); 167ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate 168ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate File packageDir = new File(mDataDir, packageInfo.packageName); 1690abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate final File[] fileset = packageDir.listFiles(); 1700abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate if (fileset != null) { 1710abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate for (File f : fileset) { 1720abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate f.delete(); 1730abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate } 1740abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate packageDir.delete(); 175ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate } 1760144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 177ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate } 1789bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1790144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int finishBackup() { 180efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, "finishBackup()"); 1810144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 1829bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 1839bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1849bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // Restore handling 1859bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException { 1869bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // one hardcoded restore set 18750c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate RestoreSet set = new RestoreSet("Local disk image", "flash", RESTORE_TOKEN); 188f68eb500f99361541049e09eb7f9ddd6f4ef4efaChristopher Tate RestoreSet[] array = { set }; 189f68eb500f99361541049e09eb7f9ddd6f4ef4efaChristopher Tate return array; 1909bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 1919bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 19250c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate public long getCurrentRestoreSet() { 19350c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate // The hardcoded restore set always has the same token 19450c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate return RESTORE_TOKEN; 19550c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate } 19650c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate 1970144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int startRestore(long token, PackageInfo[] packages) { 198efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, "start restore " + token); 199efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mRestorePackages = packages; 200efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mRestorePackage = -1; 2010144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 202efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 2039bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 204efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor public String nextRestorePackage() { 205efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); 206efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor while (++mRestorePackage < mRestorePackages.length) { 207efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String name = mRestorePackages[mRestorePackage].packageName; 208efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (new File(mDataDir, name).isDirectory()) { 209efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " nextRestorePackage() = " + name); 210efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor return name; 2112fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2129bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 2139bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 214efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " no more packages to restore"); 215efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor return ""; 2169bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 2179bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 2180144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int getRestoreData(ParcelFileDescriptor outFd) { 219efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); 220efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called"); 221efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor File packageDir = new File(mDataDir, mRestorePackages[mRestorePackage].packageName); 2229bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 2232fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // The restore set is the concatenation of the individual record blobs, 2242fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // each of which is a file in the package's directory 2252fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate File[] blobs = packageDir.listFiles(); 2260144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor if (blobs == null) { // nextRestorePackage() ensures the dir exists, so this is an error 227efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Error listing directory: " + packageDir); 2280144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_ERROR; 229efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 230efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor 231efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor // We expect at least some data if the directory exists in the first place 232efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " getRestoreData() found " + blobs.length + " key files"); 233efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor()); 234efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor try { 235efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor for (File f : blobs) { 236efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor FileInputStream in = new FileInputStream(f); 237efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor try { 238efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor int size = (int) f.length(); 239efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor byte[] buf = new byte[size]; 240efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor in.read(buf); 241efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String key = new String(Base64.decode(f.getName())); 242efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " ... key=" + key + " size=" + size); 243efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor out.writeEntityHeader(key, size); 244efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor out.writeEntityData(buf, size); 245efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } finally { 246efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor in.close(); 2478e55eac96d768a4de68a091f57487deadf6d0a87Christopher Tate } 2482fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2490144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_OK; 250efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } catch (IOException e) { 251efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Unable to read backup records", e); 2520144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor return BackupConstants.TRANSPORT_ERROR; 2532fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2549bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 2553a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 256efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor public void finishRestore() { 257efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, "finishRestore()"); 2583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 2599bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate} 260