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; 2174318c98a0f67e042815798f85c75eb7f14390e1Christopher Tateimport android.app.backup.BackupTransport; 226a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tateimport android.app.backup.RestoreDescription; 234528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.RestoreSet; 24cefba58d14f9669b57c16b4ea493779d882c43bdChristopher Tateimport android.content.ComponentName; 259bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.content.Context; 26a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tateimport android.content.Intent; 279bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.content.pm.PackageInfo; 289bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.os.Environment; 299bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.os.ParcelFileDescriptor; 30f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughesimport android.system.ErrnoException; 31f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughesimport android.system.Os; 32f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughesimport android.system.StructStat; 339bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.util.Log; 349bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 354140faeebbfa23d56068c1862b2913fb62145f4fBrian Carlstromimport com.android.org.bouncycastle.util.encoders.Base64; 36e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate 37824392bdbdd0d593c4bd2d26f197bb0009ff75c9Christopher Tateimport libcore.io.IoUtils; 38824392bdbdd0d593c4bd2d26f197bb0009ff75c9Christopher Tate 399ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tateimport java.io.BufferedOutputStream; 409bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.File; 419bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileInputStream; 429ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tateimport java.io.FileNotFoundException; 439bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileOutputStream; 449bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.IOException; 45adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tateimport java.util.ArrayList; 46adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tateimport java.util.Collections; 479310e4285b3fc951c3524d040726d1161015562cChristopher Tateimport static android.system.OsConstants.SEEK_CUR; 48b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate 499bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate/** 509bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate * Backup transport for stashing stuff into a known location on disk, and 519bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate * later restoring from there. For testing only. 529bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate */ 539bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 5474318c98a0f67e042815798f85c75eb7f14390e1Christopher Tatepublic class LocalTransport extends BackupTransport { 559bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private static final String TAG = "LocalTransport"; 56a50cd8d4264ca98e19b858596de3a223ba6bf42eEd Heyl private static final boolean DEBUG = false; 579bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 585cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate private static final String TRANSPORT_DIR_NAME 595cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate = "com.android.internal.backup.LocalTransport"; 605cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 61a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate private static final String TRANSPORT_DESTINATION_STRING 62a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate = "Backing up to debug-only private cache"; 63a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate 649679410db578e179c7559e7a52bb21c8082e9631Christopher Tate private static final String TRANSPORT_DATA_MANAGEMENT_LABEL 659679410db578e179c7559e7a52bb21c8082e9631Christopher Tate = ""; 669679410db578e179c7559e7a52bb21c8082e9631Christopher Tate 676a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private static final String INCREMENTAL_DIR = "_delta"; 686a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private static final String FULL_DATA_DIR = "_full"; 696a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 70adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // The currently-active restore set always has the same (nonzero!) token 71adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate private static final long CURRENT_SET_TOKEN = 1; 7250c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate 73872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov // Full backup size quota is set to reasonable value. 74872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov private static final long FULL_BACKUP_SIZE_QUOTA = 25 * 1024 * 1024; 75872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov 769bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private Context mContext; 779bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup"); 78adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate private File mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN)); 796a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR); 806a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR); 81adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 82efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private PackageInfo[] mRestorePackages = null; 83efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private int mRestorePackage = -1; // Index into mRestorePackages 846a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private int mRestoreType; 856a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mRestoreSetDir; 866a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mRestoreSetIncrementalDir; 876a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mRestoreSetFullDir; 889bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 899ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // Additional bookkeeping for full backup 909ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private String mFullTargetPackage; 919ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private ParcelFileDescriptor mSocket; 929ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private FileInputStream mSocketInputStream; 939ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private BufferedOutputStream mFullBackupOutputStream; 949ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private byte[] mFullBackupBuffer; 95872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov private long mFullBackupSize; 969ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 975a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate private FileInputStream mCurFullRestoreStream; 985a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate private FileOutputStream mFullRestoreSocketStream; 995a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate private byte[] mFullRestoreBuffer; 1009bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 101de2826b1e95573cf1cf065f46d661ab27bade00cChristopher Tate private void makeDataDirs() { 102adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate mCurrentSetDir.mkdirs(); 103de2826b1e95573cf1cf065f46d661ab27bade00cChristopher Tate mCurrentSetFullDir.mkdir(); 104de2826b1e95573cf1cf065f46d661ab27bade00cChristopher Tate mCurrentSetIncrementalDir.mkdir(); 105de2826b1e95573cf1cf065f46d661ab27bade00cChristopher Tate } 106de2826b1e95573cf1cf065f46d661ab27bade00cChristopher Tate 107de2826b1e95573cf1cf065f46d661ab27bade00cChristopher Tate public LocalTransport(Context context) { 108de2826b1e95573cf1cf065f46d661ab27bade00cChristopher Tate mContext = context; 109de2826b1e95573cf1cf065f46d661ab27bade00cChristopher Tate makeDataDirs(); 1109bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 1119bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1125a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 113cefba58d14f9669b57c16b4ea493779d882c43bdChristopher Tate public String name() { 114cefba58d14f9669b57c16b4ea493779d882c43bdChristopher Tate return new ComponentName(mContext, this.getClass()).flattenToShortString(); 115cefba58d14f9669b57c16b4ea493779d882c43bdChristopher Tate } 116cefba58d14f9669b57c16b4ea493779d882c43bdChristopher Tate 1175a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 118a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate public Intent configurationIntent() { 119a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate // The local transport is not user-configurable 120a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate return null; 121a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate } 122a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate 1235a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 124a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate public String currentDestinationString() { 125a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate return TRANSPORT_DESTINATION_STRING; 1269679410db578e179c7559e7a52bb21c8082e9631Christopher Tate } 1279679410db578e179c7559e7a52bb21c8082e9631Christopher Tate 1289679410db578e179c7559e7a52bb21c8082e9631Christopher Tate public Intent dataManagementIntent() { 1299679410db578e179c7559e7a52bb21c8082e9631Christopher Tate // The local transport does not present a data-management UI 1309679410db578e179c7559e7a52bb21c8082e9631Christopher Tate // TODO: consider adding simple UI to wipe the archives entirely, 1319679410db578e179c7559e7a52bb21c8082e9631Christopher Tate // for cleaning up the cache partition. 1329679410db578e179c7559e7a52bb21c8082e9631Christopher Tate return null; 1339679410db578e179c7559e7a52bb21c8082e9631Christopher Tate } 1349679410db578e179c7559e7a52bb21c8082e9631Christopher Tate 1359679410db578e179c7559e7a52bb21c8082e9631Christopher Tate public String dataManagementLabel() { 1369679410db578e179c7559e7a52bb21c8082e9631Christopher Tate return TRANSPORT_DATA_MANAGEMENT_LABEL; 137a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate } 1385cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 1395a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 1400144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public String transportDirName() { 1415cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate return TRANSPORT_DIR_NAME; 1425cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate } 1435cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 1445a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 1450144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public long requestBackupTime() { 1469bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // any time is a good time for local backup 1479bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate return 0; 1489bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 1499bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1505a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 1510144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int initializeDevice() { 1520144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor if (DEBUG) Log.v(TAG, "wiping all data"); 153adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate deleteContents(mCurrentSetDir); 154de2826b1e95573cf1cf065f46d661ab27bade00cChristopher Tate makeDataDirs(); 1555a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 1560144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor } 1570144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor 1585a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 1590144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) { 160b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate if (DEBUG) { 161b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate try { 162f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughes StructStat ss = Os.fstat(data.getFileDescriptor()); 163b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName 164b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate + " size=" + ss.st_size); 165b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } catch (ErrnoException e) { 166b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate Log.w(TAG, "Unable to stat input file in performBackup() on " 167b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate + packageInfo.packageName); 168b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 169b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 1709bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1719ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName); 1722fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate packageDir.mkdirs(); 1739bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1742fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // Each 'record' in the restore set is kept in its own file, named by 1752fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // the record key. Wind through the data file, extracting individual 1762fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // record operations and building a set of all the updates to apply 1772fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // in this update. 1782fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate BackupDataInput changeSet = new BackupDataInput(data.getFileDescriptor()); 1792fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate try { 1802fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate int bufSize = 512; 1812fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate byte[] buf = new byte[bufSize]; 1822fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate while (changeSet.readNextHeader()) { 1832fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate String key = changeSet.getKey(); 1845d605dc56b036232e885f6ec36b888b729673060Joe Onorato String base64Key = new String(Base64.encode(key.getBytes())); 1855d605dc56b036232e885f6ec36b888b729673060Joe Onorato File entityFile = new File(packageDir, base64Key); 1865d605dc56b036232e885f6ec36b888b729673060Joe Onorato 1872fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate int dataSize = changeSet.getDataSize(); 188e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate 189e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize 190e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate + " key64=" + base64Key); 1912fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate 1925d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (dataSize >= 0) { 1931afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn if (entityFile.exists()) { 1941afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn entityFile.delete(); 1951afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn } 1965d605dc56b036232e885f6ec36b888b729673060Joe Onorato FileOutputStream entity = new FileOutputStream(entityFile); 1975d605dc56b036232e885f6ec36b888b729673060Joe Onorato 1985d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (dataSize > bufSize) { 1995d605dc56b036232e885f6ec36b888b729673060Joe Onorato bufSize = dataSize; 2005d605dc56b036232e885f6ec36b888b729673060Joe Onorato buf = new byte[bufSize]; 2015d605dc56b036232e885f6ec36b888b729673060Joe Onorato } 2025d605dc56b036232e885f6ec36b888b729673060Joe Onorato changeSet.readEntityData(buf, 0, dataSize); 203b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate if (DEBUG) { 204b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate try { 205f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughes long cur = Os.lseek(data.getFileDescriptor(), 0, SEEK_CUR); 206b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate Log.v(TAG, " read entity data; new pos=" + cur); 207b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 208b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate catch (ErrnoException e) { 209b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate Log.w(TAG, "Unable to stat input file in performBackup() on " 210b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate + packageInfo.packageName); 211b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 212b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 2135d605dc56b036232e885f6ec36b888b729673060Joe Onorato 2145d605dc56b036232e885f6ec36b888b729673060Joe Onorato try { 2155d605dc56b036232e885f6ec36b888b729673060Joe Onorato entity.write(buf, 0, dataSize); 2165d605dc56b036232e885f6ec36b888b729673060Joe Onorato } catch (IOException e) { 217efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath()); 2185a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 2195d605dc56b036232e885f6ec36b888b729673060Joe Onorato } finally { 2205d605dc56b036232e885f6ec36b888b729673060Joe Onorato entity.close(); 2215d605dc56b036232e885f6ec36b888b729673060Joe Onorato } 2225d605dc56b036232e885f6ec36b888b729673060Joe Onorato } else { 2235d605dc56b036232e885f6ec36b888b729673060Joe Onorato entityFile.delete(); 2242fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2252fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2265a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 2272fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } catch (IOException e) { 2282fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // oops, something went wrong. abort the operation and return error. 229efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.v(TAG, "Exception reading backup input:", e); 2305a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 2312fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 232efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 233ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate 23425a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // Deletes the contents but not the given directory 23525a747f5c47f25c1a18961b03507f309b84924feChristopher Tate private void deleteContents(File dirname) { 23625a747f5c47f25c1a18961b03507f309b84924feChristopher Tate File[] contents = dirname.listFiles(); 23725a747f5c47f25c1a18961b03507f309b84924feChristopher Tate if (contents != null) { 23825a747f5c47f25c1a18961b03507f309b84924feChristopher Tate for (File f : contents) { 23925a747f5c47f25c1a18961b03507f309b84924feChristopher Tate if (f.isDirectory()) { 24025a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // delete the directory's contents then fall through 24125a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // and delete the directory itself. 24225a747f5c47f25c1a18961b03507f309b84924feChristopher Tate deleteContents(f); 24325a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 24425a747f5c47f25c1a18961b03507f309b84924feChristopher Tate f.delete(); 24525a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 24625a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 24725a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 24825a747f5c47f25c1a18961b03507f309b84924feChristopher Tate 2495a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 2500144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int clearBackupData(PackageInfo packageInfo) { 251ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName); 252ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate 2539ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName); 2540abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate final File[] fileset = packageDir.listFiles(); 2550abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate if (fileset != null) { 2560abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate for (File f : fileset) { 2570abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate f.delete(); 2580abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate } 2590abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate packageDir.delete(); 260ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate } 2619ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 2629ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate packageDir = new File(mCurrentSetFullDir, packageInfo.packageName); 2639ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate final File[] tarballs = packageDir.listFiles(); 2649ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (tarballs != null) { 2659ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate for (File f : tarballs) { 2669ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate f.delete(); 2679ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 2689ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate packageDir.delete(); 2699ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 2709ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 2715a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 272ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate } 2739bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 2745a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 2750144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int finishBackup() { 276e079264b981d87c648921185528b553a86ae353dChristopher Tate if (DEBUG) Log.v(TAG, "finishBackup() of " + mFullTargetPackage); 277e079264b981d87c648921185528b553a86ae353dChristopher Tate return tearDownFullBackup(); 278e079264b981d87c648921185528b553a86ae353dChristopher Tate } 279e079264b981d87c648921185528b553a86ae353dChristopher Tate 280e079264b981d87c648921185528b553a86ae353dChristopher Tate // ------------------------------------------------------------------------------------ 281e079264b981d87c648921185528b553a86ae353dChristopher Tate // Full backup handling 282e079264b981d87c648921185528b553a86ae353dChristopher Tate 283e079264b981d87c648921185528b553a86ae353dChristopher Tate private int tearDownFullBackup() { 2849ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (mSocket != null) { 2859ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate try { 2869310e4285b3fc951c3524d040726d1161015562cChristopher Tate if (mFullBackupOutputStream != null) { 2879310e4285b3fc951c3524d040726d1161015562cChristopher Tate mFullBackupOutputStream.flush(); 2889310e4285b3fc951c3524d040726d1161015562cChristopher Tate mFullBackupOutputStream.close(); 2899310e4285b3fc951c3524d040726d1161015562cChristopher Tate } 2909ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mSocketInputStream = null; 2919ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullTargetPackage = null; 2929ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mSocket.close(); 2939ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } catch (IOException e) { 29489101f7fe89134a609459e80f779c1a5114e562aChristopher Tate if (DEBUG) { 295e079264b981d87c648921185528b553a86ae353dChristopher Tate Log.w(TAG, "Exception caught in tearDownFullBackup()", e); 29689101f7fe89134a609459e80f779c1a5114e562aChristopher Tate } 2975a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 2989ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } finally { 2999ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mSocket = null; 3009310e4285b3fc951c3524d040726d1161015562cChristopher Tate mFullBackupOutputStream = null; 3019ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3029ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3035a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 3049bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 3059bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 306e079264b981d87c648921185528b553a86ae353dChristopher Tate private File tarballFile(String pkgName) { 307e079264b981d87c648921185528b553a86ae353dChristopher Tate return new File(mCurrentSetFullDir, pkgName); 308e079264b981d87c648921185528b553a86ae353dChristopher Tate } 3095a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 3105a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 3119ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate public long requestFullBackupTime() { 3129ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate return 0; 3139ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3149ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3155a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 3169310e4285b3fc951c3524d040726d1161015562cChristopher Tate public int checkFullBackupSize(long size) { 317872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov int result = TRANSPORT_OK; 3189310e4285b3fc951c3524d040726d1161015562cChristopher Tate // Decline zero-size "backups" 319872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov if (size <= 0) { 320872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov result = TRANSPORT_PACKAGE_REJECTED; 321872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov } else if (size > FULL_BACKUP_SIZE_QUOTA) { 322872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov result = TRANSPORT_QUOTA_EXCEEDED; 323872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov } 3249310e4285b3fc951c3524d040726d1161015562cChristopher Tate if (result != TRANSPORT_OK) { 3259310e4285b3fc951c3524d040726d1161015562cChristopher Tate if (DEBUG) { 3269310e4285b3fc951c3524d040726d1161015562cChristopher Tate Log.v(TAG, "Declining backup of size " + size); 3279310e4285b3fc951c3524d040726d1161015562cChristopher Tate } 3289310e4285b3fc951c3524d040726d1161015562cChristopher Tate } 3299310e4285b3fc951c3524d040726d1161015562cChristopher Tate return result; 3309310e4285b3fc951c3524d040726d1161015562cChristopher Tate } 3319310e4285b3fc951c3524d040726d1161015562cChristopher Tate 3329310e4285b3fc951c3524d040726d1161015562cChristopher Tate @Override 3339ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) { 3349ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (mSocket != null) { 3359ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.e(TAG, "Attempt to initiate full backup while one is in progress"); 3365a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3379ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3389ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3399ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (DEBUG) { 3409ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.i(TAG, "performFullBackup : " + targetPackage); 3419ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3429ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3439ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // We know a priori that we run in the system process, so we need to make 3449ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // sure to dup() our own copy of the socket fd. Transports which run in 3459ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // their own processes must not do this. 3469ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate try { 347872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov mFullBackupSize = 0; 3489ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor()); 3499ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mSocketInputStream = new FileInputStream(mSocket.getFileDescriptor()); 3509ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } catch (IOException e) { 3519ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.e(TAG, "Unable to process socket for full backup"); 3525a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3539ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3549ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3559ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullTargetPackage = targetPackage.packageName; 3569ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullBackupBuffer = new byte[4096]; 3579ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3585a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 3599ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3609ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3615a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 3629310e4285b3fc951c3524d040726d1161015562cChristopher Tate public int sendBackupData(final int numBytes) { 3639310e4285b3fc951c3524d040726d1161015562cChristopher Tate if (mSocket == null) { 3649ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.w(TAG, "Attempted sendBackupData before performFullBackup"); 3655a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3669ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3679ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 368872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov mFullBackupSize += numBytes; 369872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov if (mFullBackupSize > FULL_BACKUP_SIZE_QUOTA) { 370872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov return TRANSPORT_QUOTA_EXCEEDED; 371872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov } 372872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov 3739ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (numBytes > mFullBackupBuffer.length) { 3749ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullBackupBuffer = new byte[numBytes]; 3759ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3769310e4285b3fc951c3524d040726d1161015562cChristopher Tate 3779310e4285b3fc951c3524d040726d1161015562cChristopher Tate if (mFullBackupOutputStream == null) { 3789310e4285b3fc951c3524d040726d1161015562cChristopher Tate FileOutputStream tarstream; 3799310e4285b3fc951c3524d040726d1161015562cChristopher Tate try { 3809310e4285b3fc951c3524d040726d1161015562cChristopher Tate File tarball = tarballFile(mFullTargetPackage); 3819310e4285b3fc951c3524d040726d1161015562cChristopher Tate tarstream = new FileOutputStream(tarball); 3829310e4285b3fc951c3524d040726d1161015562cChristopher Tate } catch (FileNotFoundException e) { 3839310e4285b3fc951c3524d040726d1161015562cChristopher Tate return TRANSPORT_ERROR; 3849310e4285b3fc951c3524d040726d1161015562cChristopher Tate } 3859310e4285b3fc951c3524d040726d1161015562cChristopher Tate mFullBackupOutputStream = new BufferedOutputStream(tarstream); 3869310e4285b3fc951c3524d040726d1161015562cChristopher Tate } 3879310e4285b3fc951c3524d040726d1161015562cChristopher Tate 3889310e4285b3fc951c3524d040726d1161015562cChristopher Tate int bytesLeft = numBytes; 3899310e4285b3fc951c3524d040726d1161015562cChristopher Tate while (bytesLeft > 0) { 3909ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate try { 3919310e4285b3fc951c3524d040726d1161015562cChristopher Tate int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, bytesLeft); 3929ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (nRead < 0) { 3939ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // Something went wrong if we expect data but saw EOD 3949ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.w(TAG, "Unexpected EOD; failing backup"); 3955a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3969ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3979ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead); 3989310e4285b3fc951c3524d040726d1161015562cChristopher Tate bytesLeft -= nRead; 3999ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } catch (IOException e) { 4009ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.e(TAG, "Error handling backup data for " + mFullTargetPackage); 4015a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 4029ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 4039ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 40477a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate if (DEBUG) { 40577a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate Log.v(TAG, " stored " + numBytes + " of data"); 40677a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate } 4075a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 4089ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 4099ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 410e079264b981d87c648921185528b553a86ae353dChristopher Tate // For now we can't roll back, so just tear everything down. 411e079264b981d87c648921185528b553a86ae353dChristopher Tate @Override 412e079264b981d87c648921185528b553a86ae353dChristopher Tate public void cancelFullBackup() { 413e079264b981d87c648921185528b553a86ae353dChristopher Tate if (DEBUG) { 414e079264b981d87c648921185528b553a86ae353dChristopher Tate Log.i(TAG, "Canceling full backup of " + mFullTargetPackage); 415e079264b981d87c648921185528b553a86ae353dChristopher Tate } 416e079264b981d87c648921185528b553a86ae353dChristopher Tate File archive = tarballFile(mFullTargetPackage); 417e079264b981d87c648921185528b553a86ae353dChristopher Tate tearDownFullBackup(); 418e079264b981d87c648921185528b553a86ae353dChristopher Tate if (archive.exists()) { 419e079264b981d87c648921185528b553a86ae353dChristopher Tate archive.delete(); 420e079264b981d87c648921185528b553a86ae353dChristopher Tate } 421e079264b981d87c648921185528b553a86ae353dChristopher Tate } 422e079264b981d87c648921185528b553a86ae353dChristopher Tate 4239ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // ------------------------------------------------------------------------------------ 4249bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // Restore handling 42551fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate static final long[] POSSIBLE_SETS = { 2, 3, 4, 5, 6, 7, 8, 9 }; 4265a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 4275a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 42874318c98a0f67e042815798f85c75eb7f14390e1Christopher Tate public RestoreSet[] getAvailableRestoreSets() { 429adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate long[] existing = new long[POSSIBLE_SETS.length + 1]; 430adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate int num = 0; 431adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 4329ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // see which possible non-current sets exist... 433adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate for (long token : POSSIBLE_SETS) { 434adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate if ((new File(mDataDir, Long.toString(token))).exists()) { 435adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate existing[num++] = token; 436adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 437adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 4389ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // ...and always the currently-active set last 439adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate existing[num++] = CURRENT_SET_TOKEN; 440adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 441adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate RestoreSet[] available = new RestoreSet[num]; 442adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate for (int i = 0; i < available.length; i++) { 443adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate available[i] = new RestoreSet("Local disk image", "flash", existing[i]); 444adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 445adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return available; 4469bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 4479bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 4485a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 44950c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate public long getCurrentRestoreSet() { 450adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // The current restore set always has the same token 451adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return CURRENT_SET_TOKEN; 45250c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate } 45350c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate 4545a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 4550144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int startRestore(long token, PackageInfo[] packages) { 45651fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate if (DEBUG) Log.v(TAG, "start restore " + token + " : " + packages.length 45751fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate + " matching packages"); 458efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mRestorePackages = packages; 459efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mRestorePackage = -1; 4606a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreSetDir = new File(mDataDir, Long.toString(token)); 4616a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreSetIncrementalDir = new File(mRestoreSetDir, INCREMENTAL_DIR); 4626a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreSetFullDir = new File(mRestoreSetDir, FULL_DATA_DIR); 4635a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 464efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 4659bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 4666a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate @Override 4676a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate public RestoreDescription nextRestorePackage() { 46877a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate if (DEBUG) { 46977a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate Log.v(TAG, "nextRestorePackage() : mRestorePackage=" + mRestorePackage 47077a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate + " length=" + mRestorePackages.length); 47177a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate } 472efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); 4736a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 4746a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate boolean found = false; 475efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor while (++mRestorePackage < mRestorePackages.length) { 476efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String name = mRestorePackages[mRestorePackage].packageName; 4776a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 4786a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate // If we have key/value data for this package, deliver that 479a9b91864a1aedd71eaaaa43ee078cf93922289f3Christopher Tate // skip packages where we have a data dir but no actual contents 4806a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate String[] contents = (new File(mRestoreSetIncrementalDir, name)).list(); 481a9b91864a1aedd71eaaaa43ee078cf93922289f3Christopher Tate if (contents != null && contents.length > 0) { 48277a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate if (DEBUG) { 48377a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) @ " 48477a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate + mRestorePackage + " = " + name); 48577a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate } 4866a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreType = RestoreDescription.TYPE_KEY_VALUE; 4876a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate found = true; 4886a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate } 4896a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 4906a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (!found) { 4916a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate // No key/value data; check for [non-empty] full data 4926a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate File maybeFullData = new File(mRestoreSetFullDir, name); 4936a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (maybeFullData.length() > 0) { 49477a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate if (DEBUG) { 49577a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate Log.v(TAG, " nextRestorePackage(TYPE_FULL_STREAM) @ " 49677a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate + mRestorePackage + " = " + name); 49777a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate } 4986a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreType = RestoreDescription.TYPE_FULL_STREAM; 4995a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mCurFullRestoreStream = null; // ensure starting from the ground state 5006a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate found = true; 5016a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate } 5026a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate } 5036a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 5046a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (found) { 5056a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate return new RestoreDescription(name, mRestoreType); 5062fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 50777a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate 50877a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate if (DEBUG) { 50977a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate Log.v(TAG, " ... package @ " + mRestorePackage + " = " + name 51077a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate + " has no data; skipping"); 51177a2d78dbf91d4799f811385b1e39ad89052e7ebChristopher Tate } 5129bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 5139bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 514efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " no more packages to restore"); 5156a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate return RestoreDescription.NO_MORE_PACKAGES; 5169bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 5179bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 5185a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 5190144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int getRestoreData(ParcelFileDescriptor outFd) { 520efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); 521efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called"); 5226a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (mRestoreType != RestoreDescription.TYPE_KEY_VALUE) { 5236a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate throw new IllegalStateException("getRestoreData(fd) for non-key/value dataset"); 5246a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate } 52551fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate File packageDir = new File(mRestoreSetIncrementalDir, 52651fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate mRestorePackages[mRestorePackage].packageName); 5279bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 5282fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // The restore set is the concatenation of the individual record blobs, 529adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // each of which is a file in the package's directory. We return the 530adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // data in lexical order sorted by key, so that apps which use synthetic 531adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // keys like BLOB_1, BLOB_2, etc will see the date in the most obvious 532adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // order. 533adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate ArrayList<DecodedFilename> blobs = contentsByKey(packageDir); 5340144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor if (blobs == null) { // nextRestorePackage() ensures the dir exists, so this is an error 535adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate Log.e(TAG, "No keys for package: " + packageDir); 5365a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 537efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 538efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor 539efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor // We expect at least some data if the directory exists in the first place 540adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate if (DEBUG) Log.v(TAG, " getRestoreData() found " + blobs.size() + " key files"); 541efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor()); 542efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor try { 543adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate for (DecodedFilename keyEntry : blobs) { 544adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate File f = keyEntry.file; 545efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor FileInputStream in = new FileInputStream(f); 546efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor try { 547efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor int size = (int) f.length(); 548efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor byte[] buf = new byte[size]; 549efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor in.read(buf); 550adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate if (DEBUG) Log.v(TAG, " ... key=" + keyEntry.key + " size=" + size); 551adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate out.writeEntityHeader(keyEntry.key, size); 552efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor out.writeEntityData(buf, size); 553efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } finally { 554efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor in.close(); 5558e55eac96d768a4de68a091f57487deadf6d0a87Christopher Tate } 5562fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 5575a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 558efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } catch (IOException e) { 559efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Unable to read backup records", e); 5605a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 5612fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 5629bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 5633a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 564adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate static class DecodedFilename implements Comparable<DecodedFilename> { 565adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate public File file; 566adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate public String key; 567adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 568adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate public DecodedFilename(File f) { 569adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate file = f; 570adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate key = new String(Base64.decode(f.getName())); 571adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 572adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 573adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate @Override 574adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate public int compareTo(DecodedFilename other) { 575adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // sorts into ascending lexical order by decoded key 576adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return key.compareTo(other.key); 577adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 578adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 579adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 580adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // Return a list of the files in the given directory, sorted lexically by 581adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // the Base64-decoded file name, not by the on-disk filename 582adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate private ArrayList<DecodedFilename> contentsByKey(File dir) { 583adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate File[] allFiles = dir.listFiles(); 584adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate if (allFiles == null || allFiles.length == 0) { 585adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return null; 586adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 587adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 588adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // Decode the filenames into keys then sort lexically by key 589adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate ArrayList<DecodedFilename> contents = new ArrayList<DecodedFilename>(); 590adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate for (File f : allFiles) { 591adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate contents.add(new DecodedFilename(f)); 592adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 593adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate Collections.sort(contents); 594adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return contents; 595adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 596adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 5975a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 598efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor public void finishRestore() { 599efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, "finishRestore()"); 6005a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (mRestoreType == RestoreDescription.TYPE_FULL_STREAM) { 6015a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate resetFullRestoreState(); 6025a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6035a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mRestoreType = 0; 6043a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 6059ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 6069ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // ------------------------------------------------------------------------------------ 6079ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // Full restore handling 6089ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 6095a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate private void resetFullRestoreState() { 610824392bdbdd0d593c4bd2d26f197bb0009ff75c9Christopher Tate IoUtils.closeQuietly(mCurFullRestoreStream); 6115a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mCurFullRestoreStream = null; 6125a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mFullRestoreSocketStream = null; 6135a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mFullRestoreBuffer = null; 6149ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 6159ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 6169ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate /** 6179ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * Ask the transport to provide data for the "current" package being restored. The 6189ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * transport then writes some data to the socket supplied to this call, and returns 6199ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * the number of bytes written. The system will then read that many bytes and 6209ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * stream them to the application's agent for restore, then will call this method again 6219ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * to receive the next chunk of the archive. This sequence will be repeated until the 6229ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * transport returns zero indicating that all of the package's data has been delivered 6239ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * (or returns a negative value indicating some sort of hard error condition at the 6249ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * transport level). 6259ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * 6269ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * <p>After this method returns zero, the system will then call 6279ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * {@link #getNextFullRestorePackage()} to begin the restore process for the next 6289ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * application, and the sequence begins again. 6299ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * 6309ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * @param socket The file descriptor that the transport will use for delivering the 6319ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * streamed archive. 6329ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * @return 0 when no more data for the current package is available. A positive value 6339ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * indicates the presence of that much data to be delivered to the app. A negative 6349ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR}, 6359ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * indicating a fatal error condition that precludes further restore operations 6369ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * on the current dataset. 6379ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate */ 6385a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 6399ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) { 6405a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (mRestoreType != RestoreDescription.TYPE_FULL_STREAM) { 6415a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate throw new IllegalStateException("Asked for full restore data for non-stream package"); 6425a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6435a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 6445a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // first chunk? 6455a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (mCurFullRestoreStream == null) { 6465a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate final String name = mRestorePackages[mRestorePackage].packageName; 6475a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (DEBUG) Log.i(TAG, "Starting full restore of " + name); 6485a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate File dataset = new File(mRestoreSetFullDir, name); 6495a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate try { 6505a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mCurFullRestoreStream = new FileInputStream(dataset); 6515a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } catch (IOException e) { 6525a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // If we can't open the target package's tarball, we return the single-package 6535a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // error code and let the caller go on to the next package. 6545a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate Log.e(TAG, "Unable to read archive for " + name); 6555a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_PACKAGE_REJECTED; 6565a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6575a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mFullRestoreSocketStream = new FileOutputStream(socket.getFileDescriptor()); 65889101f7fe89134a609459e80f779c1a5114e562aChristopher Tate mFullRestoreBuffer = new byte[2*1024]; 6595a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6605a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 6615a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate int nRead; 6625a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate try { 6635a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate nRead = mCurFullRestoreStream.read(mFullRestoreBuffer); 6645a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (nRead < 0) { 6655a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // EOF: tell the caller we're done 6665a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate nRead = NO_MORE_DATA; 6675a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } else if (nRead == 0) { 6685a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // This shouldn't happen when reading a FileInputStream; we should always 6695a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // get either a positive nonzero byte count or -1. Log the situation and 6705a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // treat it as EOF. 6715a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate Log.w(TAG, "read() of archive file returned 0; treating as EOF"); 6725a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate nRead = NO_MORE_DATA; 6735a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } else { 6745a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (DEBUG) { 6755a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate Log.i(TAG, " delivering restore chunk: " + nRead); 6765a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6775a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mFullRestoreSocketStream.write(mFullRestoreBuffer, 0, nRead); 6785a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6795a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } catch (IOException e) { 6805a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; // Hard error accessing the file; shouldn't happen 6815a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } finally { 6825a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // Most transports will need to explicitly close 'socket' here, but this transport 6835a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // is in the same process as the caller so it can leave it up to the backup manager 6845a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // to manage both socket fds. 6855a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6865a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 6875a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return nRead; 6889ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 6895a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 6905a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate /** 6915a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM} 6925a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * data for restore, it will invoke this method to tell the transport that it should 6935a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * abandon the data download for the current package. The OS will then either call 6945a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * {@link #nextRestorePackage()} again to move on to restoring the next package in the 6955a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * set being iterated over, or will call {@link #finishRestore()} to shut down the restore 6965a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * operation. 6975a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * 6985a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the 6995a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious 7005a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * transport-level failure. If the transport reports an error here, the entire restore 7015a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * operation will immediately be finished with no further attempts to restore app data. 7025a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate */ 7035a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 7045a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate public int abortFullRestore() { 7055a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (mRestoreType != RestoreDescription.TYPE_FULL_STREAM) { 7065a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate throw new IllegalStateException("abortFullRestore() but not currently restoring"); 7075a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 7085a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate resetFullRestoreState(); 7095a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mRestoreType = 0; 7105a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 7115a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 7125a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 713872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov @Override 714872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov public long getBackupQuota(String packageName, boolean isFullBackup) { 715872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov return isFullBackup ? FULL_BACKUP_SIZE_QUOTA : Long.MAX_VALUE; 716872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov } 7179bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate} 718