Loading services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java +17 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading services/backup/java/com/android/server/backup/BackupRestoreTask.java +26 −5 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); } services/backup/java/com/android/server/backup/UserBackupManagerService.java +21 −26 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading Loading @@ -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. Loading Loading @@ -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}. */ Loading Loading @@ -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) { Loading @@ -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(); Loading services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +1 −1 Original line number Diff line number Diff line Loading @@ -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) { Loading services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +18 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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 = Loading Loading @@ -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, Loading Loading @@ -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); } } Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -654,7 +652,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba } finally { if (mCancelAll) { if (mCancelled) { backupRunStatus = BackupManager.ERROR_BACKUP_CANCELLED; } Loading Loading @@ -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"); } Loading Loading @@ -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( Loading @@ -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 Loading
services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java +17 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading
services/backup/java/com/android/server/backup/BackupRestoreTask.java +26 −5 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); }
services/backup/java/com/android/server/backup/UserBackupManagerService.java +21 −26 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading Loading @@ -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. Loading Loading @@ -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}. */ Loading Loading @@ -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) { Loading @@ -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(); Loading
services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +1 −1 Original line number Diff line number Diff line Loading @@ -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) { Loading
services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +18 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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 = Loading Loading @@ -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, Loading Loading @@ -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); } } Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -654,7 +652,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba } finally { if (mCancelAll) { if (mCancelled) { backupRunStatus = BackupManager.ERROR_BACKUP_CANCELLED; } Loading Loading @@ -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"); } Loading Loading @@ -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( Loading @@ -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