Flesh out restore interface on manager; work up most of LocalTransport

This commit is contained in:
Christopher Tate
2009-06-10 20:23:25 -07:00
parent b6391d6377
commit 9bbc21a773
4 changed files with 180 additions and 63 deletions

View File

@@ -45,7 +45,7 @@ public class BackupManager {
/**
* Defined backup transports understood by {@link IBackupManager.selectBackupTransport}.
*/
public static final int TRANSPORT_ADB = 1;
public static final int TRANSPORT_LOCAL = 1;
public static final int TRANSPORT_GOOGLE = 2;
/**

View File

@@ -1,55 +0,0 @@
package com.android.internal.backup;
import android.backup.RestoreSet;
import android.content.pm.PackageInfo;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
/**
* Backup transport for full backup over adb. This transport pipes everything to
* a file in a known location in /cache, which 'adb backup' then pulls to the desktop
* (deleting it afterwards).
*/
public class AdbTransport extends IBackupTransport.Stub {
public long requestBackupTime() throws RemoteException {
return 0;
}
public int startSession() throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
public int endSession() throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
// Restore handling
public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException {
RestoreSet[] set = new RestoreSet[1];
set[0].device = "USB";
set[0].name = "adb";
set[0].token = 0;
return set;
}
public PackageInfo[] getAppSet(int token) throws android.os.RemoteException {
// !!! TODO: real implementation
return new PackageInfo[0];
}
public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor data)
throws android.os.RemoteException {
// !!! TODO: real implementation
return 0;
}
}

View File

@@ -0,0 +1,140 @@
package com.android.internal.backup;
import android.backup.RestoreSet;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* Backup transport for stashing stuff into a known location on disk, and
* later restoring from there. For testing only.
*/
public class LocalTransport extends IBackupTransport.Stub {
private static final String TAG = "LocalTransport";
private static final String DATA_FILE_NAME = "data";
private Context mContext;
private PackageManager mPackageManager;
private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
private FileFilter mDirFileFilter = new FileFilter() {
public boolean accept(File f) {
return f.isDirectory();
}
};
public LocalTransport(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
}
public long requestBackupTime() throws RemoteException {
// any time is a good time for local backup
return 0;
}
public int startSession() throws RemoteException {
return 0;
}
public int endSession() throws RemoteException {
return 0;
}
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
throws RemoteException {
File packageDir = new File(mDataDir, packageInfo.packageName);
File imageFileName = new File(packageDir, DATA_FILE_NAME);
//!!! TODO: process the (partial) update into the persistent restore set:
// Parse out the existing image file into the key/value map
// Parse out the backup data into the key/value updates
// Apply the backup key/value updates to the image
// Write out the image in the canonical format
return -1;
}
// Restore handling
public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException {
// one hardcoded restore set
RestoreSet[] set = new RestoreSet[1];
set[0].device = "flash";
set[0].name = "Local disk image";
set[0].token = 0;
return set;
}
public PackageInfo[] getAppSet(int token) throws android.os.RemoteException {
// the available packages are the extant subdirs of mDatadir
File[] packageDirs = mDataDir.listFiles(mDirFileFilter);
ArrayList<PackageInfo> packages = new ArrayList<PackageInfo>();
for (File dir : packageDirs) {
try {
PackageInfo pkg = mPackageManager.getPackageInfo(dir.getName(),
PackageManager.GET_SIGNATURES);
if (pkg != null) {
packages.add(pkg);
}
} catch (NameNotFoundException e) {
// restore set contains data for a package not installed on the
// phone -- just ignore it.
}
}
Log.v(TAG, "Built app set of " + packages.size() + " entries:");
for (PackageInfo p : packages) {
Log.v(TAG, " + " + p.packageName);
}
PackageInfo[] result = new PackageInfo[packages.size()];
return packages.toArray(result);
}
public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor output)
throws android.os.RemoteException {
// we only support one hardcoded restore set
if (token != 0) return -1;
// the data for a given package is at a known location
File packageDir = new File(mDataDir, packageInfo.packageName);
File imageFile = new File(packageDir, DATA_FILE_NAME);
// restore is relatively easy: we already maintain the full data set in
// the canonical form understandable to the BackupAgent
return copyFileToFD(imageFile, output);
}
private int copyFileToFD(File source, ParcelFileDescriptor dest) {
try {
FileInputStream in = new FileInputStream(source);
FileOutputStream out = new FileOutputStream(dest.getFileDescriptor());
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
// something went wrong; claim failure
return -1;
}
return 0;
}
}

