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

Commit 09b87a7d authored by Joe Onorato's avatar Joe Onorato Committed by The Android Open Source Project
Browse files

am 8ad02811: With this, the BackupService onBackup method is called.

Merge commit '8ad02811'

* commit '8ad02811':
  With this, the BackupService onBackup method is called.
parents 937809cc 8ad02811
Loading
Loading
Loading
Loading
+150 −132
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.lang.String;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

@@ -74,62 +76,158 @@ class BackupManagerService extends IBackupManager.Stub {
            fullBackup = isFull;
        }
    }
    private HashSet<BackupRequest> mPendingBackups = new HashSet<BackupRequest>();
    // Backups that we haven't started yet.
    private HashMap<ComponentName,BackupRequest> mPendingBackups = new HashMap();
    // Backups that we have started.  These are separate to prevent starvation
    // if an app keeps re-enqueuing itself.
    private ArrayList<BackupRequest> mBackupQueue;
    private final Object mQueueLock = new Object();

    private File mStateDir;
    private File mDataDir;
    
    // ----- Handler that runs the actual backup process asynchronously -----
    public BackupManagerService(Context context) {
        mContext = context;
        mPackageManager = context.getPackageManager();

    private class BackupHandler extends Handler implements ServiceConnection {
        private volatile Object mBindSignaller = new Object();
        private volatile boolean mBinding = false;
        private IBackupService mTargetService = null;
        // Set up our bookkeeping
        mStateDir = new File(Environment.getDataDirectory(), "backup");
        mStateDir.mkdirs();
        mDataDir = Environment.getDownloadCacheDirectory();
        
        // Build our mapping of uid to backup client services
        synchronized (mBackupParticipants) {
            addPackageParticipantsLocked(null);
        }

        // Register for broadcasts about package install, etc., so we can
        // update the provider list.
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addDataScheme("package");
        mContext.registerReceiver(mBroadcastReceiver, filter);
    }

    // ----- Track installation/removal of packages -----
    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            if (DEBUG) Log.d(TAG, "Received broadcast " + intent);

            Uri uri = intent.getData();
            if (uri == null) {
                return;
            }
            String pkgName = uri.getSchemeSpecificPart();
            if (pkgName == null) {
                return;
            }

            String action = intent.getAction();
            if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                synchronized (mBackupParticipants) {
                    Bundle extras = intent.getExtras();
                    if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
                        // The package was just upgraded
                        updatePackageParticipantsLocked(pkgName);
                    } else {
                        // The package was just added
                        addPackageParticipantsLocked(pkgName);
                    }
                }
            }
            else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                Bundle extras = intent.getExtras();
                if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
                    // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
                } else {
                    synchronized (mBackupParticipants) {
                        removePackageParticipantsLocked(pkgName);
                    }
                }
            }
        }
    };

    // ----- Run the actual backup process asynchronously -----

    private class BackupHandler extends Handler implements ServiceConnection {
        public void handleMessage(Message msg) {

            switch (msg.what) {
            case MSG_RUN_BACKUP:
            {
                // snapshot the pending-backup set and work on that
                HashSet<BackupRequest> queue;
                synchronized (mQueueLock) {
                    queue = mPendingBackups;
                    mPendingBackups = new HashSet<BackupRequest>();
                    mBackupQueue = new ArrayList();
                    for (BackupRequest b: mPendingBackups.values()) {
                        mBackupQueue.add(b);
                    }
                    mPendingBackups = new HashMap<ComponentName,BackupRequest>();
                    // !!! TODO: start a new backup-queue journal file too
                    // WARNING: If we crash after this line, anything in mPendingBackups will
                    // be lost.  FIX THIS.
                }
                startOneService();
                break;
            }
        }
        
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected name=" + name + " service=" + service);
            IBackupService bs = IBackupService.Stub.asInterface(service);
            processOneBackup(name, bs);
        }

        public void onServiceDisconnected(ComponentName name) {
            // TODO: handle backup being interrupted
        }
    }

                // Walk the set of pending backups, setting up the relevant files and
                // invoking the backup service in each participant
                Intent backupIntent = new Intent(BackupService.SERVICE_ACTION);
                for (BackupRequest request : queue) {
                    mBinding = true;
                    mTargetService = null;
    void startOneService() {
        // Loop until we find someone to start or the queue empties out.
        Intent intent = new Intent(BackupService.SERVICE_ACTION);
        while (true) {
            BackupRequest request;
            synchronized (mQueueLock) {
                int queueSize = mBackupQueue.size();
                if (queueSize == 0) {
                    mBackupQueue = null;
                    // TODO: Anything else to do here?
                    return;
                }
                request = mBackupQueue.get(0);
                // Take it off the queue when we're done.
            }
            
                    backupIntent.setClassName(request.service.packageName, request.service.name);
                    Log.d(TAG, "binding to " + backupIntent);
                    if (mContext.bindService(backupIntent, this, 0)) {
                        synchronized (mBindSignaller) {
                            while (mTargetService == null && mBinding == true) {
            intent.setClassName(request.service.packageName, request.service.name);
            Log.d(TAG, "binding to " + intent);
            try {
                                    mBindSignaller.wait();
                                } catch (InterruptedException e) {
                if (mContext.bindService(intent, mBackupHandler, Context.BIND_AUTO_CREATE)) {
                    Log.d(TAG, "awaiting service object for " + intent);
                    // success
                    return;
                }
            } catch (SecurityException ex) {
                // Try for the next one.
                Log.d(TAG, "error in bind", ex);
            }
        }
    }
                        if (mTargetService != null) {

    void processOneBackup(ComponentName name, IBackupService bs) {
        try {
                                Log.d(TAG, "invoking doBackup() on " + backupIntent);
            Log.d(TAG, "processOneBackup doBackup() on " + name);

            BackupRequest request;
            synchronized (mQueueLock) {
                request = mBackupQueue.get(0);
            }

            // !!! TODO right now these naming schemes limit applications to
            // one backup service per package
                                File savedStateName = new File(mStateDir,
                                        request.service.packageName);
                                File backupDataName = new File(mDataDir,
                                        request.service.packageName + ".data");
                                File newStateName = new File(mStateDir,
                                        request.service.packageName + ".new");
            File savedStateName = new File(mStateDir, request.service.packageName);
            File backupDataName = new File(mDataDir, request.service.packageName + ".data");
            File newStateName = new File(mStateDir, request.service.packageName + ".new");
            
            // In a full backup, we pass a null ParcelFileDescriptor as
            // the saved-state "file"
@@ -152,9 +250,12 @@ class BackupManagerService extends IBackupManager.Stub {

            // Run the target's backup pass
            try {
                                    mTargetService.doBackup(savedState, backupData, newState);
                // TODO: Make this oneway
                bs.doBackup(savedState, backupData, newState);
            } finally {
                if (savedState != null) {
                    savedState.close();
                }
                backupData.close();
                newState.close();
            }
@@ -170,103 +271,17 @@ class BackupManagerService extends IBackupManager.Stub {
            Log.d(TAG, "File not found on backup: ");
            fnf.printStackTrace();
        } catch (RemoteException e) {
                                Log.d(TAG, "Remote target " + backupIntent
                                        + " threw during backup:");
            Log.d(TAG, "Remote target " + name + " threw during backup:");
            e.printStackTrace();
        } catch (Exception e) {
            Log.w(TAG, "Final exception guard in backup: ");
            e.printStackTrace();
        }
                            mContext.unbindService(this);
                        }
                    } else {
                        Log.d(TAG, "Unable to bind to " + backupIntent);
                    }
                }
            }
            break;
            }
        }
        
        public void onServiceConnected(ComponentName name, IBinder service) {
            synchronized (mBindSignaller) {
                mTargetService = IBackupService.Stub.asInterface(service);
                mBinding = false;
                mBindSignaller.notifyAll();
            }
        }

        public void onServiceDisconnected(ComponentName name) {
            synchronized (mBindSignaller) {
                mTargetService = null;
                mBinding = false;
                mBindSignaller.notifyAll();
            }
        }
    }
    
    public BackupManagerService(Context context) {
        mContext = context;
        mPackageManager = context.getPackageManager();

        // Set up our bookkeeping
        mStateDir = new File(Environment.getDataDirectory(), "backup");
        mStateDir.mkdirs();
        mDataDir = Environment.getDownloadCacheDirectory();
        
        // Build our mapping of uid to backup client services
        synchronized (mBackupParticipants) {
            addPackageParticipantsLocked(null);
        }

        // Register for broadcasts about package install, etc., so we can
        // update the provider list.
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addDataScheme("package");
        mContext.registerReceiver(mBroadcastReceiver, filter);
    }

    // ----- Track installation/removal of packages -----
    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            if (DEBUG) Log.d(TAG, "Received broadcast " + intent);

            Uri uri = intent.getData();
            if (uri == null) {
                return;
            }
            String pkgName = uri.getSchemeSpecificPart();
            if (pkgName == null) {
                return;
            }

            String action = intent.getAction();
            if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                synchronized (mBackupParticipants) {
                    Bundle extras = intent.getExtras();
                    if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
                        // The package was just upgraded
                        updatePackageParticipantsLocked(pkgName);
                    } else {
                        // The package was just added
                        addPackageParticipantsLocked(pkgName);
                    }
                }
            }
            else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                Bundle extras = intent.getExtras();
                if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
                    // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
                } else {
                    synchronized (mBackupParticipants) {
                        removePackageParticipantsLocked(pkgName);
                    }
                }
        synchronized (mQueueLock) {
            mBackupQueue.remove(0);
        }
        mContext.unbindService(mBackupHandler);
    }
    };

    // Add the backup services in the given package to our set of known backup participants.
    // If 'packageName' is null, adds all backup services in the system.
