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

Commit 6eecb4c4 authored by Sarp Misoglu's avatar Sarp Misoglu
Browse files

Pass in cancellation reason to B&R tasks

This is to give more granular information to tasks about why they got
cancelled. This will help them report why they failed.

The cancelAll parameter was only set to false for cancellations due to
timeouts, so I've removed it.

This is a no-op refactor.

Flag: EXEMPT refactor
Bug: 399645990
Test: atest CtsBackupTestCases
Change-Id: I1bd6d9eff42c5edeb0f4df453bae792cf994bb6a
parent 2e5d0bfa
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