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

Commit 9bbc21a7 authored by Christopher Tate's avatar Christopher Tate
Browse files

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

parent b6391d63
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;

    /**
+0 −55
Original line number Diff line number Diff line
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;
    }
}
+140 −0
Original line number Diff line number Diff line
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;
    }
}
+39 −7
Original line number Diff line number Diff line
@@ -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;
        }