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

Commit a59b5f79 authored by Chris Tate's avatar Chris Tate Committed by Android (Google) Code Review
Browse files

Merge "Prevent (and repair) poisoned full-data backup queue"

parents c9fd313f 339b53a8
Loading
Loading
Loading
Loading
+64 −19
Original line number Original line Diff line number Diff line
@@ -1920,7 +1920,9 @@ public class BackupManagerService {
                synchronized (mBackupParticipants) {
                synchronized (mBackupParticipants) {
                    if (replacing) {
                    if (replacing) {
                        // This is the package-replaced case; we just remove the entry
                        // This is the package-replaced case; we just remove the entry
                        // under the old uid and fall through to re-add.
                        // under the old uid and fall through to re-add.  If an app
                        // just added key/value backup participation, this picks it up
                        // as a known participant.
                        removePackageParticipantsLocked(pkgList, uid);
                        removePackageParticipantsLocked(pkgList, uid);
                    }
                    }
                    addPackageParticipantsLocked(pkgList);
                    addPackageParticipantsLocked(pkgList);
@@ -1933,6 +1935,14 @@ public class BackupManagerService {
                        if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
                        if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
                            enqueueFullBackup(packageName, now);
                            enqueueFullBackup(packageName, now);
                            scheduleNextFullBackupJob(0);
                            scheduleNextFullBackupJob(0);
                        } else {
                            // The app might have just transitioned out of full-data into
                            // doing key/value backups, or might have just disabled backups
                            // entirely.  Make sure it is no longer in the full-data queue.
                            synchronized (mQueueLock) {
                                dequeueFullBackupLocked(packageName);
                            }
                            writeFullBackupScheduleAsync();
                        }
                        }


                        // Transport maintenance: rebind to known existing transports that have
                        // Transport maintenance: rebind to known existing transports that have
@@ -1964,6 +1974,9 @@ public class BackupManagerService {
                if (replacing) {
                if (replacing) {
                    // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
                    // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
                } else {
                } else {
                    // Outright removal.  In the full-data case, the app will be dropped
                    // from the queue when its (now obsolete) name comes up again for
                    // backup.
                    synchronized (mBackupParticipants) {
                    synchronized (mBackupParticipants) {
                        removePackageParticipantsLocked(pkgList, uid);
                        removePackageParticipantsLocked(pkgList, uid);
                    }
                    }
@@ -4190,7 +4203,17 @@ public class BackupManagerService {
                        // as well as any explicit mention of the 'special' shared-storage agent
                        // as well as any explicit mention of the 'special' shared-storage agent
                        // package (we handle that one at the end).
                        // package (we handle that one at the end).
                        if (MORE_DEBUG) {
                        if (MORE_DEBUG) {
                            Slog.d(TAG, "Ignoring not eligible package " + pkg);
                            Slog.d(TAG, "Ignoring ineligible package " + pkg);
                        }
                        sendBackupOnResult(mBackupObserver, pkg,
                            BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                        continue;
                    } else if (!appGetsFullBackup(info)) {
                        // Cull any packages that are found in the queue but now aren't supposed
                        // to get full-data backup operations.
                        if (MORE_DEBUG) {
                            Slog.d(TAG, "Ignoring full-data backup of key/value participant "
                                    + pkg);
                        }
                        }
                        sendBackupOnResult(mBackupObserver, pkg,
                        sendBackupOnResult(mBackupObserver, pkg,
                                BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                                BackupManager.ERROR_BACKUP_NOT_ALLOWED);
@@ -4591,22 +4614,29 @@ public class BackupManagerService {
        }
        }
    }
    }


    /**
     * Remove a package from the full-data queue.
     */
    void dequeueFullBackupLocked(String packageName) {
        final int N = mFullBackupQueue.size();
        for (int i = N-1; i >= 0; i--) {
            final FullBackupEntry e = mFullBackupQueue.get(i);
            if (packageName.equals(e.packageName)) {
                mFullBackupQueue.remove(i);
            }
        }
    }

    /**
    /**
     * Enqueue full backup for the given app, with a note about when it last ran.
     * Enqueue full backup for the given app, with a note about when it last ran.
     */
     */
    void enqueueFullBackup(String packageName, long lastBackedUp) {
    void enqueueFullBackup(String packageName, long lastBackedUp) {
        FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
        FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
        synchronized (mQueueLock) {
        synchronized (mQueueLock) {
            int N = mFullBackupQueue.size();
            // First, sanity check that we aren't adding a duplicate.  Slow but
            // First, sanity check that we aren't adding a duplicate.  Slow but
            // straightforward; we'll have at most on the order of a few hundred
            // straightforward; we'll have at most on the order of a few hundred
            // items in this list.
            // items in this list.
            for (int i = N-1; i >= 0; i--) {
            dequeueFullBackupLocked(packageName);
                final FullBackupEntry e = mFullBackupQueue.get(i);
                if (packageName.equals(e.packageName)) {
                    mFullBackupQueue.remove(i);
                }
            }


            // This is also slow but easy for modest numbers of apps: work backwards
            // This is also slow but easy for modest numbers of apps: work backwards
            // from the end of the queue until we find an item whose last backup
            // from the end of the queue until we find an item whose last backup
@@ -4700,21 +4730,24 @@ public class BackupManagerService {
                return false;
                return false;
            }
            }


            // At this point we think that we have work to do, but possibly not right now.
            // Any exit without actually running backups will also require that we
            // reschedule the job.
            boolean runBackup = true;
            boolean headBusy;

            do {
                // Recheck each time, because culling due to ineligibility may
                // have emptied the queue.
                if (mFullBackupQueue.size() == 0) {
                if (mFullBackupQueue.size() == 0) {
                    // no work to do so just bow out
                    // no work to do so just bow out
                    if (DEBUG) {
                    if (DEBUG) {
                        Slog.i(TAG, "Backup queue empty; doing nothing");
                        Slog.i(TAG, "Backup queue empty; doing nothing");
                    }
                    }
                return false;
                    runBackup = false;
                    break;
                }
                }


            // At this point we know that we have work to do, but possibly not right now.
            // Any exit without actually running backups will also require that we
            // reschedule the job.
            boolean runBackup = true;
            boolean headBusy;

            do {
                headBusy = false;
                headBusy = false;


                if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
                if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
@@ -4744,6 +4777,19 @@ public class BackupManagerService {


                    try {
                    try {
                        PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
                        PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
                        if (!appGetsFullBackup(appInfo)) {
                            // The head app isn't supposed to get full-data backups [any more];
                            // so we cull it and force a loop around to consider the new head
                            // app.
                            if (MORE_DEBUG) {
                                Slog.i(TAG, "Culling package " + entry.packageName
                                        + " in full-backup queue but not eligible");
                            }
                            mFullBackupQueue.remove(0);
                            headBusy = true; // force the while() condition
                            continue;
                        }

                        headBusy = mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
                        headBusy = mActivityManager.isAppForeground(appInfo.applicationInfo.uid);


                        if (headBusy) {
                        if (headBusy) {
@@ -4762,7 +4808,6 @@ public class BackupManagerService {
                            enqueueFullBackup(entry.packageName,
                            enqueueFullBackup(entry.packageName,
                                    nextEligible - MIN_FULL_BACKUP_INTERVAL);
                                    nextEligible - MIN_FULL_BACKUP_INTERVAL);
                        }
                        }

                    } catch (NameNotFoundException nnf) {
                    } catch (NameNotFoundException nnf) {
                        // So, we think we want to back this up, but it turns out the package
                        // So, we think we want to back this up, but it turns out the package
                        // in question is no longer installed.  We want to drop it from the
                        // in question is no longer installed.  We want to drop it from the