Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 75a99709 authored by Christopher Tate's avatar Christopher Tate
Browse files

Restore from a previous full backup's tarfile

Usage:  adb restore [tarfilename]

Restores app data [and installs the apps if necessary from the backup
file] captured in a previous invocation of 'adb backup'.  The user
must explicitly acknowledge the action on-device before it is allowed
to proceed; this prevents any "invisible" pushes of content from the
host to the device.

Known issues:

* The settings databases and wallpaper are saved/restored, but lots
  of other system state is not yet captured in the full backup.  This
  means that for practical purposes this is usable for 3rd party
  apps at present but not for full-system cloning/imaging.

Change-Id: I0c748b645845e7c9178e30bf142857861a64efd3
parent 2978cef0
Loading
Loading
Loading
Loading
+15 −9
Original line number Diff line number Diff line
@@ -34,11 +34,12 @@ public final class Backup {
    IBackupManager mBackupManager;

    public static void main(String[] args) {
        Log.d(TAG, "Beginning: " + args[0]);
        mArgs = args;
        try {
            new Backup().run();
        } catch (Exception e) {
            Log.e(TAG, "Error running backup", e);
            Log.e(TAG, "Error running backup/restore", e);
        }
        Log.d(TAG, "Finished.");
    }
@@ -46,7 +47,7 @@ public final class Backup {
    public void run() {
        mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
        if (mBackupManager == null) {
            System.err.println("ERROR: could not contact backup manager");
            Log.e(TAG, "Can't obtain Backup Manager binder");
            return;
        }

@@ -56,7 +57,7 @@ public final class Backup {
        } else if (arg.equals("restore")) {
            doFullRestore();
        } else {
            System.err.println("ERROR: invalid operation '" + arg + "'");
            Log.e(TAG, "Invalid operation '" + arg + "'");
        }
    }

@@ -80,7 +81,6 @@ public final class Backup {
                } else if ("-all".equals(arg)) {
                    doEverything = true;
                } else {
                    System.err.println("WARNING: unknown backup flag " + arg);
                    Log.w(TAG, "Unknown backup flag " + arg);
                    continue;
                }
@@ -91,13 +91,10 @@ public final class Backup {
        }

        if (doEverything && packages.size() > 0) {
            System.err.println("WARNING: -all used with explicit backup package set");
            Log.w(TAG, "-all passed for backup along with specific package names");
        }

        if (!doEverything && !saveShared && packages.size() == 0) {
            System.err.println(
                    "ERROR: no packages supplied for backup and neither -shared nor -all given");
            Log.e(TAG, "no backup packages supplied and neither -shared nor -all given");
            return;
        }
@@ -108,13 +105,22 @@ public final class Backup {
            mBackupManager.fullBackup(fd, saveApks, saveShared, doEverything,
                    packages.toArray(packArray));
        } catch (IOException e) {
            System.err.println("ERROR: cannot dup System.out");
            Log.e(TAG, "Can't dup out");
        } catch (RemoteException e) {
            System.err.println("ERROR: unable to invoke backup manager service");
            Log.e(TAG, "Unable to invoke backup manager for backup");
        }
    }

    private void doFullRestore() {
        // No arguments to restore
        try {
            ParcelFileDescriptor fd = ParcelFileDescriptor.dup(FileDescriptor.in);
            mBackupManager.fullRestore(fd);
        } catch (IOException e) {
            Log.e(TAG, "Can't dup System.in");
        } catch (RemoteException e) {
            Log.e(TAG, "Unable to invoke backup manager for restore");
        }
    }

    private String nextArg() {
+14 −8
Original line number Diff line number Diff line
@@ -1980,7 +1980,8 @@ public final class ActivityThread {
        BackupAgent agent = null;
        String classname = data.appInfo.backupAgentName;

        if (data.backupMode == IApplicationThread.BACKUP_MODE_FULL) {
        if (data.backupMode == IApplicationThread.BACKUP_MODE_FULL
                || data.backupMode == IApplicationThread.BACKUP_MODE_RESTORE_FULL) {
            classname = "android.app.backup.FullBackupAgent";
            if ((data.appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                // system packages can supply their own full-backup agent
@@ -2011,7 +2012,8 @@ public final class ActivityThread {
                // If this is during restore, fail silently; otherwise go
                // ahead and let the user see the crash.
                Slog.e(TAG, "Agent threw during creation: " + e);
                if (data.backupMode != IApplicationThread.BACKUP_MODE_RESTORE) {
                if (data.backupMode != IApplicationThread.BACKUP_MODE_RESTORE
                        && data.backupMode != IApplicationThread.BACKUP_MODE_RESTORE_FULL) {
                    throw e;
                }
                // falling through with 'binder' still null
@@ -3658,6 +3660,9 @@ public final class ActivityThread {
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;

        // don't bring up providers in restricted mode; they may depend on the
        // app's custom Application class
        if (!data.restrictedBackupMode){ 
            List<ProviderInfo> providers = data.providers;
            if (providers != null) {
                installContentProviders(app, providers);
@@ -3665,6 +3670,7 @@ public final class ActivityThread {
                // ensure that the JIT is enabled "at some point".
                mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
            }
        }

        try {
            mInstrumentation.callApplicationOnCreate(app);
+1 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ public interface IApplicationThread extends IInterface {
    static final int BACKUP_MODE_INCREMENTAL = 0;
    static final int BACKUP_MODE_FULL = 1;
    static final int BACKUP_MODE_RESTORE = 2;
    static final int BACKUP_MODE_RESTORE_FULL = 3;
    void scheduleCreateBackupAgent(ApplicationInfo app, CompatibilityInfo compatInfo,
            int backupMode) throws RemoteException;
    void scheduleDestroyBackupAgent(ApplicationInfo app, CompatibilityInfo compatInfo)
+19 −0
Original line number Diff line number Diff line
@@ -79,4 +79,23 @@ oneway interface IBackupAgent {
     */
    void doRestore(in ParcelFileDescriptor data, int appVersionCode,
            in ParcelFileDescriptor newState, int token, IBackupManager callbackBinder);

    /**
     * Restore a single "file" to the application.  The file was typically obtained from
     * a full-backup dataset.  The agent reads 'size' bytes of file content
     * from the provided file descriptor.
     *
     * @param data Read-only pipe delivering the file content itself.
     *
     * @param size Size of the file being restored.
     * @param type Type of file system entity, e.g. FullBackup.TYPE_DIRECTORY.
     * @param domain Name of the file's semantic domain to which the 'path' argument is a
     *        relative path.  e.g. FullBackup.DATABASE_TREE_TOKEN.
     * @param path Relative path of the file within its semantic domain.
     * @param mode Access mode of the file system entity, e.g. 0660.
     * @param mtime Last modification time of the file system entity.
     */
    void doRestoreFile(in ParcelFileDescriptor data, long size,
            int type, String domain, String path, long mode, long mtime,
            int token, IBackupManager callbackBinder);
}
+31 −1
Original line number Diff line number Diff line
@@ -178,11 +178,19 @@ public abstract class BackupAgent extends ContextWrapper {
            ParcelFileDescriptor newState)
            throws IOException;

    /**
     * @hide
     */
    public void onRestoreFile(ParcelFileDescriptor data, long size,
            int type, String domain, String path, long mode, long mtime)
            throws IOException {
        // empty stub implementation
    }

    /**
     * Package-private, used only for dispatching an extra step during full backup
     */
    void onSaveApk(BackupDataOutput data) {
        if (DEBUG) Log.v(TAG, "--- base onSaveApk() ---");
    }

    // ----- Core implementation -----
@@ -203,6 +211,7 @@ public abstract class BackupAgent extends ContextWrapper {
    private class BackupServiceBinder extends IBackupAgent.Stub {
        private static final String TAG = "BackupServiceBinder";

        @Override
        public void doBackup(ParcelFileDescriptor oldState,
                ParcelFileDescriptor data,
                ParcelFileDescriptor newState,
@@ -236,6 +245,7 @@ public abstract class BackupAgent extends ContextWrapper {
            }
        }

        @Override
        public void doRestore(ParcelFileDescriptor data, int appVersionCode,
                ParcelFileDescriptor newState,
                int token, IBackupManager callbackBinder) throws RemoteException {
@@ -261,5 +271,25 @@ public abstract class BackupAgent extends ContextWrapper {
                }
            }
        }

        @Override
        public void doRestoreFile(ParcelFileDescriptor data, long size,
                int type, String domain, String path, long mode, long mtime,
                int token, IBackupManager callbackBinder) throws RemoteException {
            long ident = Binder.clearCallingIdentity();
            try {
Log.d(TAG, "doRestoreFile() => onRestoreFile()");
                BackupAgent.this.onRestoreFile(data, size, type, domain, path, mode, mtime);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                Binder.restoreCallingIdentity(ident);
                try {
                    callbackBinder.opComplete(token);
                } catch (RemoteException e) {
                    // we'll time out anyway, so we're safe
                }
            }
        }
    }
}
Loading