View File

@@ -47,7 +47,7 @@ import android.backup.IRestoreSession;
import android.backup.BackupManager;
import android.backup.RestoreSet;
import com.android.internal.backup.AdbTransport;
import com.android.internal.backup.LocalTransport;
import com.android.internal.backup.GoogleTransport;
import com.android.internal.backup.IBackupTransport;
@@ -72,6 +72,7 @@ class BackupManagerService extends IBackupManager.Stub {
private static final int MSG_RUN_BACKUP = 1;
private static final int MSG_RUN_FULL_BACKUP = 2;
private static final int MSG_RUN_RESTORE = 3;
// Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -131,7 +132,9 @@ class BackupManagerService extends IBackupManager.Stub {
mStateDir = new File(Environment.getDataDirectory(), "backup");
mStateDir.mkdirs();
mDataDir = Environment.getDownloadCacheDirectory();
mTransportId = BackupManager.TRANSPORT_GOOGLE;
//!!! TODO: default to cloud transport, not local
mTransportId = BackupManager.TRANSPORT_LOCAL;
// Build our mapping of uid to backup client services
synchronized (mBackupParticipants) {
@@ -212,6 +215,14 @@ class BackupManagerService extends IBackupManager.Stub {
case MSG_RUN_FULL_BACKUP:
break;
case MSG_RUN_RESTORE:
{
int token = msg.arg1;
IBackupTransport transport = (IBackupTransport)msg.obj;
(new PerformRestoreThread(transport, token)).run();
break;
}
}
}
}
@@ -331,9 +342,9 @@ class BackupManagerService extends IBackupManager.Stub {
private IBackupTransport createTransport(int transportID) {
IBackupTransport transport = null;
switch (transportID) {
case BackupManager.TRANSPORT_ADB:
if (DEBUG) Log.v(TAG, "Initializing adb transport");
transport = new AdbTransport();
case BackupManager.TRANSPORT_LOCAL:
if (DEBUG) Log.v(TAG, "Initializing local transport");
transport = new LocalTransport(mContext);
break;
case BackupManager.TRANSPORT_GOOGLE:
@@ -585,10 +596,12 @@ class BackupManagerService extends IBackupManager.Stub {
class PerformRestoreThread extends Thread {
private IBackupTransport mTransport;
private int mToken;
private RestoreSet mImage;
PerformRestoreThread(IBackupTransport transport) {
PerformRestoreThread(IBackupTransport transport, int restoreSetToken) {
mTransport = transport;
mToken = restoreSetToken;
}
@Override
@@ -622,7 +635,7 @@ class BackupManagerService extends IBackupManager.Stub {
try {
RestoreSet[] images = mTransport.getAvailableRestoreSets();
if (images.length > 0) {
// !!! for now we always take the first set
// !!! TODO: pick out the set for this token
mImage = images[0];
// build the set of apps we will attempt to restore
@@ -870,6 +883,9 @@ class BackupManagerService extends IBackupManager.Stub {
// --- Binder interface ---
public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException {
mContext.enforceCallingPermission("android.permission.BACKUP",
"getAvailableRestoreSets");
synchronized(this) {
if (mRestoreSets == null) {
mRestoreSets = mRestoreTransport.getAvailableRestoreSets();
@@ -879,10 +895,26 @@ class BackupManagerService extends IBackupManager.Stub {
}
public int performRestore(int token) throws android.os.RemoteException {
mContext.enforceCallingPermission("android.permission.BACKUP", "performRestore");
if (mRestoreSets != null) {
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE,
mRestoreTransport);
msg.arg1 = token;
mBackupHandler.sendMessage(msg);
return 0;
}
}
}
return -1;
}
public void endRestoreSession() throws android.os.RemoteException {
mContext.enforceCallingPermission("android.permission.BACKUP",
"endRestoreSession");
mRestoreTransport.endSession();
mRestoreTransport = null;
}