Christopher Tate | 9bbc21a | 2009-06-10 20:23:25 -0700 | [diff] [blame^] | 1 | package com.android.internal.backup; |
| 2 | |
| 3 | import android.backup.RestoreSet; |
| 4 | import android.content.Context; |
| 5 | import android.content.pm.PackageInfo; |
| 6 | import android.content.pm.PackageManager; |
| 7 | import android.content.pm.PackageManager.NameNotFoundException; |
| 8 | import android.os.Environment; |
| 9 | import android.os.ParcelFileDescriptor; |
| 10 | import android.os.RemoteException; |
| 11 | import android.util.Log; |
| 12 | |
| 13 | import java.io.File; |
| 14 | import java.io.FileFilter; |
| 15 | import java.io.FileInputStream; |
| 16 | import java.io.FileOutputStream; |
| 17 | import java.io.IOException; |
| 18 | import java.util.ArrayList; |
| 19 | |
| 20 | /** |
| 21 | * Backup transport for stashing stuff into a known location on disk, and |
| 22 | * later restoring from there. For testing only. |
| 23 | */ |
| 24 | |
| 25 | public class LocalTransport extends IBackupTransport.Stub { |
| 26 | private static final String TAG = "LocalTransport"; |
| 27 | private static final String DATA_FILE_NAME = "data"; |
| 28 | |
| 29 | private Context mContext; |
| 30 | private PackageManager mPackageManager; |
| 31 | private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup"); |
| 32 | private FileFilter mDirFileFilter = new FileFilter() { |
| 33 | public boolean accept(File f) { |
| 34 | return f.isDirectory(); |
| 35 | } |
| 36 | }; |
| 37 | |
| 38 | |
| 39 | public LocalTransport(Context context) { |
| 40 | mContext = context; |
| 41 | mPackageManager = context.getPackageManager(); |
| 42 | } |
| 43 | |
| 44 | public long requestBackupTime() throws RemoteException { |
| 45 | // any time is a good time for local backup |
| 46 | return 0; |
| 47 | } |
| 48 | |
| 49 | public int startSession() throws RemoteException { |
| 50 | return 0; |
| 51 | } |
| 52 | |
| 53 | public int endSession() throws RemoteException { |
| 54 | return 0; |
| 55 | } |
| 56 | |
| 57 | public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) |
| 58 | throws RemoteException { |
| 59 | File packageDir = new File(mDataDir, packageInfo.packageName); |
| 60 | File imageFileName = new File(packageDir, DATA_FILE_NAME); |
| 61 | |
| 62 | //!!! TODO: process the (partial) update into the persistent restore set: |
| 63 | |
| 64 | // Parse out the existing image file into the key/value map |
| 65 | |
| 66 | // Parse out the backup data into the key/value updates |
| 67 | |
| 68 | // Apply the backup key/value updates to the image |
| 69 | |
| 70 | // Write out the image in the canonical format |
| 71 | |
| 72 | return -1; |
| 73 | } |
| 74 | |
| 75 | // Restore handling |
| 76 | public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException { |
| 77 | // one hardcoded restore set |
| 78 | RestoreSet[] set = new RestoreSet[1]; |
| 79 | set[0].device = "flash"; |
| 80 | set[0].name = "Local disk image"; |
| 81 | set[0].token = 0; |
| 82 | return set; |
| 83 | } |
| 84 | |
| 85 | public PackageInfo[] getAppSet(int token) throws android.os.RemoteException { |
| 86 | // the available packages are the extant subdirs of mDatadir |
| 87 | File[] packageDirs = mDataDir.listFiles(mDirFileFilter); |
| 88 | ArrayList<PackageInfo> packages = new ArrayList<PackageInfo>(); |
| 89 | for (File dir : packageDirs) { |
| 90 | try { |
| 91 | PackageInfo pkg = mPackageManager.getPackageInfo(dir.getName(), |
| 92 | PackageManager.GET_SIGNATURES); |
| 93 | if (pkg != null) { |
| 94 | packages.add(pkg); |
| 95 | } |
| 96 | } catch (NameNotFoundException e) { |
| 97 | // restore set contains data for a package not installed on the |
| 98 | // phone -- just ignore it. |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | Log.v(TAG, "Built app set of " + packages.size() + " entries:"); |
| 103 | for (PackageInfo p : packages) { |
| 104 | Log.v(TAG, " + " + p.packageName); |
| 105 | } |
| 106 | |
| 107 | PackageInfo[] result = new PackageInfo[packages.size()]; |
| 108 | return packages.toArray(result); |
| 109 | } |
| 110 | |
| 111 | public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor output) |
| 112 | throws android.os.RemoteException { |
| 113 | // we only support one hardcoded restore set |
| 114 | if (token != 0) return -1; |
| 115 | |
| 116 | // the data for a given package is at a known location |
| 117 | File packageDir = new File(mDataDir, packageInfo.packageName); |
| 118 | File imageFile = new File(packageDir, DATA_FILE_NAME); |
| 119 | |
| 120 | // restore is relatively easy: we already maintain the full data set in |
| 121 | // the canonical form understandable to the BackupAgent |
| 122 | return copyFileToFD(imageFile, output); |
| 123 | } |
| 124 | |
| 125 | private int copyFileToFD(File source, ParcelFileDescriptor dest) { |
| 126 | try { |
| 127 | FileInputStream in = new FileInputStream(source); |
| 128 | FileOutputStream out = new FileOutputStream(dest.getFileDescriptor()); |
| 129 | byte[] buffer = new byte[4096]; |
| 130 | int bytesRead; |
| 131 | while ((bytesRead = in.read(buffer)) >= 0) { |
| 132 | out.write(buffer, 0, bytesRead); |
| 133 | } |
| 134 | } catch (IOException e) { |
| 135 | // something went wrong; claim failure |
| 136 | return -1; |
| 137 | } |
| 138 | return 0; |
| 139 | } |
| 140 | } |