summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java65
-rw-r--r--core/java/android/backup/BackupManager.java4
-rw-r--r--core/java/android/backup/IBackupManager.aidl21
-rw-r--r--services/java/com/android/server/BackupManagerService.java118
4 files changed, 154 insertions, 54 deletions
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index c299bff..c3ddd20 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -124,11 +124,14 @@ public final class Bmgr {
private void doTransport() {
try {
- int which = Integer.parseInt(nextArg());
- int old = mBmgr.selectBackupTransport(which);
- System.out.println("Selected transport " + which + " (formerly " + old + ")");
- } catch (NumberFormatException e) {
- showUsage();
+ String which = nextArg();
+ String old = mBmgr.selectBackupTransport(which);
+ if (old == null) {
+ System.out.println("Unknown transport '" + which
+ + "' specified; no changes made.");
+ } else {
+ System.out.println("Selected transport " + which + " (formerly " + old + ")");
+ }
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -144,7 +147,7 @@ public final class Bmgr {
// The rest of the 'list' options work with a restore session on the current transport
try {
- int curTransport = mBmgr.getCurrentTransport();
+ String curTransport = mBmgr.getCurrentTransport();
mRestore = mBmgr.beginRestoreSession(curTransport);
if (mRestore == null) {
System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -153,6 +156,8 @@ public final class Bmgr {
if ("sets".equals(arg)) {
doListRestoreSets();
+ } else if ("transports".equals(arg)) {
+ doListTransports();
}
mRestore.endRestoreSession();
@@ -163,6 +168,22 @@ public final class Bmgr {
}
private void doListTransports() {
+ try {
+ String current = mBmgr.getCurrentTransport();
+ String[] transports = mBmgr.listAllTransports();
+ if (transports == null || transports.length == 0) {
+ System.out.println("No transports available.");
+ return;
+ }
+
+ for (String t : transports) {
+ String pad = (t.equals(current)) ? " * " : " ";
+ System.out.println(pad + t);
+ }
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
}
private void doListRestoreSets() {
@@ -217,7 +238,7 @@ public final class Bmgr {
try {
boolean didRestore = false;
- int curTransport = mBmgr.getCurrentTransport();
+ String curTransport = mBmgr.getCurrentTransport();
mRestore = mBmgr.beginRestoreSession(curTransport);
if (mRestore == null) {
System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -269,11 +290,33 @@ public final class Bmgr {
private static void showUsage() {
System.err.println("usage: bmgr [backup|restore|list|transport|run]");
- System.err.println(" bmgr backup [-f] package");
+ System.err.println(" bmgr backup PACKAGE");
+ System.err.println(" bmgr list transports");
System.err.println(" bmgr list sets");
- System.err.println(" #bmgr list transports");
- System.err.println(" #bmgr transport which#");
- System.err.println(" bmgr restore token#");
+ System.err.println(" bmgr transport WHICH");
+ System.err.println(" bmgr restore TOKEN");
System.err.println(" bmgr run");
+ System.err.println("");
+ System.err.println("The 'backup' command schedules a backup pass for the named package.");
+ System.err.println("Note that the backup pass will effectively be a no-op if the package");
+ System.err.println("does not actually have changed data to store.");
+ System.err.println("");
+ System.err.println("The 'list transports' command reports the names of the backup transports");
+ System.err.println("currently available on the device. These names can be passed as arguments");
+ System.err.println("to the 'transport' command. The currently selected transport is indicated");
+ System.err.println("with a '*' character.");
+ System.err.println("");
+ System.err.println("The 'list sets' command reports the token and name of each restore set");
+ System.err.println("available to the device via the current transport.");
+ System.err.println("");
+ System.err.println("The 'transport' command designates the named transport as the currently");
+ System.err.println("active one. This setting is persistent across reboots.");
+ System.err.println("");
+ System.err.println("The 'restore' command initiates a restore operation, using the restore set");
+ System.err.println("from the current transport whose token matches the argument.");
+ System.err.println("");
+ System.err.println("The 'run' command causes any scheduled backup operation to be initiated");
+ System.err.println("immediately, without the usual waiting period for batching together");
+ System.err.println("data changes.");
}
}
diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java
index 79e2c03..5b4ac0d 100644
--- a/core/java/android/backup/BackupManager.java
+++ b/core/java/android/backup/BackupManager.java
@@ -83,11 +83,11 @@ public class BackupManager {
*
* {@hide}
*/
- public IRestoreSession beginRestoreSession(int transportID) {
+ public IRestoreSession beginRestoreSession(String transport) {
IRestoreSession binder = null;
if (mService != null) {
try {
- binder = mService.beginRestoreSession(transportID);
+ binder = mService.beginRestoreSession(transport);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl
index d6283d0..39e160b 100644
--- a/core/java/android/backup/IBackupManager.aidl
+++ b/core/java/android/backup/IBackupManager.aidl
@@ -63,23 +63,32 @@ interface IBackupManager {
* Identify the currently selected transport. Callers must hold the
* android.permission.BACKUP permission to use this method.
*/
- int getCurrentTransport();
+ String getCurrentTransport();
/**
- * Specify a default backup transport. Callers must hold the
+ * Request a list of all available backup transports' names. Callers must
+ * hold the android.permission.BACKUP permission to use this method.
+ */
+ String[] listAllTransports();
+
+ /**
+ * Specify the current backup transport. Callers must hold the
* android.permission.BACKUP permission to use this method.
*
- * @param transportID The ID of the transport to select. This should be one
+ * @param transport The name of the transport to select. This should be one
* of {@link BackupManager.TRANSPORT_GOOGLE} or {@link BackupManager.TRANSPORT_ADB}.
- * @return The ID of the previously selected transport.
+ * @return The name of the previously selected transport. If the given transport
+ * name is not one of the currently available transports, no change is made to
+ * the current transport setting and the method returns null.
*/
- int selectBackupTransport(int transportID);
+ String selectBackupTransport(String transport);
/**
* Begin a restore session with the given transport (which may differ from the
* currently-active backup transport).
*
+ * @param transport The name of the transport to use for the restore operation.
* @return An interface to the restore session, or null on error.
*/
- IRestoreSession beginRestoreSession(int transportID);
+ IRestoreSession beginRestoreSession(String transportID);
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index c0f0d74..2b9ac4d 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -42,13 +42,13 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.util.Log;
import android.util.SparseArray;
import android.backup.IBackupManager;
import android.backup.IRestoreObserver;
import android.backup.IRestoreSession;
-import android.backup.BackupManager;
import android.backup.RestoreSet;
import com.android.internal.backup.LocalTransport;
@@ -68,6 +68,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
@@ -79,7 +80,6 @@ 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;
- private static final String RESTORE_OBSERVER_KEY = "_resOb";
// Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -127,8 +127,11 @@ class BackupManagerService extends IBackupManager.Stub {
private final Object mClearDataLock = new Object();
private volatile boolean mClearingData;
- // Current active transport & restore session
- private int mTransportId;
+ // Transport bookkeeping
+ static private final String BACKUP_TRANSPORT_PROPERTY = "persist.service.bkup.trans";
+ private final HashMap<String,IBackupTransport> mTransports
+ = new HashMap<String,IBackupTransport>();
+ private String mCurrentTransport;
private IBackupTransport mLocalTransport, mGoogleTransport;
private RestoreSession mActiveRestoreSession;
@@ -175,11 +178,19 @@ class BackupManagerService extends IBackupManager.Stub {
// Set up our transport options and initialize the default transport
// TODO: Have transports register themselves somehow?
// TODO: Don't create transports that we don't need to?
- mTransportId = BackupManager.TRANSPORT_GOOGLE;
mLocalTransport = new LocalTransport(context); // This is actually pretty cheap
- mGoogleTransport = null;
+ ComponentName localName = new ComponentName(context, LocalTransport.class);
+ registerTransport(localName.flattenToShortString(), mLocalTransport);
- // Attach to the Google backup transport.
+ mGoogleTransport = null;
+ // !!! TODO: set up the default transport name "the right way"
+ mCurrentTransport = SystemProperties.get(BACKUP_TRANSPORT_PROPERTY,
+ "com.google.android.backup/.BackupTransportService");
+ if (DEBUG) Log.v(TAG, "Starting with transport " + mCurrentTransport);
+
+ // Attach to the Google backup transport. When this comes up, it will set
+ // itself as the current transport because we explicitly reset mCurrentTransport
+ // to null.
Intent intent = new Intent().setComponent(new ComponentName(
"com.google.android.backup",
"com.google.android.backup.BackupTransportService"));
@@ -238,6 +249,13 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ // Add a transport to our set of available backends
+ private void registerTransport(String name, IBackupTransport transport) {
+ synchronized (mTransports) {
+ mTransports.put(name, transport);
+ }
+ }
+
// ----- Track installation/removal of packages -----
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
@@ -283,11 +301,13 @@ class BackupManagerService extends IBackupManager.Stub {
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.v(TAG, "Connected to Google transport");
mGoogleTransport = IBackupTransport.Stub.asInterface(service);
+ registerTransport(name.flattenToShortString(), mGoogleTransport);
}
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.v(TAG, "Disconnected from Google transport");
mGoogleTransport = null;
+ registerTransport(name.flattenToShortString(), null);
}
};
@@ -299,7 +319,7 @@ class BackupManagerService extends IBackupManager.Stub {
switch (msg.what) {
case MSG_RUN_BACKUP:
{
- IBackupTransport transport = getTransport(mTransportId);
+ IBackupTransport transport = getTransport(mCurrentTransport);
if (transport == null) {
Log.v(TAG, "Backup requested but no transport available");
break;
@@ -474,19 +494,13 @@ class BackupManagerService extends IBackupManager.Stub {
}
// Return the given transport
- private IBackupTransport getTransport(int transportID) {
- switch (transportID) {
- case BackupManager.TRANSPORT_LOCAL:
- Log.v(TAG, "Supplying local transport");
- return mLocalTransport;
-
- case BackupManager.TRANSPORT_GOOGLE:
- Log.v(TAG, "Supplying Google transport");
- return mGoogleTransport;
-
- default:
- Log.e(TAG, "Asked for unknown transport " + transportID);
- return null;
+ private IBackupTransport getTransport(String transportName) {
+ synchronized (mTransports) {
+ IBackupTransport transport = mTransports.get(transportName);
+ if (transport == null) {
+ Log.w(TAG, "Requested unavailable transport: " + transportName);
+ }
+ return transport;
}
}
@@ -1111,21 +1125,51 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- // Report the currently active transport
- public int getCurrentTransport() {
+ // Report the name of the currently active transport
+ public String getCurrentTransport() {
+ mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
+ Log.v(TAG, "getCurrentTransport() returning " + mCurrentTransport);
+ return mCurrentTransport;
+ }
+
+ // Report all known, available backup transports
+ public String[] listAllTransports() {
mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
- Log.v(TAG, "getCurrentTransport() returning " + mTransportId);
- return mTransportId;
+
+ String[] list = null;
+ ArrayList<String> known = new ArrayList<String>();
+ for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
+ if (entry.getValue() != null) {
+ known.add(entry.getKey());
+ }
+ }
+
+ if (known.size() > 0) {
+ list = new String[known.size()];
+ known.toArray(list);
+ }
+ return list;
}
- // Select which transport to use for the next backup operation
- public int selectBackupTransport(int transportId) {
+ // Select which transport to use for the next backup operation. If the given
+ // name is not one of the available transports, no action is taken and the method
+ // returns null.
+ public String selectBackupTransport(String transport) {
mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
- int prevTransport = mTransportId;
- mTransportId = transportId;
- Log.v(TAG, "selectBackupTransport() set " + mTransportId + " returning " + prevTransport);
- return prevTransport;
+ synchronized (mTransports) {
+ String prevTransport = null;
+ if (mTransports.get(transport) != null) {
+ prevTransport = mCurrentTransport;
+ mCurrentTransport = transport;
+ SystemProperties.set(BACKUP_TRANSPORT_PROPERTY, transport);
+ Log.v(TAG, "selectBackupTransport() set " + mCurrentTransport
+ + " returning " + prevTransport);
+ } else {
+ Log.w(TAG, "Attempt to select unavailable transport " + transport);
+ }
+ return prevTransport;
+ }
}
// Callback: a requested backup agent has been instantiated. This should only
@@ -1163,7 +1207,7 @@ class BackupManagerService extends IBackupManager.Stub {
}
// Hand off a restore session
- public IRestoreSession beginRestoreSession(int transportID) {
+ public IRestoreSession beginRestoreSession(String transport) {
mContext.enforceCallingPermission("android.permission.BACKUP", "beginRestoreSession");
synchronized(this) {
@@ -1171,7 +1215,7 @@ class BackupManagerService extends IBackupManager.Stub {
Log.d(TAG, "Restore session requested but one already active");
return null;
}
- mActiveRestoreSession = new RestoreSession(transportID);
+ mActiveRestoreSession = new RestoreSession(transport);
}
return mActiveRestoreSession;
}
@@ -1184,8 +1228,8 @@ class BackupManagerService extends IBackupManager.Stub {
private IBackupTransport mRestoreTransport = null;
RestoreSet[] mRestoreSets = null;
- RestoreSession(int transportID) {
- mRestoreTransport = getTransport(transportID);
+ RestoreSession(String transport) {
+ mRestoreTransport = getTransport(transport);
}
// --- Binder interface ---
@@ -1246,6 +1290,10 @@ class BackupManagerService extends IBackupManager.Stub {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mQueueLock) {
+ pw.println("Available transports:");
+ for (String t : listAllTransports()) {
+ pw.println(" " + t);
+ }
int N = mBackupParticipants.size();
pw.println("Participants:");
for (int i=0; i<N; i++) {