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; 30ebab0ae105f1a6df593a4bc2549fae3ee8b2ade4rpcraigimport android.os.SELinux; 31f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughesimport android.system.ErrnoException; 32f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughesimport android.system.Os; 33f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughesimport android.system.StructStat; 349bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport android.util.Log; 359bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 364140faeebbfa23d56068c1862b2913fb62145f4fBrian Carlstromimport com.android.org.bouncycastle.util.encoders.Base64; 37e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate 38824392bdbdd0d593c4bd2d26f197bb0009ff75c9Christopher Tateimport libcore.io.IoUtils; 39824392bdbdd0d593c4bd2d26f197bb0009ff75c9Christopher Tate 409ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tateimport java.io.BufferedOutputStream; 419bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.File; 429bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileInputStream; 439ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tateimport java.io.FileNotFoundException; 449bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.FileOutputStream; 459bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tateimport java.io.IOException; 46adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tateimport java.util.ArrayList; 479ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tateimport java.util.Arrays; 48adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tateimport java.util.Collections; 499ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tateimport java.util.HashSet; 509ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tateimport java.util.List; 519bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 52f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughesimport static android.system.OsConstants.*; 53b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate 549bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate/** 559bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate * Backup transport for stashing stuff into a known location on disk, and 569bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate * later restoring from there. For testing only. 579bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate */ 589bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 5974318c98a0f67e042815798f85c75eb7f14390e1Christopher Tatepublic class LocalTransport extends BackupTransport { 609bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private static final String TAG = "LocalTransport"; 61a50cd8d4264ca98e19b858596de3a223ba6bf42eEd Heyl private static final boolean DEBUG = false; 629bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 635cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate private static final String TRANSPORT_DIR_NAME 645cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate = "com.android.internal.backup.LocalTransport"; 655cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 66a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate private static final String TRANSPORT_DESTINATION_STRING 67a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate = "Backing up to debug-only private cache"; 68a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate 699679410db578e179c7559e7a52bb21c8082e9631Christopher Tate private static final String TRANSPORT_DATA_MANAGEMENT_LABEL 709679410db578e179c7559e7a52bb21c8082e9631Christopher Tate = ""; 719679410db578e179c7559e7a52bb21c8082e9631Christopher Tate 726a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private static final String INCREMENTAL_DIR = "_delta"; 736a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private static final String FULL_DATA_DIR = "_full"; 746a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 75adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // The currently-active restore set always has the same (nonzero!) token 76adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate private static final long CURRENT_SET_TOKEN = 1; 7750c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate 789bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private Context mContext; 799bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup"); 80adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate private File mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN)); 816a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR); 826a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR); 83adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 84efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private PackageInfo[] mRestorePackages = null; 85efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor private int mRestorePackage = -1; // Index into mRestorePackages 866a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private int mRestoreType; 876a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mRestoreSetDir; 886a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mRestoreSetIncrementalDir; 896a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate private File mRestoreSetFullDir; 90adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate private long mRestoreToken; 919bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 929ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // Additional bookkeeping for full backup 939ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private String mFullTargetPackage; 949ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private ParcelFileDescriptor mSocket; 959ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private FileInputStream mSocketInputStream; 969ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private BufferedOutputStream mFullBackupOutputStream; 979ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private byte[] mFullBackupBuffer; 989ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 999ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private File mFullRestoreSetDir; 1009ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate private HashSet<String> mFullRestorePackages; 1015a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate private FileInputStream mCurFullRestoreStream; 1025a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate private FileOutputStream mFullRestoreSocketStream; 1035a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate private byte[] mFullRestoreBuffer; 1049bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1059bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate public LocalTransport(Context context) { 1069bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate mContext = context; 107adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate mCurrentSetDir.mkdirs(); 1089ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mCurrentSetFullDir.mkdir(); 1099ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mCurrentSetIncrementalDir.mkdir(); 110adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate if (!SELinux.restorecon(mCurrentSetDir)) { 111adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate Log.e(TAG, "SELinux restorecon failed for " + mCurrentSetDir); 112ebab0ae105f1a6df593a4bc2549fae3ee8b2ade4rpcraig } 1139bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 1149bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1155a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 116cefba58d14f9669b57c16b4ea493779d882c43bdChristopher Tate public String name() { 117cefba58d14f9669b57c16b4ea493779d882c43bdChristopher Tate return new ComponentName(mContext, this.getClass()).flattenToShortString(); 118cefba58d14f9669b57c16b4ea493779d882c43bdChristopher Tate } 119cefba58d14f9669b57c16b4ea493779d882c43bdChristopher Tate 1205a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 121a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate public Intent configurationIntent() { 122a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate // The local transport is not user-configurable 123a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate return null; 124a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate } 125a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate 1265a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 127a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate public String currentDestinationString() { 128a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate return TRANSPORT_DESTINATION_STRING; 1299679410db578e179c7559e7a52bb21c8082e9631Christopher Tate } 1309679410db578e179c7559e7a52bb21c8082e9631Christopher Tate 1319679410db578e179c7559e7a52bb21c8082e9631Christopher Tate public Intent dataManagementIntent() { 1329679410db578e179c7559e7a52bb21c8082e9631Christopher Tate // The local transport does not present a data-management UI 1339679410db578e179c7559e7a52bb21c8082e9631Christopher Tate // TODO: consider adding simple UI to wipe the archives entirely, 1349679410db578e179c7559e7a52bb21c8082e9631Christopher Tate // for cleaning up the cache partition. 1359679410db578e179c7559e7a52bb21c8082e9631Christopher Tate return null; 1369679410db578e179c7559e7a52bb21c8082e9631Christopher Tate } 1379679410db578e179c7559e7a52bb21c8082e9631Christopher Tate 1389679410db578e179c7559e7a52bb21c8082e9631Christopher Tate public String dataManagementLabel() { 1399679410db578e179c7559e7a52bb21c8082e9631Christopher Tate return TRANSPORT_DATA_MANAGEMENT_LABEL; 140a8ddef346cece1ad229e270ac4deebbd41ba6721Chris Tate } 1415cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 1425a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 1430144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public String transportDirName() { 1445cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate return TRANSPORT_DIR_NAME; 1455cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate } 1465cb400bd72726c22f641f334951b35ce2ddcfeefChristopher Tate 1475a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 1480144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public long requestBackupTime() { 1499bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // any time is a good time for local backup 1509bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate return 0; 1519bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 1529bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1535a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 1540144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int initializeDevice() { 1550144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor if (DEBUG) Log.v(TAG, "wiping all data"); 156adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate deleteContents(mCurrentSetDir); 1575a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 1580144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor } 1590144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor 1605a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 1610144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) { 162b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate if (DEBUG) { 163b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate try { 164f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughes StructStat ss = Os.fstat(data.getFileDescriptor()); 165b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName 166b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate + " size=" + ss.st_size); 167b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } catch (ErrnoException e) { 168b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate Log.w(TAG, "Unable to stat input file in performBackup() on " 169b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate + packageInfo.packageName); 170b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 171b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 1729bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1739ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName); 1742fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate packageDir.mkdirs(); 1759bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 1762fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // Each 'record' in the restore set is kept in its own file, named by 1772fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // the record key. Wind through the data file, extracting individual 1782fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // record operations and building a set of all the updates to apply 1792fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // in this update. 1802fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate BackupDataInput changeSet = new BackupDataInput(data.getFileDescriptor()); 1812fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate try { 1822fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate int bufSize = 512; 1832fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate byte[] buf = new byte[bufSize]; 1842fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate while (changeSet.readNextHeader()) { 1852fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate String key = changeSet.getKey(); 1865d605dc56b036232e885f6ec36b888b729673060Joe Onorato String base64Key = new String(Base64.encode(key.getBytes())); 1875d605dc56b036232e885f6ec36b888b729673060Joe Onorato File entityFile = new File(packageDir, base64Key); 1885d605dc56b036232e885f6ec36b888b729673060Joe Onorato 1892fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate int dataSize = changeSet.getDataSize(); 190e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate 191e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize 192e9190a2750e1fb67e300d2c128227cc9b7339efeChristopher Tate + " key64=" + base64Key); 1932fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate 1945d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (dataSize >= 0) { 1951afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn if (entityFile.exists()) { 1961afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn entityFile.delete(); 1971afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn } 1985d605dc56b036232e885f6ec36b888b729673060Joe Onorato FileOutputStream entity = new FileOutputStream(entityFile); 1995d605dc56b036232e885f6ec36b888b729673060Joe Onorato 2005d605dc56b036232e885f6ec36b888b729673060Joe Onorato if (dataSize > bufSize) { 2015d605dc56b036232e885f6ec36b888b729673060Joe Onorato bufSize = dataSize; 2025d605dc56b036232e885f6ec36b888b729673060Joe Onorato buf = new byte[bufSize]; 2035d605dc56b036232e885f6ec36b888b729673060Joe Onorato } 2045d605dc56b036232e885f6ec36b888b729673060Joe Onorato changeSet.readEntityData(buf, 0, dataSize); 205b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate if (DEBUG) { 206b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate try { 207f97c63350abcc6715ba9fdc21fd3405d0f7ba716Elliott Hughes long cur = Os.lseek(data.getFileDescriptor(), 0, SEEK_CUR); 208b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate Log.v(TAG, " read entity data; new pos=" + cur); 209b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 210b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate catch (ErrnoException e) { 211b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate Log.w(TAG, "Unable to stat input file in performBackup() on " 212b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate + packageInfo.packageName); 213b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 214b048c33d5bdaec747195dfedf971d4d9155f5000Christopher Tate } 2155d605dc56b036232e885f6ec36b888b729673060Joe Onorato 2165d605dc56b036232e885f6ec36b888b729673060Joe Onorato try { 2175d605dc56b036232e885f6ec36b888b729673060Joe Onorato entity.write(buf, 0, dataSize); 2185d605dc56b036232e885f6ec36b888b729673060Joe Onorato } catch (IOException e) { 219efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath()); 2205a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 2215d605dc56b036232e885f6ec36b888b729673060Joe Onorato } finally { 2225d605dc56b036232e885f6ec36b888b729673060Joe Onorato entity.close(); 2235d605dc56b036232e885f6ec36b888b729673060Joe Onorato } 2245d605dc56b036232e885f6ec36b888b729673060Joe Onorato } else { 2255d605dc56b036232e885f6ec36b888b729673060Joe Onorato entityFile.delete(); 2262fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2272fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 2285a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 2292fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } catch (IOException e) { 2302fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // oops, something went wrong. abort the operation and return error. 231efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.v(TAG, "Exception reading backup input:", e); 2325a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 2332fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 234efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 235ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate 23625a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // Deletes the contents but not the given directory 23725a747f5c47f25c1a18961b03507f309b84924feChristopher Tate private void deleteContents(File dirname) { 23825a747f5c47f25c1a18961b03507f309b84924feChristopher Tate File[] contents = dirname.listFiles(); 23925a747f5c47f25c1a18961b03507f309b84924feChristopher Tate if (contents != null) { 24025a747f5c47f25c1a18961b03507f309b84924feChristopher Tate for (File f : contents) { 24125a747f5c47f25c1a18961b03507f309b84924feChristopher Tate if (f.isDirectory()) { 24225a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // delete the directory's contents then fall through 24325a747f5c47f25c1a18961b03507f309b84924feChristopher Tate // and delete the directory itself. 24425a747f5c47f25c1a18961b03507f309b84924feChristopher Tate deleteContents(f); 24525a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 24625a747f5c47f25c1a18961b03507f309b84924feChristopher Tate f.delete(); 24725a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 24825a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 24925a747f5c47f25c1a18961b03507f309b84924feChristopher Tate } 25025a747f5c47f25c1a18961b03507f309b84924feChristopher Tate 2515a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 2520144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int clearBackupData(PackageInfo packageInfo) { 253ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName); 254ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate 2559ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName); 2560abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate final File[] fileset = packageDir.listFiles(); 2570abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate if (fileset != null) { 2580abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate for (File f : fileset) { 2590abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate f.delete(); 2600abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate } 2610abf6a001461a4c2ea31ddc44a60b003b4e0554dChristopher Tate packageDir.delete(); 262ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate } 2639ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 2649ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate packageDir = new File(mCurrentSetFullDir, packageInfo.packageName); 2659ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate final File[] tarballs = packageDir.listFiles(); 2669ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (tarballs != null) { 2679ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate for (File f : tarballs) { 2689ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate f.delete(); 2699ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 2709ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate packageDir.delete(); 2719ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 2729ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 2735a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 274ee0e78af5af3bf23dd928fe5e0ebeb39157eaf66Christopher Tate } 2759bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 2765a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 2770144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int finishBackup() { 278e079264b981d87c648921185528b553a86ae353dChristopher Tate if (DEBUG) Log.v(TAG, "finishBackup() of " + mFullTargetPackage); 279e079264b981d87c648921185528b553a86ae353dChristopher Tate return tearDownFullBackup(); 280e079264b981d87c648921185528b553a86ae353dChristopher Tate } 281e079264b981d87c648921185528b553a86ae353dChristopher Tate 282e079264b981d87c648921185528b553a86ae353dChristopher Tate // ------------------------------------------------------------------------------------ 283e079264b981d87c648921185528b553a86ae353dChristopher Tate // Full backup handling 284e079264b981d87c648921185528b553a86ae353dChristopher Tate 285e079264b981d87c648921185528b553a86ae353dChristopher Tate private int tearDownFullBackup() { 2869ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (mSocket != null) { 2879ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate try { 2889ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullBackupOutputStream.flush(); 2899ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullBackupOutputStream.close(); 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; 3009ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3019ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3025a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 3039bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 3049bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 305e079264b981d87c648921185528b553a86ae353dChristopher Tate private File tarballFile(String pkgName) { 306e079264b981d87c648921185528b553a86ae353dChristopher Tate return new File(mCurrentSetFullDir, pkgName); 307e079264b981d87c648921185528b553a86ae353dChristopher Tate } 3085a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 3095a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 3109ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate public long requestFullBackupTime() { 3119ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate return 0; 3129ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3139ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3145a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 3159ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) { 3169ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (mSocket != null) { 3179ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.e(TAG, "Attempt to initiate full backup while one is in progress"); 3185a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3199ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3209ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3219ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (DEBUG) { 3229ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.i(TAG, "performFullBackup : " + targetPackage); 3239ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3249ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3259ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // We know a priori that we run in the system process, so we need to make 3269ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // sure to dup() our own copy of the socket fd. Transports which run in 3279ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // their own processes must not do this. 3289ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate try { 3299ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor()); 3309ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mSocketInputStream = new FileInputStream(mSocket.getFileDescriptor()); 3319ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } catch (IOException e) { 3329ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.e(TAG, "Unable to process socket for full backup"); 3335a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3349ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3359ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3369ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullTargetPackage = targetPackage.packageName; 3379ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate FileOutputStream tarstream; 3389ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate try { 339e079264b981d87c648921185528b553a86ae353dChristopher Tate File tarball = tarballFile(mFullTargetPackage); 3409ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate tarstream = new FileOutputStream(tarball); 3419ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } catch (FileNotFoundException e) { 3425a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3439ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3449ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullBackupOutputStream = new BufferedOutputStream(tarstream); 3459ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullBackupBuffer = new byte[4096]; 3469ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3475a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 3489ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3499ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3505a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 3519ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate public int sendBackupData(int numBytes) { 3529ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (mFullBackupBuffer == null) { 3539ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.w(TAG, "Attempted sendBackupData before performFullBackup"); 3545a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3559ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3569ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 3579ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (numBytes > mFullBackupBuffer.length) { 3589ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullBackupBuffer = new byte[numBytes]; 3599ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3609ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate while (numBytes > 0) { 3619ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate try { 3629ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, numBytes); 3639ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate if (nRead < 0) { 3649ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // Something went wrong if we expect data but saw EOD 3659ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.w(TAG, "Unexpected EOD; failing backup"); 3665a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3679ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3689ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead); 3699ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate numBytes -= nRead; 3709ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } catch (IOException e) { 3719ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate Log.e(TAG, "Error handling backup data for " + mFullTargetPackage); 3725a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 3739ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3749ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3755a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 3769ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 3779ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 378e079264b981d87c648921185528b553a86ae353dChristopher Tate // For now we can't roll back, so just tear everything down. 379e079264b981d87c648921185528b553a86ae353dChristopher Tate @Override 380e079264b981d87c648921185528b553a86ae353dChristopher Tate public void cancelFullBackup() { 381e079264b981d87c648921185528b553a86ae353dChristopher Tate if (DEBUG) { 382e079264b981d87c648921185528b553a86ae353dChristopher Tate Log.i(TAG, "Canceling full backup of " + mFullTargetPackage); 383e079264b981d87c648921185528b553a86ae353dChristopher Tate } 384e079264b981d87c648921185528b553a86ae353dChristopher Tate File archive = tarballFile(mFullTargetPackage); 385e079264b981d87c648921185528b553a86ae353dChristopher Tate tearDownFullBackup(); 386e079264b981d87c648921185528b553a86ae353dChristopher Tate if (archive.exists()) { 387e079264b981d87c648921185528b553a86ae353dChristopher Tate archive.delete(); 388e079264b981d87c648921185528b553a86ae353dChristopher Tate } 389e079264b981d87c648921185528b553a86ae353dChristopher Tate } 390e079264b981d87c648921185528b553a86ae353dChristopher Tate 3919ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // ------------------------------------------------------------------------------------ 3929bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate // Restore handling 39351fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate static final long[] POSSIBLE_SETS = { 2, 3, 4, 5, 6, 7, 8, 9 }; 3945a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 3955a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 39674318c98a0f67e042815798f85c75eb7f14390e1Christopher Tate public RestoreSet[] getAvailableRestoreSets() { 397adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate long[] existing = new long[POSSIBLE_SETS.length + 1]; 398adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate int num = 0; 399adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 4009ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // see which possible non-current sets exist... 401adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate for (long token : POSSIBLE_SETS) { 402adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate if ((new File(mDataDir, Long.toString(token))).exists()) { 403adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate existing[num++] = token; 404adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 405adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 4069ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // ...and always the currently-active set last 407adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate existing[num++] = CURRENT_SET_TOKEN; 408adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 409adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate RestoreSet[] available = new RestoreSet[num]; 410adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate for (int i = 0; i < available.length; i++) { 411adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate available[i] = new RestoreSet("Local disk image", "flash", existing[i]); 412adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 413adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return available; 4149bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 4159bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 4165a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 41750c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate public long getCurrentRestoreSet() { 418adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // The current restore set always has the same token 419adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return CURRENT_SET_TOKEN; 42050c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate } 42150c6df04cf17a99c3959c306a4e0e10da6d85c46Christopher Tate 4225a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 4230144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int startRestore(long token, PackageInfo[] packages) { 42451fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate if (DEBUG) Log.v(TAG, "start restore " + token + " : " + packages.length 42551fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate + " matching packages"); 426efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mRestorePackages = packages; 427efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor mRestorePackage = -1; 428adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate mRestoreToken = token; 4296a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreSetDir = new File(mDataDir, Long.toString(token)); 4306a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreSetIncrementalDir = new File(mRestoreSetDir, INCREMENTAL_DIR); 4316a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreSetFullDir = new File(mRestoreSetDir, FULL_DATA_DIR); 4325a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 433efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 4349bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 4356a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate @Override 4366a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate public RestoreDescription nextRestorePackage() { 437efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); 4386a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 4396a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate boolean found = false; 440efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor while (++mRestorePackage < mRestorePackages.length) { 441efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor String name = mRestorePackages[mRestorePackage].packageName; 4426a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 4436a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate // If we have key/value data for this package, deliver that 444a9b91864a1aedd71eaaaa43ee078cf93922289f3Christopher Tate // skip packages where we have a data dir but no actual contents 4456a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate String[] contents = (new File(mRestoreSetIncrementalDir, name)).list(); 446a9b91864a1aedd71eaaaa43ee078cf93922289f3Christopher Tate if (contents != null && contents.length > 0) { 4476a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) = " + name); 4486a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreType = RestoreDescription.TYPE_KEY_VALUE; 4496a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate found = true; 4506a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate } 4516a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 4526a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (!found) { 4536a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate // No key/value data; check for [non-empty] full data 4546a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate File maybeFullData = new File(mRestoreSetFullDir, name); 4556a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (maybeFullData.length() > 0) { 4566a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_FULL_STREAM) = " + name); 4576a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate mRestoreType = RestoreDescription.TYPE_FULL_STREAM; 4585a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mCurFullRestoreStream = null; // ensure starting from the ground state 4596a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate found = true; 4606a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate } 4616a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate } 4626a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate 4636a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (found) { 4646a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate return new RestoreDescription(name, mRestoreType); 4652fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 4669bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 4679bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 468efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, " no more packages to restore"); 4696a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate return RestoreDescription.NO_MORE_PACKAGES; 4709bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 4719bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 4725a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 4730144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor public int getRestoreData(ParcelFileDescriptor outFd) { 474efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); 475efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called"); 4766a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate if (mRestoreType != RestoreDescription.TYPE_KEY_VALUE) { 4776a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate throw new IllegalStateException("getRestoreData(fd) for non-key/value dataset"); 4786a49dd087f29cfca82d55dfabeb97439ef84b508Christopher Tate } 47951fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate File packageDir = new File(mRestoreSetIncrementalDir, 48051fea57e06fcb1dab1d239a5fff6e75ba2b7cee7Christopher Tate mRestorePackages[mRestorePackage].packageName); 4819bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate 4822fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate // The restore set is the concatenation of the individual record blobs, 483adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // each of which is a file in the package's directory. We return the 484adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // data in lexical order sorted by key, so that apps which use synthetic 485adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // keys like BLOB_1, BLOB_2, etc will see the date in the most obvious 486adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // order. 487adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate ArrayList<DecodedFilename> blobs = contentsByKey(packageDir); 4880144516e19b9fd5415a56f8b41191187e2344bb0Dan Egnor if (blobs == null) { // nextRestorePackage() ensures the dir exists, so this is an error 489adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate Log.e(TAG, "No keys for package: " + packageDir); 4905a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 491efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } 492efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor 493efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor // We expect at least some data if the directory exists in the first place 494adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate if (DEBUG) Log.v(TAG, " getRestoreData() found " + blobs.size() + " key files"); 495efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor()); 496efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor try { 497adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate for (DecodedFilename keyEntry : blobs) { 498adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate File f = keyEntry.file; 499efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor FileInputStream in = new FileInputStream(f); 500efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor try { 501efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor int size = (int) f.length(); 502efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor byte[] buf = new byte[size]; 503efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor in.read(buf); 504adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate if (DEBUG) Log.v(TAG, " ... key=" + keyEntry.key + " size=" + size); 505adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate out.writeEntityHeader(keyEntry.key, size); 506efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor out.writeEntityData(buf, size); 507efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } finally { 508efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor in.close(); 5098e55eac96d768a4de68a091f57487deadf6d0a87Christopher Tate } 5102fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 5115a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 512efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor } catch (IOException e) { 513efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor Log.e(TAG, "Unable to read backup records", e); 5145a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; 5152fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2Christopher Tate } 5169bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate } 5173a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate 518adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate static class DecodedFilename implements Comparable<DecodedFilename> { 519adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate public File file; 520adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate public String key; 521adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 522adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate public DecodedFilename(File f) { 523adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate file = f; 524adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate key = new String(Base64.decode(f.getName())); 525adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 526adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 527adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate @Override 528adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate public int compareTo(DecodedFilename other) { 529adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // sorts into ascending lexical order by decoded key 530adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return key.compareTo(other.key); 531adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 532adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 533adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 534adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // Return a list of the files in the given directory, sorted lexically by 535adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // the Base64-decoded file name, not by the on-disk filename 536adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate private ArrayList<DecodedFilename> contentsByKey(File dir) { 537adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate File[] allFiles = dir.listFiles(); 538adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate if (allFiles == null || allFiles.length == 0) { 539adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return null; 540adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 541adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 542adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate // Decode the filenames into keys then sort lexically by key 543adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate ArrayList<DecodedFilename> contents = new ArrayList<DecodedFilename>(); 544adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate for (File f : allFiles) { 545adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate contents.add(new DecodedFilename(f)); 546adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 547adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate Collections.sort(contents); 548adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate return contents; 549adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate } 550adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate 5515a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 552efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor public void finishRestore() { 553efe52647f6b41993be43a5f47d1178bb0468cec8Dan Egnor if (DEBUG) Log.v(TAG, "finishRestore()"); 5545a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (mRestoreType == RestoreDescription.TYPE_FULL_STREAM) { 5555a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate resetFullRestoreState(); 5565a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 5575a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mRestoreType = 0; 5583a31a93b8a195ae2d0180e6dfbf292da2e581f50Christopher Tate } 5599ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 5609ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // ------------------------------------------------------------------------------------ 5619ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate // Full restore handling 5629ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 5635a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate private void resetFullRestoreState() { 564824392bdbdd0d593c4bd2d26f197bb0009ff75c9Christopher Tate IoUtils.closeQuietly(mCurFullRestoreStream); 5655a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mCurFullRestoreStream = null; 5665a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mFullRestoreSocketStream = null; 5675a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mFullRestoreBuffer = null; 5689ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 5699ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate 5709ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate /** 5719ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * Ask the transport to provide data for the "current" package being restored. The 5729ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * transport then writes some data to the socket supplied to this call, and returns 5739ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * the number of bytes written. The system will then read that many bytes and 5749ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * stream them to the application's agent for restore, then will call this method again 5759ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * to receive the next chunk of the archive. This sequence will be repeated until the 5769ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * transport returns zero indicating that all of the package's data has been delivered 5779ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * (or returns a negative value indicating some sort of hard error condition at the 5789ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * transport level). 5799ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * 5809ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * <p>After this method returns zero, the system will then call 5819ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * {@link #getNextFullRestorePackage()} to begin the restore process for the next 5829ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * application, and the sequence begins again. 5839ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * 5849ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * @param socket The file descriptor that the transport will use for delivering the 5859ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * streamed archive. 5869ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * @return 0 when no more data for the current package is available. A positive value 5879ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * indicates the presence of that much data to be delivered to the app. A negative 5889ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR}, 5899ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * indicating a fatal error condition that precludes further restore operations 5909ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate * on the current dataset. 5919ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate */ 5925a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 5939ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) { 5945a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (mRestoreType != RestoreDescription.TYPE_FULL_STREAM) { 5955a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate throw new IllegalStateException("Asked for full restore data for non-stream package"); 5965a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 5975a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 5985a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // first chunk? 5995a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (mCurFullRestoreStream == null) { 6005a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate final String name = mRestorePackages[mRestorePackage].packageName; 6015a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (DEBUG) Log.i(TAG, "Starting full restore of " + name); 6025a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate File dataset = new File(mRestoreSetFullDir, name); 6035a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate try { 6045a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mCurFullRestoreStream = new FileInputStream(dataset); 6055a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } catch (IOException e) { 6065a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // If we can't open the target package's tarball, we return the single-package 6075a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // error code and let the caller go on to the next package. 6085a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate Log.e(TAG, "Unable to read archive for " + name); 6095a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_PACKAGE_REJECTED; 6105a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6115a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mFullRestoreSocketStream = new FileOutputStream(socket.getFileDescriptor()); 61289101f7fe89134a609459e80f779c1a5114e562aChristopher Tate mFullRestoreBuffer = new byte[2*1024]; 6135a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6145a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 6155a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate int nRead; 6165a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate try { 6175a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate nRead = mCurFullRestoreStream.read(mFullRestoreBuffer); 6185a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (nRead < 0) { 6195a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // EOF: tell the caller we're done 6205a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate nRead = NO_MORE_DATA; 6215a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } else if (nRead == 0) { 6225a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // This shouldn't happen when reading a FileInputStream; we should always 6235a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // get either a positive nonzero byte count or -1. Log the situation and 6245a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // treat it as EOF. 6255a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate Log.w(TAG, "read() of archive file returned 0; treating as EOF"); 6265a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate nRead = NO_MORE_DATA; 6275a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } else { 6285a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (DEBUG) { 6295a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate Log.i(TAG, " delivering restore chunk: " + nRead); 6305a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6315a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mFullRestoreSocketStream.write(mFullRestoreBuffer, 0, nRead); 6325a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6335a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } catch (IOException e) { 6345a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_ERROR; // Hard error accessing the file; shouldn't happen 6355a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } finally { 6365a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // Most transports will need to explicitly close 'socket' here, but this transport 6375a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // is in the same process as the caller so it can leave it up to the backup manager 6385a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate // to manage both socket fds. 6395a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6405a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 6415a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return nRead; 6429ff53a7100b1a40f5d2df3eb19a2f3f2fff39a46Christopher Tate } 6435a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 6445a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate /** 6455a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM} 6465a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * data for restore, it will invoke this method to tell the transport that it should 6475a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * abandon the data download for the current package. The OS will then either call 6485a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * {@link #nextRestorePackage()} again to move on to restoring the next package in the 6495a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * set being iterated over, or will call {@link #finishRestore()} to shut down the restore 6505a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * operation. 6515a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * 6525a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the 6535a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious 6545a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * transport-level failure. If the transport reports an error here, the entire restore 6555a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate * operation will immediately be finished with no further attempts to restore app data. 6565a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate */ 6575a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate @Override 6585a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate public int abortFullRestore() { 6595a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate if (mRestoreType != RestoreDescription.TYPE_FULL_STREAM) { 6605a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate throw new IllegalStateException("abortFullRestore() but not currently restoring"); 6615a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6625a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate resetFullRestoreState(); 6635a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate mRestoreType = 0; 6645a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate return TRANSPORT_OK; 6655a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate } 6665a009f9008d1f18b156c142b69e173109f5e218bChristopher Tate 6679bbc21a773cbdfbef2876a75c32bda5839647751Christopher Tate} 668