diff options
-rw-r--r-- | cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java | 65 | ||||
-rw-r--r-- | core/java/android/backup/BackupManager.java | 4 | ||||
-rw-r--r-- | core/java/android/backup/IBackupManager.aidl | 21 | ||||
-rw-r--r-- | services/java/com/android/server/BackupManagerService.java | 118 |
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++) { |