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

Commit 3e821737 authored by Sarp Misoglu's avatar Sarp Misoglu Committed by Android (Google) Code Review
Browse files

Merge "Pass in cancellation reason to B&R tasks" into main

parents 9c6e2c3b 6eecb4c4
Loading
Loading
Loading
Loading
+17 −14
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.backup.BackupRestoreTask.CancellationReason;
import com.android.server.backup.internal.LifecycleOperationStorage;

import java.util.Set;
@@ -298,18 +299,20 @@ public class BackupAgentConnectionManager {
            // Offload operation cancellation off the main thread as the cancellation callbacks
            // might call out to BackupTransport. Other operations started on the same package
            // before the cancellation callback has executed will also be cancelled by the callback.
            Runnable cancellationRunnable = () -> {
                // handleCancel() causes the PerformFullTransportBackupTask to go on to
                // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
                // that the package being backed up doesn't get stuck in restricted mode until the
                // backup time-out elapses.
            Runnable cancellationRunnable =
                    () -> {
                        // On handleCancel(), the operation will call unbindAgent() which will make
                        // sure the app doesn't get stuck in restricted mode.
                        for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
                            if (DEBUG) {
                        Slog.d(TAG,
                                mUserIdMsg + "agentDisconnected: will handleCancel(all) for token:"
                                Slog.d(
                                        TAG,
                                        mUserIdMsg
                                                + "agentDisconnected: cancelling for token:"
                                                + Integer.toHexString(token));
                            }
                    mUserBackupManagerService.handleCancel(token, true /* cancelAll */);
                            mUserBackupManagerService.handleCancel(
                                    token, CancellationReason.AGENT_DISCONNECTED);
                        }
                    };
            getThreadForCancellation(cancellationRunnable).start();
+26 −5
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@

package com.android.server.backup;

/**
 * Interface and methods used by the asynchronous-with-timeout backup/restore operations.
 */
import android.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/** Interface and methods used by the asynchronous-with-timeout backup/restore operations. */
public interface BackupRestoreTask {

    // Execute one tick of whatever state machine the task implements
@@ -27,6 +30,24 @@ public interface BackupRestoreTask {
    // An operation that wanted a callback has completed
    void operationComplete(long result);

    // An operation that wanted a callback has timed out
    void handleCancel(boolean cancelAll);
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({
        CancellationReason.TIMEOUT,
        CancellationReason.AGENT_DISCONNECTED,
        CancellationReason.EXTERNAL,
        CancellationReason.SCHEDULED_JOB_STOPPED,
    })
    @interface CancellationReason {
        // The task timed out.
        int TIMEOUT = 0;
        // The agent went away before the task was able to finish (e.g. due to an app crash).
        int AGENT_DISCONNECTED = 1;
        // An external caller cancelled the operation (e.g. via BackupManager#cancelBackups).
        int EXTERNAL = 2;
        // The job scheduler has stopped an ongoing scheduled backup pass.
        int SCHEDULED_JOB_STOPPED = 3;
    }

    /** The task is cancelled for the given {@link CancellationReason}. */
    void handleCancel(@CancellationReason int cancellationReason);
}
+21 −26
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ import com.android.internal.util.Preconditions;
import com.android.server.AppWidgetBackupBridge;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.backup.BackupRestoreTask.CancellationReason;
import com.android.server.backup.OperationStorage.OpState;
import com.android.server.backup.OperationStorage.OpType;
import com.android.server.backup.fullbackup.FullBackupEntry;
@@ -168,6 +169,7 @@ import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntConsumer;

/** System service that performs backup/restore operations. */
public class UserBackupManagerService {
@@ -1816,11 +1818,9 @@ public class UserBackupManagerService {

            for (Integer token : operationsToCancel) {
                mOperationStorage.cancelOperation(
                        token, /* cancelAll */
                        true,
                        operationType -> {
                            /* no callback needed here */
                        });
                        token,
                        operationType -> {}, // no callback needed here
                        CancellationReason.EXTERNAL);
            }
            // We don't want the backup jobs to kick in any time soon.
            // Reschedules them to run in the distant future.
@@ -1897,19 +1897,17 @@ public class UserBackupManagerService {
    }

    /** Cancel the operation associated with {@code token}. */
    public void handleCancel(int token, boolean cancelAll) {
    public void handleCancel(int token, @CancellationReason int cancellationReason) {
        // Remove all pending timeout messages of types OpType.BACKUP_WAIT and
        // OpType.RESTORE_WAIT. On the other hand, OP_TYPE_BACKUP cannot time out and
        // doesn't require cancellation.
        mOperationStorage.cancelOperation(
                token,
                cancelAll,
                operationType -> {
                    if (operationType == OpType.BACKUP_WAIT
                            || operationType == OpType.RESTORE_WAIT) {
                        mBackupHandler.removeMessages(getMessageIdForOperationType(operationType));
        IntConsumer timeoutCallback =
                opType -> {
                    if (opType == OpType.BACKUP_WAIT || opType == OpType.RESTORE_WAIT) {
                        mBackupHandler.removeMessages(getMessageIdForOperationType(opType));
                    }
                });
                };
        mOperationStorage.cancelOperation(token, timeoutCallback, cancellationReason);
    }

    /** Returns {@code true} if a backup is currently running, else returns {@code false}. */
@@ -2219,9 +2217,7 @@ public class UserBackupManagerService {
        // offload the mRunningFullBackupTask.handleCancel() call to another thread,
        // as we might have to wait for mCancelLock
        Runnable endFullBackupRunnable =
                new Runnable() {
                    @Override
                    public void run() {
                () -> {
                    PerformFullTransportBackupTask pftbt = null;
                    synchronized (mQueueLock) {
                        if (mRunningFullBackupTask != null) {
@@ -2230,8 +2226,7 @@ public class UserBackupManagerService {
                    }
                    if (pftbt != null) {
                        Slog.i(TAG, mLogIdMsg + "Telling running backup to stop");
                            pftbt.handleCancel(true);
                        }
                        pftbt.handleCancel(CancellationReason.SCHEDULED_JOB_STOPPED);
                    }
                };
        new Thread(endFullBackupRunnable, "end-full-backup").start();
+1 −1
Original line number Diff line number Diff line
@@ -484,7 +484,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
    }

    @Override
    public void handleCancel(boolean cancelAll) {
    public void handleCancel(@CancellationReason int cancellationReason) {
        final PackageInfo target = mCurrentTarget;
        Slog.w(TAG, "adb backup cancel of " + target);
        if (target != null) {
+18 −20
Original line number Diff line number Diff line
@@ -162,7 +162,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba

    // This is true when a backup operation for some package is in progress.
    private volatile boolean mIsDoingBackup;
    private volatile boolean mCancelAll;
    private volatile boolean mCancelled;
    private final int mCurrentOpToken;
    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
    private final BackupEligibilityRules mBackupEligibilityRules;
@@ -199,7 +199,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba

        if (backupManagerService.isBackupOperationInProgress()) {
            Slog.d(TAG, "Skipping full backup. A backup is already in progress.");
            mCancelAll = true;
            mCancelled = true;
            return;
        }

@@ -287,25 +287,23 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
    }

    @Override
    public void handleCancel(boolean cancelAll) {
    public void handleCancel(@CancellationReason int cancellationReason) {
        synchronized (mCancelLock) {
            // We only support 'cancelAll = true' case for this task. Cancelling of a single package

            // due to timeout is handled by SinglePackageBackupRunner and
            // This callback is only used for cancelling the entire backup operation. Cancelling of
            // a single package due to timeout is handled by SinglePackageBackupRunner and
            // SinglePackageBackupPreflight.

            if (!cancelAll) {
                Slog.wtf(TAG, "Expected cancelAll to be true.");
            if (cancellationReason == CancellationReason.TIMEOUT) {
                Slog.wtf(TAG, "This task cannot time out");
            }

            if (mCancelAll) {
            if (mCancelled) {
                Slog.d(TAG, "Ignoring duplicate cancel call.");
                return;
            }

            mCancelAll = true;
            mCancelled = true;
            if (mIsDoingBackup) {
                mUserBackupManagerService.handleCancel(mBackupRunnerOpToken, cancelAll);
                mUserBackupManagerService.handleCancel(mBackupRunnerOpToken, cancellationReason);
                try {
                    // If we're running a backup we should be connected to a transport
                    BackupTransportClient transport =
@@ -410,7 +408,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
                int backupPackageStatus;
                long quota = Long.MAX_VALUE;
                synchronized (mCancelLock) {
                    if (mCancelAll) {
                    if (mCancelled) {
                        break;
                    }
                    backupPackageStatus = transport.performFullBackup(currentPackage,
@@ -478,7 +476,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
                            if (nRead > 0) {
                                out.write(buffer, 0, nRead);
                                synchronized (mCancelLock) {
                                    if (!mCancelAll) {
                                    if (!mCancelled) {
                                        backupPackageStatus = transport.sendBackupData(nRead);
                                    }
                                }
@@ -509,7 +507,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
                    synchronized (mCancelLock) {
                        mIsDoingBackup = false;
                        // If mCancelCurrent is true, we have already called cancelFullBackup().
                        if (!mCancelAll) {
                        if (!mCancelled) {
                            if (backupRunnerResult == BackupTransport.TRANSPORT_OK) {
                                // If we were otherwise in a good state, now interpret the final
                                // result based on what finishBackup() returns.  If we're in a
@@ -607,7 +605,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
                            .sendBackupOnPackageResult(mBackupObserver, packageName,
                                    BackupManager.ERROR_BACKUP_CANCELLED);
                    Slog.w(TAG, "Backup cancelled. package=" + packageName +
                            ", cancelAll=" + mCancelAll);
                            ", entire session cancelled=" + mCancelled);
                    EventLog.writeEvent(EventLogTags.FULL_BACKUP_CANCELLED, packageName);
                    mUserBackupManagerService.getBackupAgentConnectionManager().unbindAgent(
                            currentPackage.applicationInfo, /* allowKill= */ true);
@@ -654,7 +652,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba

        } finally {

            if (mCancelAll) {
            if (mCancelled) {
                backupRunStatus = BackupManager.ERROR_BACKUP_CANCELLED;
            }

@@ -820,7 +818,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
        }

        @Override
        public void handleCancel(boolean cancelAll) {
        public void handleCancel(@CancellationReason int cancellationReason) {
            if (DEBUG) {
                Slog.i(TAG, "Preflight cancelled; failing");
            }
@@ -974,7 +972,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
        public void operationComplete(long result) { /* intentionally empty */ }

        @Override
        public void handleCancel(boolean cancelAll) {
        public void handleCancel(@CancellationReason int cancellationReason) {
            Slog.w(TAG, "Full backup cancel of " + mTarget.packageName);

            mBackupManagerMonitorEventSender.monitorEvent(
@@ -984,7 +982,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
                    /* extras= */ null);
            mIsCancelled = true;
            // Cancel tasks spun off by this task.
            mUserBackupManagerService.handleCancel(mEphemeralToken, cancelAll);
            mUserBackupManagerService.handleCancel(mEphemeralToken, cancellationReason);
            mUserBackupManagerService.getBackupAgentConnectionManager().unbindAgent(
                    mTarget.applicationInfo, /* allowKill= */ true);
            // Free up everyone waiting on this task and its children.
Loading