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

Commit 37dbf099 authored by Android (Google) Code Review's avatar Android (Google) Code Review Committed by The Android Open Source Project
Browse files

am 9a6f2503: Merge change 1089 into donut

Merge commit '9a6f2503'

* commit '9a6f2503':
  Add a Backup Manager interface to request a full backup
parents 54f2422b 9a6f2503
Loading
Loading
Loading
Loading
+7 −1
Original line number Original line Diff line number Diff line
@@ -29,7 +29,13 @@ package android.backup;
interface IBackupManager {
interface IBackupManager {
    /**
    /**
     * Tell the system service that the caller has made changes to its
     * Tell the system service that the caller has made changes to its
     * data, and therefore needs to undergo a backup pass.
     * data, and therefore needs to undergo an incremental backup pass.
     */
     */
    oneway void dataChanged(String packageName);
    oneway void dataChanged(String packageName);

    /**
     * Schedule a full backup of the given package.
     * !!! TODO: protect with a signature-or-system permission?
     */
    oneway void scheduleFullBackup(String packageName);
}
}
+52 −15
Original line number Original line Diff line number Diff line
@@ -58,7 +58,16 @@ class BackupManagerService extends IBackupManager.Stub {
    private SparseArray<HashSet<ServiceInfo>> mBackupParticipants
    private SparseArray<HashSet<ServiceInfo>> mBackupParticipants
        = new SparseArray<HashSet<ServiceInfo>>();
        = new SparseArray<HashSet<ServiceInfo>>();
    // set of backup services that have pending changes
    // set of backup services that have pending changes
    private HashSet<ServiceInfo> mPendingBackups = new HashSet<ServiceInfo>();
    private class BackupRequest {
        public ServiceInfo service;
        public boolean fullBackup;
        
        BackupRequest(ServiceInfo svc, boolean isFull) {
            service = svc;
            fullBackup = isFull;
        }
    }
    private HashSet<BackupRequest> mPendingBackups = new HashSet<BackupRequest>();
    private final Object mQueueLock = new Object();
    private final Object mQueueLock = new Object();


    private File mStateDir;
    private File mStateDir;
@@ -77,21 +86,21 @@ class BackupManagerService extends IBackupManager.Stub {
            case MSG_RUN_BACKUP:
            case MSG_RUN_BACKUP:
            {
            {
                // snapshot the pending-backup set and work on that
                // snapshot the pending-backup set and work on that
                HashSet<ServiceInfo> queue;
                HashSet<BackupRequest> queue;
                synchronized (mQueueLock) {
                synchronized (mQueueLock) {
                    queue = mPendingBackups;
                    queue = mPendingBackups;
                    mPendingBackups = new HashSet<ServiceInfo>();
                    mPendingBackups = new HashSet<BackupRequest>();
                    // !!! TODO: start a new backup-queue journal file too
                    // !!! TODO: start a new backup-queue journal file too
                }
                }
                
                
                // Walk the set of pending backups, setting up the relevant files and
                // Walk the set of pending backups, setting up the relevant files and
                // invoking the backup service in each participant
                // invoking the backup service in each participant
                Intent backupIntent = new Intent(BackupService.SERVICE_ACTION);
                Intent backupIntent = new Intent(BackupService.SERVICE_ACTION);
                for (ServiceInfo service : queue) {
                for (BackupRequest request : queue) {
                    mBinding = true;
                    mBinding = true;
                    mTargetService = null;
                    mTargetService = null;


                    backupIntent.setClassName(service.packageName, service.name);
                    backupIntent.setClassName(request.service.packageName, request.service.name);
                    Log.d(TAG, "binding to " + backupIntent);
                    Log.d(TAG, "binding to " + backupIntent);
                    if (mContext.bindService(backupIntent, this, 0)) {
                    if (mContext.bindService(backupIntent, this, 0)) {
                        synchronized (mBindSignaller) {
                        synchronized (mBindSignaller) {
@@ -106,12 +115,22 @@ class BackupManagerService extends IBackupManager.Stub {
                            try {
                            try {
                                Log.d(TAG, "invoking doBackup() on " + backupIntent);
                                Log.d(TAG, "invoking doBackup() on " + backupIntent);


                                File savedStateName = new File(mStateDir, service.packageName);
                                // !!! TODO right now these naming schemes limit applications to
                                File backupDataName = new File(mDataDir, service.packageName + ".data");
                                // one backup service per package
                                File newStateName = new File(mStateDir, service.packageName + ".new");
                                File savedStateName = new File(mStateDir,
                                
                                        request.service.packageName);
                                File dummyName = new File(mStateDir, "#####");
                                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 file that is never writeable, hence
                                // is always zero-sized, as a sentinel to the callee that they must
                                // write all of their data.
                                ParcelFileDescriptor savedState = 
                                ParcelFileDescriptor savedState = 
                                        ParcelFileDescriptor.open(savedStateName,
                                    ParcelFileDescriptor.open(
                                            (request.fullBackup) ? savedStateName : dummyName,
                                            ParcelFileDescriptor.MODE_READ_ONLY |
                                            ParcelFileDescriptor.MODE_READ_ONLY |
                                            ParcelFileDescriptor.MODE_CREATE);
                                            ParcelFileDescriptor.MODE_CREATE);


@@ -231,7 +250,7 @@ class BackupManagerService extends IBackupManager.Stub {
                    // packages associated with this uid
                    // packages associated with this uid
                    if (service.packageName.equals(packageName)) {
                    if (service.packageName.equals(packageName)) {
                        // add the caller to the set of pending backups
                        // add the caller to the set of pending backups
                        if (mPendingBackups.add(service)) {
                        if (mPendingBackups.add(new BackupRequest(service, false))) {
                            // !!! TODO: write to the pending-backup journal file in case of crash
                            // !!! TODO: write to the pending-backup journal file in case of crash
                        }
                        }
                    }
                    }
@@ -240,9 +259,27 @@ class BackupManagerService extends IBackupManager.Stub {
                // Schedule a backup pass in a few minutes.  As backup-eligible data
                // Schedule a backup pass in a few minutes.  As backup-eligible data
                // keeps changing, continue to defer the backup pass until things
                // keeps changing, continue to defer the backup pass until things
                // settle down, to avoid extra overhead.
                // settle down, to avoid extra overhead.
                mBackupHandler.removeMessages(MSG_RUN_BACKUP);
                mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL);
                mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL);
            }
            }
        }
        }
    }
    }

    // Schedule a backup pass for a given package, even if the caller is not part of
    // that uid or package itself.
    public void scheduleFullBackup(String packageName) throws RemoteException {
        // !!! TODO: protect with a signature-or-system permission?
        HashSet<ServiceInfo> targets = new HashSet<ServiceInfo>();
        synchronized (mQueueLock) {
            int numKeys = mBackupParticipants.size();
            for (int index = 0; index < numKeys; index++) {
                int uid = mBackupParticipants.keyAt(index);
                HashSet<ServiceInfo> servicesAtUid = mBackupParticipants.get(uid);
                for (ServiceInfo service: servicesAtUid) {
                    if (service.packageName.equals(packageName)) {
                        mPendingBackups.add(new BackupRequest(service, true));
                    }
                }
            }
        }
    }
}
}