Loading services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java +3 −3 Original line number Diff line number Diff line Loading @@ -6,7 +6,6 @@ import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; Loading @@ -22,6 +21,7 @@ import android.os.RemoteException; import android.os.SELinux; import android.util.Slog; import com.android.server.backup.OperationStorage.OpType; import com.android.server.backup.fullbackup.AppMetadataBackupWriter; import com.android.server.backup.remote.ServiceBackupCallback; import com.android.server.backup.utils.FullBackupUtils; Loading Loading @@ -162,7 +162,7 @@ public class KeyValueAdbBackupEngine { long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis(); try { mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); OpType.BACKUP_WAIT); IBackupCallback callback = new ServiceBackupCallback( Loading Loading @@ -262,7 +262,7 @@ public class KeyValueAdbBackupEngine { pipes = ParcelFileDescriptor.createPipe(); mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); OpType.BACKUP_WAIT); // We will have to create a runnable that will read the manifest and backup data we // created, such that we can pipe the data into mOutput. The reason we do this is that Loading services/backup/java/com/android/server/backup/UserBackupManagerService.java +43 −255 Original line number Diff line number Diff line Loading @@ -107,12 +107,14 @@ 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.OperationStorage.OpState; import com.android.server.backup.OperationStorage.OpType; import com.android.server.backup.fullbackup.FullBackupEntry; import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; import com.android.server.backup.internal.BackupHandler; import com.android.server.backup.internal.ClearDataObserver; import com.android.server.backup.internal.LifecycleOperationStorage; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.internal.Operation; import com.android.server.backup.internal.PerformInitializeTask; import com.android.server.backup.internal.RunInitializeReceiver; import com.android.server.backup.internal.SetupObserver; Loading Loading @@ -287,21 +289,6 @@ public class UserBackupManagerService { private static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED"; private static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName"; // Bookkeeping of in-flight operations. The operation token is the index of the entry in the // pending operations list. public static final int OP_PENDING = 0; private static final int OP_ACKNOWLEDGED = 1; private static final int OP_TIMEOUT = -1; // Waiting for backup agent to respond during backup operation. public static final int OP_TYPE_BACKUP_WAIT = 0; // Waiting for backup agent to respond during restore operation. public static final int OP_TYPE_RESTORE_WAIT = 1; // An entire backup operation spanning multiple packages. public static final int OP_TYPE_BACKUP = 2; // Time delay for initialization operations that can be delayed so as not to consume too much // CPU on bring-up and increase time-to-UI. private static final long INITIALIZATION_DELAY_MILLIS = 3000; Loading Loading @@ -400,30 +387,8 @@ public class UserBackupManagerService { private ActiveRestoreSession mActiveRestoreSession; /** * mCurrentOperations contains the list of currently active operations. * * If type of operation is OP_TYPE_WAIT, it are waiting for an ack or timeout. * An operation wraps a BackupRestoreTask within it. * It's the responsibility of this task to remove the operation from this array. * * A BackupRestore task gets notified of ack/timeout for the operation via * BackupRestoreTask#handleCancel, BackupRestoreTask#operationComplete and notifyAll called * on the mCurrentOpLock. * {@link UserBackupManagerService#waitUntilOperationComplete(int)} is * used in various places to 'wait' for notifyAll and detect change of pending state of an * operation. So typically, an operation will be removed from this array by: * - BackupRestoreTask#handleCancel and * - BackupRestoreTask#operationComplete OR waitUntilOperationComplete. Do not remove at both * these places because waitUntilOperationComplete relies on the operation being present to * determine its completion status. * * If type of operation is OP_BACKUP, it is a task running backups. It provides a handle to * cancel backup tasks. */ @GuardedBy("mCurrentOpLock") private final SparseArray<Operation> mCurrentOperations = new SparseArray<>(); private final Object mCurrentOpLock = new Object(); private final LifecycleOperationStorage mOperationStorage; private final Random mTokenGenerator = new Random(); private final AtomicInteger mNextToken = new AtomicInteger(); Loading Loading @@ -542,12 +507,14 @@ public class UserBackupManagerService { } @VisibleForTesting UserBackupManagerService(Context context, PackageManager packageManager) { UserBackupManagerService(Context context, PackageManager packageManager, LifecycleOperationStorage operationStorage) { mContext = context; mUserId = 0; mRegisterTransportsRequestedTime = 0; mPackageManager = packageManager; mOperationStorage = operationStorage; mBaseStateDir = null; mDataDir = null; Loading Loading @@ -600,8 +567,10 @@ public class UserBackupManagerService { BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver()); mAgentTimeoutParameters.start(); mOperationStorage = new LifecycleOperationStorage(mUserId); Objects.requireNonNull(userBackupThread, "userBackupThread cannot be null"); mBackupHandler = new BackupHandler(this, userBackupThread); mBackupHandler = new BackupHandler(this, mOperationStorage, userBackupThread); // Set up our bookkeeping final ContentResolver resolver = context.getContentResolver(); Loading Loading @@ -756,6 +725,10 @@ public class UserBackupManagerService { return mTransportManager; } public OperationStorage getOperationStorage() { return mOperationStorage; } public boolean isEnabled() { return mEnabled; } Loading Loading @@ -838,14 +811,6 @@ public class UserBackupManagerService { return mActiveRestoreSession; } public SparseArray<Operation> getCurrentOperations() { return mCurrentOperations; } public Object getCurrentOpLock() { return mCurrentOpLock; } public SparseArray<AdbParams> getAdbBackupRestoreConfirmations() { return mAdbBackupRestoreConfirmations; } Loading Loading @@ -1987,18 +1952,12 @@ public class UserBackupManagerService { } final long oldToken = Binder.clearCallingIdentity(); try { List<Integer> operationsToCancel = new ArrayList<>(); synchronized (mCurrentOpLock) { for (int i = 0; i < mCurrentOperations.size(); i++) { Operation op = mCurrentOperations.valueAt(i); int token = mCurrentOperations.keyAt(i); if (op.type == OP_TYPE_BACKUP) { operationsToCancel.add(token); } } } Set<Integer> operationsToCancel = mOperationStorage.operationTokensForOpType(OpType.BACKUP); for (Integer token : operationsToCancel) { handleCancel(token, true /* cancelAll */); mOperationStorage.cancelOperation(token, /* cancelAll */ true, operationType -> { /* no callback needed here */ }); } // We don't want the backup jobs to kick in any time soon. // Reschedules them to run in the distant future. Loading @@ -2012,7 +1971,7 @@ public class UserBackupManagerService { /** Schedule a timeout message for the operation identified by {@code token}. */ public void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback, int operationType) { if (operationType != OP_TYPE_BACKUP_WAIT && operationType != OP_TYPE_RESTORE_WAIT) { if (operationType != OpType.BACKUP_WAIT && operationType != OpType.RESTORE_WAIT) { Slog.wtf( TAG, addUserIdToLogMessage( Loading @@ -2036,19 +1995,17 @@ public class UserBackupManagerService { + callback)); } synchronized (mCurrentOpLock) { mCurrentOperations.put(token, new Operation(OP_PENDING, callback, operationType)); mOperationStorage.registerOperation(token, OpState.PENDING, callback, operationType); Message msg = mBackupHandler.obtainMessage(getMessageIdForOperationType(operationType), token, 0, callback); mBackupHandler.sendMessageDelayed(msg, interval); } } private int getMessageIdForOperationType(int operationType) { switch (operationType) { case OP_TYPE_BACKUP_WAIT: case OpType.BACKUP_WAIT: return MSG_BACKUP_OPERATION_TIMEOUT; case OP_TYPE_RESTORE_WAIT: case OpType.RESTORE_WAIT: return MSG_RESTORE_OPERATION_TIMEOUT; default: Slog.wtf( Loading @@ -2061,162 +2018,28 @@ public class UserBackupManagerService { } } /** * Add an operation to the list of currently running operations. Used for cancellation, * completion and timeout callbacks that act on the operation via the {@code token}. */ public void putOperation(int token, Operation operation) { if (MORE_DEBUG) { Slog.d( TAG, addUserIdToLogMessage( mUserId, "Adding operation token=" + Integer.toHexString(token) + ", operation type=" + operation.type)); } synchronized (mCurrentOpLock) { mCurrentOperations.put(token, operation); } } /** * Remove an operation from the list of currently running operations. An operation is removed * when it is completed, cancelled, or timed out, and thus no longer running. */ public void removeOperation(int token) { if (MORE_DEBUG) { Slog.d( TAG, addUserIdToLogMessage( mUserId, "Removing operation token=" + Integer.toHexString(token))); } synchronized (mCurrentOpLock) { if (mCurrentOperations.get(token) == null) { Slog.w(TAG, addUserIdToLogMessage(mUserId, "Duplicate remove for operation. token=" + Integer.toHexString(token))); } mCurrentOperations.remove(token); } } /** Block until we received an operation complete message (from the agent or cancellation). */ public boolean waitUntilOperationComplete(int token) { if (MORE_DEBUG) { Slog.i(TAG, addUserIdToLogMessage(mUserId, "Blocking until operation complete for " + Integer.toHexString(token))); } int finalState = OP_PENDING; Operation op = null; synchronized (mCurrentOpLock) { while (true) { op = mCurrentOperations.get(token); if (op == null) { // mysterious disappearance: treat as success with no callback break; } else { if (op.state == OP_PENDING) { try { mCurrentOpLock.wait(); } catch (InterruptedException e) { } // When the wait is notified we loop around and recheck the current state } else { if (MORE_DEBUG) { Slog.d( TAG, addUserIdToLogMessage( mUserId, "Unblocked waiting for operation token=" + Integer.toHexString(token))); } // No longer pending; we're done finalState = op.state; break; } } } } removeOperation(token); if (op != null) { mBackupHandler.removeMessages(getMessageIdForOperationType(op.type)); } if (MORE_DEBUG) { Slog.v(TAG, addUserIdToLogMessage(mUserId, "operation " + Integer.toHexString(token) + " complete: finalState=" + finalState)); } return finalState == OP_ACKNOWLEDGED; return mOperationStorage.waitUntilOperationComplete(token, operationType -> { mBackupHandler.removeMessages(getMessageIdForOperationType(operationType)); }); } /** Cancel the operation associated with {@code token}. */ public void handleCancel(int token, boolean cancelAll) { // Notify any synchronous waiters Operation op = null; synchronized (mCurrentOpLock) { op = mCurrentOperations.get(token); if (MORE_DEBUG) { if (op == null) { Slog.w( TAG, addUserIdToLogMessage( mUserId, "Cancel of token " + Integer.toHexString(token) + " but no op found")); } } int state = (op != null) ? op.state : OP_TIMEOUT; if (state == OP_ACKNOWLEDGED) { // The operation finished cleanly, so we have nothing more to do. if (DEBUG) { Slog.w(TAG, addUserIdToLogMessage(mUserId, "Operation already got an ack." + "Should have been removed from mCurrentOperations.")); } op = null; mCurrentOperations.delete(token); } else if (state == OP_PENDING) { if (DEBUG) { Slog.v( TAG, addUserIdToLogMessage( mUserId, "Cancel: token=" + Integer.toHexString(token))); } op.state = OP_TIMEOUT; // Can't delete op from mCurrentOperations here. waitUntilOperationComplete may be // called after we receive cancel here. We need this op's state there. // Remove all pending timeout messages of types OP_TYPE_BACKUP_WAIT and // OP_TYPE_RESTORE_WAIT. On the other hand, OP_TYPE_BACKUP cannot time out and // 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. if (op.type == OP_TYPE_BACKUP_WAIT || op.type == OP_TYPE_RESTORE_WAIT) { mBackupHandler.removeMessages(getMessageIdForOperationType(op.type)); } } mCurrentOpLock.notifyAll(); } // If there's a TimeoutHandler for this event, call it if (op != null && op.callback != null) { if (MORE_DEBUG) { Slog.v(TAG, addUserIdToLogMessage(mUserId, " Invoking cancel on " + op.callback)); } op.callback.handleCancel(cancelAll); mOperationStorage.cancelOperation(token, cancelAll, operationType -> { if (operationType == OpType.BACKUP_WAIT || operationType == OpType.RESTORE_WAIT) { mBackupHandler.removeMessages(getMessageIdForOperationType(operationType)); } }); } /** Returns {@code true} if a backup is currently running, else returns {@code false}. */ public boolean isBackupOperationInProgress() { synchronized (mCurrentOpLock) { for (int i = 0; i < mCurrentOperations.size(); i++) { Operation op = mCurrentOperations.valueAt(i); if (op.type == OP_TYPE_BACKUP && op.state == OP_PENDING) { return true; } } } return false; return mOperationStorage.isBackupOperationInProgress(); } /** Unbind the backup agent and kill the app if it's a non-system app. */ Loading Loading @@ -2578,6 +2401,7 @@ public class UserBackupManagerService { String[] pkg = new String[]{entry.packageName}; mRunningFullBackupTask = PerformFullTransportBackupTask.newWithCurrentTransport( this, mOperationStorage, /* observer */ null, pkg, /* updateSchedule */ true, Loading Loading @@ -3107,6 +2931,7 @@ public class UserBackupManagerService { CountDownLatch latch = new CountDownLatch(1); Runnable task = PerformFullTransportBackupTask.newWithCurrentTransport( this, mOperationStorage, /* observer */ null, pkgNames, /* updateSchedule */ false, Loading Loading @@ -4126,48 +3951,11 @@ public class UserBackupManagerService { * outstanding asynchronous backup/restore operation. */ public void opComplete(int token, long result) { if (MORE_DEBUG) { Slog.v( TAG, addUserIdToLogMessage( mUserId, "opComplete: " + Integer.toHexString(token) + " result=" + result)); } Operation op = null; synchronized (mCurrentOpLock) { op = mCurrentOperations.get(token); if (op != null) { if (op.state == OP_TIMEOUT) { // The operation already timed out, and this is a late response. Tidy up // and ignore it; we've already dealt with the timeout. op = null; mCurrentOperations.delete(token); } else if (op.state == OP_ACKNOWLEDGED) { if (DEBUG) { Slog.w( TAG, addUserIdToLogMessage( mUserId, "Received duplicate ack for token=" + Integer.toHexString(token))); } op = null; mCurrentOperations.remove(token); } else if (op.state == OP_PENDING) { // Can't delete op from mCurrentOperations. waitUntilOperationComplete can be // called after we we receive this call. op.state = OP_ACKNOWLEDGED; } } mCurrentOpLock.notifyAll(); } // The completion callback, if any, is invoked on the handler if (op != null && op.callback != null) { Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result); mOperationStorage.onOperationComplete(token, result, callback -> { Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(callback, result); Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult); mBackupHandler.sendMessage(msg); } }); } /** Checks if the package is eligible for backup. */ Loading services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +2 −2 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import android.annotation.UserIdInt; Loading @@ -39,6 +38,7 @@ import android.util.Slog; import com.android.server.AppWidgetBackupBridge; import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.OperationStorage.OpType; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.remote.RemoteCall; import com.android.server.backup.utils.BackupEligibilityRules; Loading Loading @@ -147,7 +147,7 @@ public class FullBackupEngine { mToken, timeout, mTimeoutMonitor /* in parent class */, OP_TYPE_BACKUP_WAIT); OpType.BACKUP_WAIT); mAgent.doFullBackup( mPipe, mQuota, Loading services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java +2 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.backup.fullbackup; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import android.app.backup.IBackupManager; import android.content.ComponentName; Loading @@ -33,6 +32,7 @@ import android.util.Slog; import com.android.internal.backup.IObbBackupService; import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.OperationStorage.OpType; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.utils.FullBackupUtils; Loading Loading @@ -83,7 +83,7 @@ public class FullBackupObbConnection implements ServiceConnection { long fullBackupAgentTimeoutMillis = mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); backupManagerService.prepareOperationTimeout( token, fullBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); token, fullBackupAgentTimeoutMillis, null, OpType.BACKUP_WAIT); mService.backupObbs(pkg.packageName, pipes[1], token, backupManagerService.getBackupManagerBinder()); FullBackupUtils.routeSocketDataToOutput(pipes[0], out); Loading services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +6 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.util.Slog; import com.android.server.AppWidgetBackupBridge; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.KeyValueAdbBackupEngine; import com.android.server.backup.OperationStorage; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.utils.BackupEligibilityRules; import com.android.server.backup.utils.PasswordUtils; Loading Loading @@ -67,6 +68,7 @@ import javax.crypto.spec.SecretKeySpec; public class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask { private final UserBackupManagerService mUserBackupManagerService; private final OperationStorage mOperationStorage; private final AtomicBoolean mLatch; private final ParcelFileDescriptor mOutputFile; Loading @@ -85,7 +87,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor private final int mCurrentOpToken; private final BackupEligibilityRules mBackupEligibilityRules; public PerformAdbBackupTask(UserBackupManagerService backupManagerService, public PerformAdbBackupTask( UserBackupManagerService backupManagerService, OperationStorage operationStorage, ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps, boolean doSystem, Loading @@ -93,6 +96,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor BackupEligibilityRules backupEligibilityRules) { super(observer); mUserBackupManagerService = backupManagerService; mOperationStorage = operationStorage; mCurrentOpToken = backupManagerService.generateRandomIntegerToken(); mLatch = latch; Loading Loading @@ -505,6 +509,6 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor if (target != null) { mUserBackupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo); } mUserBackupManagerService.removeOperation(mCurrentOpToken); mOperationStorage.removeOperation(mCurrentOpToken); } } Loading
services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java +3 −3 Original line number Diff line number Diff line Loading @@ -6,7 +6,6 @@ import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; Loading @@ -22,6 +21,7 @@ import android.os.RemoteException; import android.os.SELinux; import android.util.Slog; import com.android.server.backup.OperationStorage.OpType; import com.android.server.backup.fullbackup.AppMetadataBackupWriter; import com.android.server.backup.remote.ServiceBackupCallback; import com.android.server.backup.utils.FullBackupUtils; Loading Loading @@ -162,7 +162,7 @@ public class KeyValueAdbBackupEngine { long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis(); try { mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); OpType.BACKUP_WAIT); IBackupCallback callback = new ServiceBackupCallback( Loading Loading @@ -262,7 +262,7 @@ public class KeyValueAdbBackupEngine { pipes = ParcelFileDescriptor.createPipe(); mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); OpType.BACKUP_WAIT); // We will have to create a runnable that will read the manifest and backup data we // created, such that we can pipe the data into mOutput. The reason we do this is that Loading
services/backup/java/com/android/server/backup/UserBackupManagerService.java +43 −255 Original line number Diff line number Diff line Loading @@ -107,12 +107,14 @@ 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.OperationStorage.OpState; import com.android.server.backup.OperationStorage.OpType; import com.android.server.backup.fullbackup.FullBackupEntry; import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; import com.android.server.backup.internal.BackupHandler; import com.android.server.backup.internal.ClearDataObserver; import com.android.server.backup.internal.LifecycleOperationStorage; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.internal.Operation; import com.android.server.backup.internal.PerformInitializeTask; import com.android.server.backup.internal.RunInitializeReceiver; import com.android.server.backup.internal.SetupObserver; Loading Loading @@ -287,21 +289,6 @@ public class UserBackupManagerService { private static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED"; private static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName"; // Bookkeeping of in-flight operations. The operation token is the index of the entry in the // pending operations list. public static final int OP_PENDING = 0; private static final int OP_ACKNOWLEDGED = 1; private static final int OP_TIMEOUT = -1; // Waiting for backup agent to respond during backup operation. public static final int OP_TYPE_BACKUP_WAIT = 0; // Waiting for backup agent to respond during restore operation. public static final int OP_TYPE_RESTORE_WAIT = 1; // An entire backup operation spanning multiple packages. public static final int OP_TYPE_BACKUP = 2; // Time delay for initialization operations that can be delayed so as not to consume too much // CPU on bring-up and increase time-to-UI. private static final long INITIALIZATION_DELAY_MILLIS = 3000; Loading Loading @@ -400,30 +387,8 @@ public class UserBackupManagerService { private ActiveRestoreSession mActiveRestoreSession; /** * mCurrentOperations contains the list of currently active operations. * * If type of operation is OP_TYPE_WAIT, it are waiting for an ack or timeout. * An operation wraps a BackupRestoreTask within it. * It's the responsibility of this task to remove the operation from this array. * * A BackupRestore task gets notified of ack/timeout for the operation via * BackupRestoreTask#handleCancel, BackupRestoreTask#operationComplete and notifyAll called * on the mCurrentOpLock. * {@link UserBackupManagerService#waitUntilOperationComplete(int)} is * used in various places to 'wait' for notifyAll and detect change of pending state of an * operation. So typically, an operation will be removed from this array by: * - BackupRestoreTask#handleCancel and * - BackupRestoreTask#operationComplete OR waitUntilOperationComplete. Do not remove at both * these places because waitUntilOperationComplete relies on the operation being present to * determine its completion status. * * If type of operation is OP_BACKUP, it is a task running backups. It provides a handle to * cancel backup tasks. */ @GuardedBy("mCurrentOpLock") private final SparseArray<Operation> mCurrentOperations = new SparseArray<>(); private final Object mCurrentOpLock = new Object(); private final LifecycleOperationStorage mOperationStorage; private final Random mTokenGenerator = new Random(); private final AtomicInteger mNextToken = new AtomicInteger(); Loading Loading @@ -542,12 +507,14 @@ public class UserBackupManagerService { } @VisibleForTesting UserBackupManagerService(Context context, PackageManager packageManager) { UserBackupManagerService(Context context, PackageManager packageManager, LifecycleOperationStorage operationStorage) { mContext = context; mUserId = 0; mRegisterTransportsRequestedTime = 0; mPackageManager = packageManager; mOperationStorage = operationStorage; mBaseStateDir = null; mDataDir = null; Loading Loading @@ -600,8 +567,10 @@ public class UserBackupManagerService { BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver()); mAgentTimeoutParameters.start(); mOperationStorage = new LifecycleOperationStorage(mUserId); Objects.requireNonNull(userBackupThread, "userBackupThread cannot be null"); mBackupHandler = new BackupHandler(this, userBackupThread); mBackupHandler = new BackupHandler(this, mOperationStorage, userBackupThread); // Set up our bookkeeping final ContentResolver resolver = context.getContentResolver(); Loading Loading @@ -756,6 +725,10 @@ public class UserBackupManagerService { return mTransportManager; } public OperationStorage getOperationStorage() { return mOperationStorage; } public boolean isEnabled() { return mEnabled; } Loading Loading @@ -838,14 +811,6 @@ public class UserBackupManagerService { return mActiveRestoreSession; } public SparseArray<Operation> getCurrentOperations() { return mCurrentOperations; } public Object getCurrentOpLock() { return mCurrentOpLock; } public SparseArray<AdbParams> getAdbBackupRestoreConfirmations() { return mAdbBackupRestoreConfirmations; } Loading Loading @@ -1987,18 +1952,12 @@ public class UserBackupManagerService { } final long oldToken = Binder.clearCallingIdentity(); try { List<Integer> operationsToCancel = new ArrayList<>(); synchronized (mCurrentOpLock) { for (int i = 0; i < mCurrentOperations.size(); i++) { Operation op = mCurrentOperations.valueAt(i); int token = mCurrentOperations.keyAt(i); if (op.type == OP_TYPE_BACKUP) { operationsToCancel.add(token); } } } Set<Integer> operationsToCancel = mOperationStorage.operationTokensForOpType(OpType.BACKUP); for (Integer token : operationsToCancel) { handleCancel(token, true /* cancelAll */); mOperationStorage.cancelOperation(token, /* cancelAll */ true, operationType -> { /* no callback needed here */ }); } // We don't want the backup jobs to kick in any time soon. // Reschedules them to run in the distant future. Loading @@ -2012,7 +1971,7 @@ public class UserBackupManagerService { /** Schedule a timeout message for the operation identified by {@code token}. */ public void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback, int operationType) { if (operationType != OP_TYPE_BACKUP_WAIT && operationType != OP_TYPE_RESTORE_WAIT) { if (operationType != OpType.BACKUP_WAIT && operationType != OpType.RESTORE_WAIT) { Slog.wtf( TAG, addUserIdToLogMessage( Loading @@ -2036,19 +1995,17 @@ public class UserBackupManagerService { + callback)); } synchronized (mCurrentOpLock) { mCurrentOperations.put(token, new Operation(OP_PENDING, callback, operationType)); mOperationStorage.registerOperation(token, OpState.PENDING, callback, operationType); Message msg = mBackupHandler.obtainMessage(getMessageIdForOperationType(operationType), token, 0, callback); mBackupHandler.sendMessageDelayed(msg, interval); } } private int getMessageIdForOperationType(int operationType) { switch (operationType) { case OP_TYPE_BACKUP_WAIT: case OpType.BACKUP_WAIT: return MSG_BACKUP_OPERATION_TIMEOUT; case OP_TYPE_RESTORE_WAIT: case OpType.RESTORE_WAIT: return MSG_RESTORE_OPERATION_TIMEOUT; default: Slog.wtf( Loading @@ -2061,162 +2018,28 @@ public class UserBackupManagerService { } } /** * Add an operation to the list of currently running operations. Used for cancellation, * completion and timeout callbacks that act on the operation via the {@code token}. */ public void putOperation(int token, Operation operation) { if (MORE_DEBUG) { Slog.d( TAG, addUserIdToLogMessage( mUserId, "Adding operation token=" + Integer.toHexString(token) + ", operation type=" + operation.type)); } synchronized (mCurrentOpLock) { mCurrentOperations.put(token, operation); } } /** * Remove an operation from the list of currently running operations. An operation is removed * when it is completed, cancelled, or timed out, and thus no longer running. */ public void removeOperation(int token) { if (MORE_DEBUG) { Slog.d( TAG, addUserIdToLogMessage( mUserId, "Removing operation token=" + Integer.toHexString(token))); } synchronized (mCurrentOpLock) { if (mCurrentOperations.get(token) == null) { Slog.w(TAG, addUserIdToLogMessage(mUserId, "Duplicate remove for operation. token=" + Integer.toHexString(token))); } mCurrentOperations.remove(token); } } /** Block until we received an operation complete message (from the agent or cancellation). */ public boolean waitUntilOperationComplete(int token) { if (MORE_DEBUG) { Slog.i(TAG, addUserIdToLogMessage(mUserId, "Blocking until operation complete for " + Integer.toHexString(token))); } int finalState = OP_PENDING; Operation op = null; synchronized (mCurrentOpLock) { while (true) { op = mCurrentOperations.get(token); if (op == null) { // mysterious disappearance: treat as success with no callback break; } else { if (op.state == OP_PENDING) { try { mCurrentOpLock.wait(); } catch (InterruptedException e) { } // When the wait is notified we loop around and recheck the current state } else { if (MORE_DEBUG) { Slog.d( TAG, addUserIdToLogMessage( mUserId, "Unblocked waiting for operation token=" + Integer.toHexString(token))); } // No longer pending; we're done finalState = op.state; break; } } } } removeOperation(token); if (op != null) { mBackupHandler.removeMessages(getMessageIdForOperationType(op.type)); } if (MORE_DEBUG) { Slog.v(TAG, addUserIdToLogMessage(mUserId, "operation " + Integer.toHexString(token) + " complete: finalState=" + finalState)); } return finalState == OP_ACKNOWLEDGED; return mOperationStorage.waitUntilOperationComplete(token, operationType -> { mBackupHandler.removeMessages(getMessageIdForOperationType(operationType)); }); } /** Cancel the operation associated with {@code token}. */ public void handleCancel(int token, boolean cancelAll) { // Notify any synchronous waiters Operation op = null; synchronized (mCurrentOpLock) { op = mCurrentOperations.get(token); if (MORE_DEBUG) { if (op == null) { Slog.w( TAG, addUserIdToLogMessage( mUserId, "Cancel of token " + Integer.toHexString(token) + " but no op found")); } } int state = (op != null) ? op.state : OP_TIMEOUT; if (state == OP_ACKNOWLEDGED) { // The operation finished cleanly, so we have nothing more to do. if (DEBUG) { Slog.w(TAG, addUserIdToLogMessage(mUserId, "Operation already got an ack." + "Should have been removed from mCurrentOperations.")); } op = null; mCurrentOperations.delete(token); } else if (state == OP_PENDING) { if (DEBUG) { Slog.v( TAG, addUserIdToLogMessage( mUserId, "Cancel: token=" + Integer.toHexString(token))); } op.state = OP_TIMEOUT; // Can't delete op from mCurrentOperations here. waitUntilOperationComplete may be // called after we receive cancel here. We need this op's state there. // Remove all pending timeout messages of types OP_TYPE_BACKUP_WAIT and // OP_TYPE_RESTORE_WAIT. On the other hand, OP_TYPE_BACKUP cannot time out and // 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. if (op.type == OP_TYPE_BACKUP_WAIT || op.type == OP_TYPE_RESTORE_WAIT) { mBackupHandler.removeMessages(getMessageIdForOperationType(op.type)); } } mCurrentOpLock.notifyAll(); } // If there's a TimeoutHandler for this event, call it if (op != null && op.callback != null) { if (MORE_DEBUG) { Slog.v(TAG, addUserIdToLogMessage(mUserId, " Invoking cancel on " + op.callback)); } op.callback.handleCancel(cancelAll); mOperationStorage.cancelOperation(token, cancelAll, operationType -> { if (operationType == OpType.BACKUP_WAIT || operationType == OpType.RESTORE_WAIT) { mBackupHandler.removeMessages(getMessageIdForOperationType(operationType)); } }); } /** Returns {@code true} if a backup is currently running, else returns {@code false}. */ public boolean isBackupOperationInProgress() { synchronized (mCurrentOpLock) { for (int i = 0; i < mCurrentOperations.size(); i++) { Operation op = mCurrentOperations.valueAt(i); if (op.type == OP_TYPE_BACKUP && op.state == OP_PENDING) { return true; } } } return false; return mOperationStorage.isBackupOperationInProgress(); } /** Unbind the backup agent and kill the app if it's a non-system app. */ Loading Loading @@ -2578,6 +2401,7 @@ public class UserBackupManagerService { String[] pkg = new String[]{entry.packageName}; mRunningFullBackupTask = PerformFullTransportBackupTask.newWithCurrentTransport( this, mOperationStorage, /* observer */ null, pkg, /* updateSchedule */ true, Loading Loading @@ -3107,6 +2931,7 @@ public class UserBackupManagerService { CountDownLatch latch = new CountDownLatch(1); Runnable task = PerformFullTransportBackupTask.newWithCurrentTransport( this, mOperationStorage, /* observer */ null, pkgNames, /* updateSchedule */ false, Loading Loading @@ -4126,48 +3951,11 @@ public class UserBackupManagerService { * outstanding asynchronous backup/restore operation. */ public void opComplete(int token, long result) { if (MORE_DEBUG) { Slog.v( TAG, addUserIdToLogMessage( mUserId, "opComplete: " + Integer.toHexString(token) + " result=" + result)); } Operation op = null; synchronized (mCurrentOpLock) { op = mCurrentOperations.get(token); if (op != null) { if (op.state == OP_TIMEOUT) { // The operation already timed out, and this is a late response. Tidy up // and ignore it; we've already dealt with the timeout. op = null; mCurrentOperations.delete(token); } else if (op.state == OP_ACKNOWLEDGED) { if (DEBUG) { Slog.w( TAG, addUserIdToLogMessage( mUserId, "Received duplicate ack for token=" + Integer.toHexString(token))); } op = null; mCurrentOperations.remove(token); } else if (op.state == OP_PENDING) { // Can't delete op from mCurrentOperations. waitUntilOperationComplete can be // called after we we receive this call. op.state = OP_ACKNOWLEDGED; } } mCurrentOpLock.notifyAll(); } // The completion callback, if any, is invoked on the handler if (op != null && op.callback != null) { Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result); mOperationStorage.onOperationComplete(token, result, callback -> { Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(callback, result); Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult); mBackupHandler.sendMessage(msg); } }); } /** Checks if the package is eligible for backup. */ Loading
services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +2 −2 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import android.annotation.UserIdInt; Loading @@ -39,6 +38,7 @@ import android.util.Slog; import com.android.server.AppWidgetBackupBridge; import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.OperationStorage.OpType; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.remote.RemoteCall; import com.android.server.backup.utils.BackupEligibilityRules; Loading Loading @@ -147,7 +147,7 @@ public class FullBackupEngine { mToken, timeout, mTimeoutMonitor /* in parent class */, OP_TYPE_BACKUP_WAIT); OpType.BACKUP_WAIT); mAgent.doFullBackup( mPipe, mQuota, Loading
services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java +2 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.backup.fullbackup; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import android.app.backup.IBackupManager; import android.content.ComponentName; Loading @@ -33,6 +32,7 @@ import android.util.Slog; import com.android.internal.backup.IObbBackupService; import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.OperationStorage.OpType; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.utils.FullBackupUtils; Loading Loading @@ -83,7 +83,7 @@ public class FullBackupObbConnection implements ServiceConnection { long fullBackupAgentTimeoutMillis = mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); backupManagerService.prepareOperationTimeout( token, fullBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); token, fullBackupAgentTimeoutMillis, null, OpType.BACKUP_WAIT); mService.backupObbs(pkg.packageName, pipes[1], token, backupManagerService.getBackupManagerBinder()); FullBackupUtils.routeSocketDataToOutput(pipes[0], out); Loading
services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +6 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.util.Slog; import com.android.server.AppWidgetBackupBridge; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.KeyValueAdbBackupEngine; import com.android.server.backup.OperationStorage; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.utils.BackupEligibilityRules; import com.android.server.backup.utils.PasswordUtils; Loading Loading @@ -67,6 +68,7 @@ import javax.crypto.spec.SecretKeySpec; public class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask { private final UserBackupManagerService mUserBackupManagerService; private final OperationStorage mOperationStorage; private final AtomicBoolean mLatch; private final ParcelFileDescriptor mOutputFile; Loading @@ -85,7 +87,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor private final int mCurrentOpToken; private final BackupEligibilityRules mBackupEligibilityRules; public PerformAdbBackupTask(UserBackupManagerService backupManagerService, public PerformAdbBackupTask( UserBackupManagerService backupManagerService, OperationStorage operationStorage, ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps, boolean doSystem, Loading @@ -93,6 +96,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor BackupEligibilityRules backupEligibilityRules) { super(observer); mUserBackupManagerService = backupManagerService; mOperationStorage = operationStorage; mCurrentOpToken = backupManagerService.generateRandomIntegerToken(); mLatch = latch; Loading Loading @@ -505,6 +509,6 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor if (target != null) { mUserBackupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo); } mUserBackupManagerService.removeOperation(mCurrentOpToken); mOperationStorage.removeOperation(mCurrentOpToken); } }