LocalTransport.java revision f68eb500f99361541049e09eb7f9ddd6f4ef4efa
1package com.android.internal.backup; 2 3import android.backup.BackupDataInput; 4import android.backup.BackupDataOutput; 5import android.backup.RestoreSet; 6import android.content.Context; 7import android.content.pm.PackageInfo; 8import android.content.pm.PackageManager; 9import android.content.pm.PackageManager.NameNotFoundException; 10import android.os.Environment; 11import android.os.ParcelFileDescriptor; 12import android.os.RemoteException; 13import android.util.Log; 14 15import java.io.File; 16import java.io.FileFilter; 17import java.io.FileInputStream; 18import java.io.FileOutputStream; 19import java.io.IOException; 20import java.util.ArrayList; 21 22/** 23 * Backup transport for stashing stuff into a known location on disk, and 24 * later restoring from there. For testing only. 25 */ 26 27public class LocalTransport extends IBackupTransport.Stub { 28 private static final String TAG = "LocalTransport"; 29 private static final boolean DEBUG = true; 30 31 private Context mContext; 32 private PackageManager mPackageManager; 33 private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup"); 34 private FileFilter mDirFileFilter = new FileFilter() { 35 public boolean accept(File f) { 36 return f.isDirectory(); 37 } 38 }; 39 40 41 public LocalTransport(Context context) { 42 if (DEBUG) Log.v(TAG, "Transport constructed"); 43 mContext = context; 44 mPackageManager = context.getPackageManager(); 45 } 46 47 public long requestBackupTime() throws RemoteException { 48 // any time is a good time for local backup 49 return 0; 50 } 51 52 public int startSession() throws RemoteException { 53 if (DEBUG) Log.v(TAG, "session started"); 54 mDataDir.mkdirs(); 55 return 0; 56 } 57 58 public int endSession() throws RemoteException { 59 if (DEBUG) Log.v(TAG, "session ended"); 60 return 0; 61 } 62 63 public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) 64 throws RemoteException { 65 if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName); 66 int err = 0; 67 68 File packageDir = new File(mDataDir, packageInfo.packageName); 69 packageDir.mkdirs(); 70 71 // Each 'record' in the restore set is kept in its own file, named by 72 // the record key. Wind through the data file, extracting individual 73 // record operations and building a set of all the updates to apply 74 // in this update. 75 BackupDataInput changeSet = new BackupDataInput(data.getFileDescriptor()); 76 try { 77 int bufSize = 512; 78 byte[] buf = new byte[bufSize]; 79 while (changeSet.readNextHeader()) { 80 String key = changeSet.getKey(); 81 int dataSize = changeSet.getDataSize(); 82 if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize); 83 if (dataSize > bufSize) { 84 bufSize = dataSize; 85 buf = new byte[bufSize]; 86 } 87 changeSet.readEntityData(buf, dataSize); 88 if (DEBUG) Log.v(TAG, " + data size " + dataSize); 89 90 File entityFile = new File(packageDir, key); 91 FileOutputStream entity = new FileOutputStream(entityFile); 92 try { 93 entity.write(buf, 0, dataSize); 94 } catch (IOException e) { 95 Log.e(TAG, "Unable to update key file " 96 + entityFile.getAbsolutePath()); 97 err = -1; 98 } finally { 99 entity.close(); 100 } 101 } 102 } catch (IOException e) { 103 // oops, something went wrong. abort the operation and return error. 104 Log.v(TAG, "Exception reading backup input:"); 105 e.printStackTrace(); 106 err = -1; 107 } 108 109 return err; 110 } 111 112 // Restore handling 113 public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException { 114 // one hardcoded restore set 115 RestoreSet set = new RestoreSet("Local disk image", "flash", 0); 116 RestoreSet[] array = { set }; 117 return array; 118 } 119 120 public PackageInfo[] getAppSet(int token) throws android.os.RemoteException { 121 if (DEBUG) Log.v(TAG, "getting app set " + token); 122 // the available packages are the extant subdirs of mDatadir 123 File[] packageDirs = mDataDir.listFiles(mDirFileFilter); 124 ArrayList<PackageInfo> packages = new ArrayList<PackageInfo>(); 125 for (File dir : packageDirs) { 126 try { 127 PackageInfo pkg = mPackageManager.getPackageInfo(dir.getName(), 128 PackageManager.GET_SIGNATURES); 129 if (pkg != null) { 130 packages.add(pkg); 131 } 132 } catch (NameNotFoundException e) { 133 // restore set contains data for a package not installed on the 134 // phone -- just ignore it. 135 } 136 } 137 138 if (DEBUG) { 139 Log.v(TAG, "Built app set of " + packages.size() + " entries:"); 140 for (PackageInfo p : packages) { 141 Log.v(TAG, " + " + p.packageName); 142 } 143 } 144 145 PackageInfo[] result = new PackageInfo[packages.size()]; 146 return packages.toArray(result); 147 } 148 149 public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor outFd) 150 throws android.os.RemoteException { 151 if (DEBUG) Log.v(TAG, "getting restore data " + token + " : " + packageInfo.packageName); 152 // we only support one hardcoded restore set 153 if (token != 0) return -1; 154 155 // the data for a given package is at a known location 156 File packageDir = new File(mDataDir, packageInfo.packageName); 157 158 // The restore set is the concatenation of the individual record blobs, 159 // each of which is a file in the package's directory 160 File[] blobs = packageDir.listFiles(); 161 int err = 0; 162 if (blobs != null && blobs.length > 0) { 163 BackupDataOutput out = new BackupDataOutput(mContext, outFd.getFileDescriptor()); 164 try { 165 for (File f : blobs) { 166 FileInputStream in = new FileInputStream(f); 167 int size = (int) f.length(); 168 byte[] buf = new byte[size]; 169 in.read(buf); 170 out.writeEntityHeader(f.getName(), size); 171 out.writeEntityData(buf, size); 172 } 173 } catch (Exception e) { 174 Log.e(TAG, "Unable to read backup records"); 175 err = -1; 176 } 177 } 178 return err; 179 } 180} 181