@@ -305,7 +320,8 @@ class BackupManagerService extends IBackupManager.Stub {
        removePackageParticipantsLockedInner(packageName, services);
    }

    private void removePackageParticipantsLockedInner(String packageName, List<ResolveInfo> services) {
    private void removePackageParticipantsLockedInner(String packageName,
            List<ResolveInfo> services) {
        for (ResolveInfo ri : services) {
            if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) {
                int uid = ri.serviceInfo.applicationInfo.uid;
@@ -353,12 +369,13 @@ class BackupManagerService extends IBackupManager.Stub {
                    // validate the caller-supplied package name against the known set of
                    // packages associated with this uid
                    if (service.packageName.equals(packageName)) {
                        // add the caller to the set of pending backups
                        if (mPendingBackups.add(new BackupRequest(service, false))) {
                        // Add the caller to the set of pending backups.  If there is
                        // one already there, then overwrite it, but no harm done.
                        mPendingBackups.put(new ComponentName(service.packageName, service.name),
                                new BackupRequest(service, true));
                        // !!! TODO: write to the pending-backup journal file in case of crash
                    }
                }
                }

                Log.d(TAG, "Scheduling backup for " + mPendingBackups.size() + " participants");
                // Schedule a backup pass in a few minutes.  As backup-eligible data
@@ -381,7 +398,8 @@ class BackupManagerService extends IBackupManager.Stub {
                HashSet<ServiceInfo> servicesAtUid = mBackupParticipants.get(uid);
                for (ServiceInfo service: servicesAtUid) {
                    if (service.packageName.equals(packageName)) {
                        mPendingBackups.add(new BackupRequest(service, true));
                        mPendingBackups.put(new ComponentName(service.packageName, service.name),
                                new BackupRequest(service, true));
                    }
                }
            }
+1 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

package com.example.android.apis.app;
package com.android.backuptest;

import android.backup.BackupService;
import android.os.ParcelFileDescriptor;