1b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tatepackage com.android.sharedstoragebackup; 2b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 3b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tateimport android.app.backup.FullBackupAgent; 479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport android.app.backup.FullBackup; 579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport android.app.backup.FullBackupDataOutput; 6b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tateimport android.content.Context; 7b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tateimport android.os.ParcelFileDescriptor; 8b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tateimport android.os.storage.StorageManager; 9b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tateimport android.os.storage.StorageVolume; 10b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tateimport android.util.Slog; 11b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 12b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tateimport java.io.File; 13b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tateimport java.io.IOException; 14b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 15b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tatepublic class SharedStorageAgent extends FullBackupAgent { 16b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate static final String TAG = "SharedStorageAgent"; 17b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate static final boolean DEBUG = true; 18b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 19b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate StorageVolume[] mVolumes; 20b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 21b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate @Override 22b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate public void onCreate() { 23b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate StorageManager mgr = (StorageManager) getSystemService(Context.STORAGE_SERVICE); 24b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate if (mgr != null) { 25b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate mVolumes = mgr.getVolumeList(); 26b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } else { 27b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate Slog.e(TAG, "Unable to access Storage Manager"); 28b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 29b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 30b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 3179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate /** 3279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * Full backup of the shared-storage filesystem 3379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate */ 34b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate @Override 3579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate public void onFullBackup(FullBackupDataOutput output) throws IOException { 36b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate // If there are shared-storage volumes available, run the inherited directory- 37b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate // hierarchy backup process on them. By convention in the Storage Manager, the 38b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate // "primary" shared storage volume is first in the list. 39b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate if (mVolumes != null) { 40fb2ea43112bdf5a7dc121b59e2ef7e8b411bd019Christopher Tate if (DEBUG) Slog.i(TAG, "Backing up " + mVolumes.length + " shared volumes"); 41b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate for (int i = 0; i < mVolumes.length; i++) { 42b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate StorageVolume v = mVolumes[i]; 43b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate // Express the contents of volume N this way in the tar stream: 44b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate // shared/N/path/to/file 45b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate // The restore will then extract to the given volume 46b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate String domain = FullBackup.SHARED_PREFIX + i; 4779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate fullBackupFileTree(null, domain, v.getPath(), null, output); 48b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 49b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 50b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 51b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 52b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate /** 53b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate * Full restore of one file to shared storage 54b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate */ 55b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate @Override 56b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate public void onRestoreFile(ParcelFileDescriptor data, long size, 57b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate int type, String domain, String relpath, long mode, long mtime) 58b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate throws IOException { 59fb2ea43112bdf5a7dc121b59e2ef7e8b411bd019Christopher Tate if (DEBUG) Slog.d(TAG, "Shared restore: [ " + domain + " : " + relpath + "]"); 60b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 61b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate File outFile = null; 62b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 63b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate // The file path must be in the semantic form [number]/path/to/file... 64b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate int slash = relpath.indexOf('/'); 65b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate if (slash > 0) { 66b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate try { 67b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate int i = Integer.parseInt(relpath.substring(0, slash)); 68b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate if (i <= mVolumes.length) { 69b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate outFile = new File(mVolumes[i].getPath(), relpath.substring(slash + 1)); 70b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate if (DEBUG) Slog.i(TAG, " => " + outFile.getAbsolutePath()); 71b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } else { 72b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate Slog.w(TAG, "Cannot restore data for unavailable volume " + i); 73b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 74b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } catch (NumberFormatException e) { 75b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate if (DEBUG) Slog.w(TAG, "Bad volume number token: " + relpath.substring(0, slash)); 76b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 77b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } else { 78b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate if (DEBUG) Slog.i(TAG, "Can't find volume-number token"); 79b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 80b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate if (outFile == null) { 81b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate Slog.e(TAG, "Skipping data with malformed path " + relpath); 82b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 83b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 8479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate FullBackup.restoreFile(data, size, type, -1, mtime, outFile); 85b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate } 86b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate} 87