diff options
author | 2024-11-11 14:42:31 +0000 | |
---|---|---|
committer | 2024-11-18 13:26:43 +0000 | |
commit | f658e37095197043246f4ae177d441fb73cf2da2 (patch) | |
tree | 822d75c4f54fdc240eaa554caf38c01f67900b8a /services/backup/java | |
parent | 0d0270676a0b91a844e04b9909cd67e50fc9b030 (diff) |
Move BackupAgent connection to a helper class
This is to isolate some scope of UserBackupManagerService. It's too big
and unreadable.
I've also added some tests. But since these are blocking and async
operations, I couldn't see any way other than adding some thread sleeps
to avoid flakiness.
These tests could still end up being too flaky. If that's the case we
might have to leave this code untested :(
This is a no-op refactor.
Bug: 376661510
Flag: EXEMPT refactor
Test: atest BackupAgentConnectionManagerTest & atest CtsBackupHostTestCases
Change-Id: I9893336fb224148ce5b2f3c6fa2fc26828d2a1e9
Diffstat (limited to 'services/backup/java')
9 files changed, 353 insertions, 283 deletions
diff --git a/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java new file mode 100644 index 000000000000..5e4bab15952d --- /dev/null +++ b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.backup; + +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; + +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.ActivityManagerInternal; +import android.app.ApplicationThreadConstants; +import android.app.IActivityManager; +import android.app.IBackupAgent; +import android.app.backup.BackupAnnotations; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Binder; +import android.os.Build; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.ArraySet; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; +import com.android.server.backup.internal.LifecycleOperationStorage; + +import java.util.Set; + +/** + * Handles the lifecycle of {@link IBackupAgent}s that the {@link UserBackupManagerService} + * communicates with. + * + * <p>There can only be one agent that's connected to at a time. + * + * <p>There should be only one instance of this class per {@link UserBackupManagerService}. + */ +public class BackupAgentConnectionManager { + + /** + * Enables the OS making a decision on whether backup restricted mode should be used for apps + * that haven't explicitly opted in or out. See + * {@link android.content.pm.PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE} for details. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA) + public static final long OS_DECIDES_BACKUP_RESTRICTED_MODE = 376661510; + + // The thread performing the sequence of queued backups binds to each app's agent + // in succession. Bind notifications are asynchronously delivered through the + // Activity Manager; use this lock object to signal when a requested binding has + // completed. + private final Object mAgentConnectLock = new Object(); + private IBackupAgent mConnectedAgent; + private volatile boolean mConnecting; + private final ArraySet<String> mRestoreNoRestrictedModePackages = new ArraySet<>(); + private final ArraySet<String> mBackupNoRestrictedModePackages = new ArraySet<>(); + + private final IActivityManager mActivityManager; + private final ActivityManagerInternal mActivityManagerInternal; + private final LifecycleOperationStorage mOperationStorage; + private final PackageManager mPackageManager; + private final UserBackupManagerService mUserBackupManagerService; + private final int mUserId; + private final String mUserIdMsg; + + BackupAgentConnectionManager(LifecycleOperationStorage operationStorage, + PackageManager packageManager, UserBackupManagerService userBackupManagerService, + int userId) { + mActivityManager = ActivityManager.getService(); + mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); + mOperationStorage = operationStorage; + mPackageManager = packageManager; + mUserBackupManagerService = userBackupManagerService; + mUserId = userId; + mUserIdMsg = "[UserID:" + userId + "] "; + } + + /** + * Fires off a backup agent, blocking until it attaches (and ActivityManager will call + * {@link #agentConnected(String, IBinder)}) or until this operation times out. + * + * @param mode a {@code BACKUP_MODE} from {@link android.app.ApplicationThreadConstants}. + */ + @Nullable + public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode, + @BackupAnnotations.BackupDestination int backupDestination) { + IBackupAgent agent = null; + synchronized (mAgentConnectLock) { + mConnecting = true; + mConnectedAgent = null; + boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(mode, + app.packageName); + try { + if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId, + backupDestination, useRestrictedMode)) { + Slog.d(TAG, mUserIdMsg + "awaiting agent for " + app); + + // success; wait for the agent to arrive + // only wait 10 seconds for the bind to happen + long timeoutMark = System.currentTimeMillis() + 10 * 1000; + while (mConnecting && mConnectedAgent == null && (System.currentTimeMillis() + < timeoutMark)) { + try { + mAgentConnectLock.wait(5000); + } catch (InterruptedException e) { + // just bail + Slog.w(TAG, mUserIdMsg + "Interrupted: " + e); + mConnecting = false; + mConnectedAgent = null; + } + } + + // if we timed out with no connect, abort and move on + if (mConnecting) { + Slog.w(TAG, mUserIdMsg + "Timeout waiting for agent " + app); + mConnectedAgent = null; + } + Slog.i(TAG, mUserIdMsg + "got agent " + mConnectedAgent); + agent = mConnectedAgent; + } + } catch (RemoteException e) { + // can't happen - ActivityManager is local + } + } + if (agent == null) { + mActivityManagerInternal.clearPendingBackup(mUserId); + } + return agent; + } + + /** + * Tell the ActivityManager that we are done with the {@link IBackupAgent} of this {@code app}. + * It will tell the app to destroy the agent. + */ + public void unbindAgent(ApplicationInfo app) { + try { + mActivityManager.unbindBackupAgent(app); + } catch (RemoteException e) { + // Can't happen - activity manager is local + } + } + + /** + * Callback: a requested backup agent has been instantiated. This should only be called from + * the + * {@link ActivityManager} when it's telling us that an agent is ready after a call to + * {@link #bindToAgentSynchronous(ApplicationInfo, int, int)}. + */ + public void agentConnected(String packageName, IBinder agentBinder) { + synchronized (mAgentConnectLock) { + if (getCallingUid() == android.os.Process.SYSTEM_UID) { + Slog.d(TAG, + mUserIdMsg + "agentConnected pkg=" + packageName + " agent=" + agentBinder); + mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder); + mConnecting = false; + } else { + Slog.w(TAG, mUserIdMsg + "Non-system process uid=" + getCallingUid() + + " claiming agent connected"); + } + mAgentConnectLock.notifyAll(); + } + } + + /** + * Callback: a backup agent has failed to come up, or has unexpectedly quit. If the agent failed + * to come up in the first place, the agentBinder argument will be {@code null}. This should + * only be called from the {@link ActivityManager}. + */ + public void agentDisconnected(String packageName) { + synchronized (mAgentConnectLock) { + if (getCallingUid() == Process.SYSTEM_UID) { + mConnectedAgent = null; + mConnecting = false; + } else { + Slog.w(TAG, mUserIdMsg + "Non-system process uid=" + getCallingUid() + + " claiming agent disconnected"); + } + Slog.w(TAG, mUserIdMsg + "agentDisconnected: the backup agent for " + packageName + + " died: cancel current operations"); + + // 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. + for (int token : mOperationStorage.operationTokensForPackage(packageName)) { + if (MORE_DEBUG) { + Slog.d(TAG, + mUserIdMsg + "agentDisconnected: will handleCancel(all) for token:" + + Integer.toHexString(token)); + } + mUserBackupManagerService.handleCancel(token, true /* cancelAll */); + } + }; + getThreadForCancellation(cancellationRunnable).start(); + + mAgentConnectLock.notifyAll(); + } + } + + /** + * Marks the given set of packages as packages that should not be put into restricted mode if + * they are started for the given {@link BackupAnnotations.OperationType}. + */ + public void setNoRestrictedModePackages(Set<String> packageNames, + @BackupAnnotations.OperationType int opType) { + if (opType == BackupAnnotations.OperationType.BACKUP) { + mBackupNoRestrictedModePackages.clear(); + mBackupNoRestrictedModePackages.addAll(packageNames); + } else if (opType == BackupAnnotations.OperationType.RESTORE) { + mRestoreNoRestrictedModePackages.clear(); + mRestoreNoRestrictedModePackages.addAll(packageNames); + } else { + throw new IllegalArgumentException("opType must be BACKUP or RESTORE"); + } + } + + /** + * Clears the list of packages that should not be put into restricted mode for either backup or + * restore. + */ + public void clearNoRestrictedModePackages() { + mBackupNoRestrictedModePackages.clear(); + mRestoreNoRestrictedModePackages.clear(); + } + + /** + * If the app has specified {@link PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE}, then + * its value is returned. If it hasn't and it targets an SDK below + * {@link Build.VERSION_CODES#BAKLAVA} then returns true. If it targets a newer SDK, then + * returns the decision made by the {@link android.app.backup.BackupTransport}. + * + * <p>When this method is called, we should have already asked the transport and cached its + * response in {@link #mBackupNoRestrictedModePackages} or + * {@link #mRestoreNoRestrictedModePackages} so this method will immediately return without + * any IPC to the transport. + */ + private boolean shouldUseRestrictedBackupModeForPackage( + @BackupAnnotations.OperationType int mode, String packageName) { + if (!Flags.enableRestrictedModeChanges()) { + return true; + } + + // Key/Value apps are never put in restricted mode. + if (mode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL + || mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) { + return false; + } + + try { + PackageManager.Property property = mPackageManager.getPropertyAsUser( + PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, + packageName, /* className= */ null, mUserId); + if (property.isBoolean()) { + // If the package has explicitly specified, we won't ask the transport. + return property.getBoolean(); + } else { + Slog.w(TAG, + PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE + "must be a boolean."); + } + } catch (NameNotFoundException e) { + // This is expected when the package has not defined the property in its manifest. + } + + // The package has not specified the property. The behavior depends on the package's + // targetSdk. + // <36 gets the old behavior of always using restricted mode. + if (!CompatChanges.isChangeEnabled(OS_DECIDES_BACKUP_RESTRICTED_MODE, packageName, + UserHandle.of(mUserId))) { + return true; + } + + // Apps targeting >=36 get the behavior decided by the transport. + // By this point, we should have asked the transport and cached its decision. + if ((mode == ApplicationThreadConstants.BACKUP_MODE_FULL + && mBackupNoRestrictedModePackages.contains(packageName)) || ( + mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL + && mRestoreNoRestrictedModePackages.contains(packageName))) { + Slog.d(TAG, "Transport requested no restricted mode for: " + packageName); + return false; + } + return true; + } + + @VisibleForTesting + Thread getThreadForCancellation(Runnable operation) { + return new Thread(operation, /* operationName */ "agent-disconnected"); + } + + @VisibleForTesting + int getCallingUid() { + return Binder.getCallingUid(); + } +} diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 5f0071d47c89..3f6ede95eaf9 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -658,7 +658,8 @@ public class BackupManagerService extends IBackupManager.Stub { getServiceForUserIfCallerHasPermission(userId, "agentConnected()"); if (userBackupManagerService != null) { - userBackupManagerService.agentConnected(packageName, agentBinder); + userBackupManagerService.getBackupAgentConnectionManager().agentConnected(packageName, + agentBinder); } } @@ -683,7 +684,8 @@ public class BackupManagerService extends IBackupManager.Stub { getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()"); if (userBackupManagerService != null) { - userBackupManagerService.agentDisconnected(packageName); + userBackupManagerService.getBackupAgentConnectionManager().agentDisconnected( + packageName); } } diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java index f5d68362c70a..136bacdd6399 100644 --- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java +++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java @@ -146,7 +146,8 @@ public class KeyValueAdbBackupEngine { private IBackupAgent bindToAgent(ApplicationInfo targetApp) { try { - return mBackupManagerService.bindToAgentSynchronous(targetApp, + return mBackupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous( + targetApp, ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL, BackupAnnotations.BackupDestination.CLOUD); } catch (SecurityException e) { diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 5de2fb30ac78..e085f6e63067 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -43,9 +43,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.AppGlobals; -import android.app.ApplicationThreadConstants; import android.app.IActivityManager; -import android.app.IBackupAgent; import android.app.PendingIntent; import android.app.backup.BackupAgent; import android.app.backup.BackupAnnotations; @@ -60,9 +58,6 @@ import android.app.backup.IBackupObserver; import android.app.backup.IFullBackupRestoreObserver; import android.app.backup.IRestoreSession; import android.app.backup.ISelectBackupTransportCallback; -import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -83,7 +78,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; -import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PowerManager; @@ -302,21 +296,10 @@ public class UserBackupManagerService { private static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED"; private static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName"; - /** - * Enables the OS making a decision on whether backup restricted mode should be used for apps - * that haven't explicitly opted in or out. See - * {@link PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE} for details. - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA) - public static final long OS_DECIDES_BACKUP_RESTRICTED_MODE = 376661510; - // 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; - // Timeout interval for deciding that a bind has taken too long. - private static final long BIND_TIMEOUT_INTERVAL = 10 * 1000; // Timeout interval for deciding that a clear-data has taken too long. private static final long CLEAR_DATA_TIMEOUT_INTERVAL = 30 * 1000; @@ -365,22 +348,9 @@ public class UserBackupManagerService { // Backups that we haven't started yet. Keys are package names. private final HashMap<String, BackupRequest> mPendingBackups = new HashMap<>(); - private final ArraySet<String> mRestoreNoRestrictedModePackages = new ArraySet<>(); - private final ArraySet<String> mBackupNoRestrictedModePackages = new ArraySet<>(); - // locking around the pending-backup management private final Object mQueueLock = new Object(); - private final UserBackupPreferences mBackupPreferences; - - // The thread performing the sequence of queued backups binds to each app's agent - // in succession. Bind notifications are asynchronously delivered through the - // Activity Manager; use this lock object to signal when a requested binding has - // completed. - private final Object mAgentConnectLock = new Object(); - private IBackupAgent mConnectedAgent; - private volatile boolean mConnecting; - private volatile boolean mBackupRunning; private volatile long mLastBackupPass; @@ -410,6 +380,7 @@ public class UserBackupManagerService { private ActiveRestoreSession mActiveRestoreSession; + private final BackupAgentConnectionManager mBackupAgentConnectionManager; private final LifecycleOperationStorage mOperationStorage; private final Random mTokenGenerator = new Random(); @@ -547,6 +518,8 @@ public class UserBackupManagerService { mRegisterTransportsRequestedTime = 0; mPackageManager = packageManager; mOperationStorage = operationStorage; + mBackupAgentConnectionManager = new BackupAgentConnectionManager(mOperationStorage, + mPackageManager, this, mUserId); mTransportManager = transportManager; mFullBackupQueue = new ArrayList<>(); mBackupHandler = backupHandler; @@ -599,6 +572,8 @@ public class UserBackupManagerService { mAgentTimeoutParameters.start(); mOperationStorage = new LifecycleOperationStorage(mUserId); + mBackupAgentConnectionManager = new BackupAgentConnectionManager(mOperationStorage, + mPackageManager, this, mUserId); Objects.requireNonNull(userBackupThread, "userBackupThread cannot be null"); mBackupHandler = new BackupHandler(this, mOperationStorage, userBackupThread); @@ -1660,67 +1635,6 @@ public class UserBackupManagerService { } } - /** Fires off a backup agent, blocking until it attaches or times out. */ - @Nullable - public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode, - @BackupDestination int backupDestination) { - IBackupAgent agent = null; - synchronized (mAgentConnectLock) { - mConnecting = true; - mConnectedAgent = null; - boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(mode, - app.packageName); - try { - if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId, - backupDestination, useRestrictedMode)) { - Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app)); - - // success; wait for the agent to arrive - // only wait 10 seconds for the bind to happen - long timeoutMark = System.currentTimeMillis() + BIND_TIMEOUT_INTERVAL; - while (mConnecting && mConnectedAgent == null - && (System.currentTimeMillis() < timeoutMark)) { - try { - mAgentConnectLock.wait(5000); - } catch (InterruptedException e) { - // just bail - Slog.w(TAG, addUserIdToLogMessage(mUserId, "Interrupted: " + e)); - mConnecting = false; - mConnectedAgent = null; - } - } - - // if we timed out with no connect, abort and move on - if (mConnecting) { - Slog.w( - TAG, - addUserIdToLogMessage(mUserId, "Timeout waiting for agent " + app)); - mConnectedAgent = null; - } - if (DEBUG) { - Slog.i(TAG, addUserIdToLogMessage(mUserId, "got agent " + mConnectedAgent)); - } - agent = mConnectedAgent; - } - } catch (RemoteException e) { - // can't happen - ActivityManager is local - } - } - if (agent == null) { - mActivityManagerInternal.clearPendingBackup(mUserId); - } - return agent; - } - - /** Unbind from a backup agent. */ - public void unbindAgent(ApplicationInfo app) { - try { - mActivityManager.unbindBackupAgent(app); - } catch (RemoteException e) { - // Can't happen - activity manager is local - } - } - /** * Clear an application's data after a failed restore, blocking until the operation completes or * times out. @@ -2493,10 +2407,6 @@ public class UserBackupManagerService { AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, mUserId); } - // ***************************** - // NEW UNIFIED RESTORE IMPLEMENTATION - // ***************************** - /** Schedule a backup pass for {@code packageName}. */ public void dataChangedImpl(String packageName) { HashSet<String> targets = dataChangedTargets(packageName); @@ -3122,91 +3032,6 @@ public class UserBackupManagerService { } } - /** - * Marks the given set of packages as packages that should not be put into restricted mode if - * they are started for the given {@link BackupAnnotations.OperationType}. - */ - public void setNoRestrictedModePackages(Set<String> packageNames, - @BackupAnnotations.OperationType int opType) { - if (opType == BackupAnnotations.OperationType.BACKUP) { - mBackupNoRestrictedModePackages.clear(); - mBackupNoRestrictedModePackages.addAll(packageNames); - } else if (opType == BackupAnnotations.OperationType.RESTORE) { - mRestoreNoRestrictedModePackages.clear(); - mRestoreNoRestrictedModePackages.addAll(packageNames); - } else { - throw new IllegalArgumentException("opType must be BACKUP or RESTORE"); - } - } - - /** - * Clears the list of packages that should not be put into restricted mode for either backup or - * restore. - */ - public void clearNoRestrictedModePackages() { - mBackupNoRestrictedModePackages.clear(); - mRestoreNoRestrictedModePackages.clear(); - } - - /** - * If the app has specified {@link PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE}, then - * its value is returned. If it hasn't and it targets an SDK below - * {@link Build.VERSION_CODES#BAKLAVA} then returns true. If it targets a newer SDK, then - * returns the decision made by the {@link android.app.backup.BackupTransport}. - * - * <p>When this method is called, we should have already asked the transport and cached its - * response in {@link #mBackupNoRestrictedModePackages} or - * {@link #mRestoreNoRestrictedModePackages} so this method will immediately return without - * any IPC to the transport. - */ - private boolean shouldUseRestrictedBackupModeForPackage( - @BackupAnnotations.OperationType int mode, String packageName) { - if (!Flags.enableRestrictedModeChanges()) { - return true; - } - - // Key/Value apps are never put in restricted mode. - if (mode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL - || mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) { - return false; - } - - try { - PackageManager.Property property = mPackageManager.getPropertyAsUser( - PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, - packageName, /* className= */ null, - mUserId); - if (property.isBoolean()) { - // If the package has explicitly specified, we won't ask the transport. - return property.getBoolean(); - } else { - Slog.w(TAG, PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE - + "must be a boolean."); - } - } catch (NameNotFoundException e) { - // This is expected when the package has not defined the property in its manifest. - } - - // The package has not specified the property. The behavior depends on the package's - // targetSdk. - // <36 gets the old behavior of always using restricted mode. - if (!CompatChanges.isChangeEnabled(OS_DECIDES_BACKUP_RESTRICTED_MODE, packageName, - UserHandle.of(mUserId))) { - return true; - } - - // Apps targeting >=36 get the behavior decided by the transport. - // By this point, we should have asked the transport and cached its decision. - if ((mode == ApplicationThreadConstants.BACKUP_MODE_FULL - && mBackupNoRestrictedModePackages.contains(packageName)) - || (mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL - && mRestoreNoRestrictedModePackages.contains(packageName))) { - Slog.d(TAG, "Transport requested no restricted mode for: " + packageName); - return false; - } - return true; - } - private boolean startConfirmationUi(int token, String action) { try { Intent confIntent = new Intent(action); @@ -3898,83 +3723,6 @@ public class UserBackupManagerService { } /** - * Callback: a requested backup agent has been instantiated. This should only be called from the - * {@link ActivityManager}. - */ - public void agentConnected(String packageName, IBinder agentBinder) { - synchronized (mAgentConnectLock) { - if (Binder.getCallingUid() == Process.SYSTEM_UID) { - Slog.d( - TAG, - addUserIdToLogMessage( - mUserId, - "agentConnected pkg=" + packageName + " agent=" + agentBinder)); - mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder); - mConnecting = false; - } else { - Slog.w( - TAG, - addUserIdToLogMessage( - mUserId, - "Non-system process uid=" - + Binder.getCallingUid() - + " claiming agent connected")); - } - mAgentConnectLock.notifyAll(); - } - } - - /** - * Callback: a backup agent has failed to come up, or has unexpectedly quit. If the agent failed - * to come up in the first place, the agentBinder argument will be {@code null}. This should - * only be called from the {@link ActivityManager}. - */ - public void agentDisconnected(String packageName) { - synchronized (mAgentConnectLock) { - if (Binder.getCallingUid() == Process.SYSTEM_UID) { - mConnectedAgent = null; - mConnecting = false; - } else { - Slog.w( - TAG, - addUserIdToLogMessage( - mUserId, - "Non-system process uid=" - + Binder.getCallingUid() - + " claiming agent disconnected")); - } - Slog.w(TAG, "agentDisconnected: the backup agent for " + packageName - + " died: cancel current operations"); - - // 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. - for (int token : mOperationStorage.operationTokensForPackage(packageName)) { - if (MORE_DEBUG) { - Slog.d(TAG, "agentDisconnected: will handleCancel(all) for token:" - + Integer.toHexString(token)); - } - handleCancel(token, true /* cancelAll */); - } - }; - getThreadForAsyncOperation(/* operationName */ "agent-disconnected", - cancellationRunnable).start(); - - mAgentConnectLock.notifyAll(); - } - } - - @VisibleForTesting - Thread getThreadForAsyncOperation(String operationName, Runnable operation) { - return new Thread(operation, operationName); - } - - /** * An application being installed will need a restore pass, then the {@link PackageManager} will * need to be told when the restore is finished. */ @@ -4521,4 +4269,8 @@ public class UserBackupManagerService { public IBackupManager getBackupManagerBinder() { return mBackupManagerBinder; } + + public BackupAgentConnectionManager getBackupAgentConnectionManager() { + return mBackupAgentConnectionManager; + } } diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java index 12712063e344..b98cb1086680 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java @@ -314,7 +314,7 @@ public class FullBackupEngine { Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName); } mAgent = - backupManagerService.bindToAgentSynchronous( + backupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous( mPkg.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_FULL, mBackupEligibilityRules.getBackupDestination()); } diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index be9cdc8692cb..65730c9591a8 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -702,7 +702,8 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba } // Clear this to avoid using the memory until reboot. - mUserBackupManagerService.clearNoRestrictedModePackages(); + mUserBackupManagerService + .getBackupAgentConnectionManager().clearNoRestrictedModePackages(); Slog.i(TAG, "Full data backup pass finished."); mUserBackupManagerService.getWakelock().release(); @@ -741,7 +742,8 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba } packageNames = transport.getPackagesThatShouldNotUseRestrictedMode(packageNames, BACKUP); - mUserBackupManagerService.setNoRestrictedModePackages(packageNames, BACKUP); + mUserBackupManagerService.getBackupAgentConnectionManager().setNoRestrictedModePackages( + packageNames, BACKUP); } catch (RemoteException e) { Slog.i(TAG, "Failed to retrieve no restricted mode packages from transport"); } diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java index 3a6e1cafa505..82232a653858 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java @@ -741,7 +741,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { final IBackupAgent agent; try { agent = - mBackupManagerService.bindToAgentSynchronous( + mBackupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous( packageInfo.applicationInfo, BACKUP_MODE_INCREMENTAL, mBackupEligibilityRules.getBackupDestination()); if (agent == null) { @@ -1302,7 +1302,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { // For PM metadata (for which applicationInfo is null) there is no agent-bound state. if (mCurrentPackage.applicationInfo != null) { - mBackupManagerService.unbindAgent(mCurrentPackage.applicationInfo); + mBackupManagerService.getBackupAgentConnectionManager().unbindAgent( + mCurrentPackage.applicationInfo); } mAgent = null; } diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index 2d99c96452da..b59e860f81fe 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -410,11 +410,7 @@ public class FullRestoreEngine extends RestoreEngine { // All set; now set up the IPC and launch the agent setUpPipes(); - mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp, - FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain) - ? ApplicationThreadConstants.BACKUP_MODE_RESTORE - : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL, - mBackupEligibilityRules.getBackupDestination()); + mAgent = bindToAgent(info); mAgentPackage = pkg; } catch (IOException | NameNotFoundException e) { // fall through to error handling @@ -805,15 +801,12 @@ public class FullRestoreEngine extends RestoreEngine { return packages.contains(packageName); } - void sendOnRestorePackage(String name) { - if (mObserver != null) { - try { - // TODO: use a more user-friendly name string - mObserver.onRestorePackage(name); - } catch (RemoteException e) { - Slog.w(TAG, "full restore observer went away: restorePackage"); - mObserver = null; - } - } + private IBackupAgent bindToAgent(FileMetadata info) { + return mBackupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous( + mTargetApp, + FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain) + ? ApplicationThreadConstants.BACKUP_MODE_RESTORE + : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL, + mBackupEligibilityRules.getBackupDestination()); } } diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 5ee51a5aa189..e5c7e5cce757 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -814,7 +814,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // Good to go! Set up and bind the agent... mAgent = - backupManagerService.bindToAgentSynchronous( + backupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous( mCurrentPackage.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_RESTORE, mBackupEligibilityRules.getBackupDestination()); @@ -1364,7 +1364,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { backupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT); // Clear this to avoid using the memory until reboot. - backupManagerService.clearNoRestrictedModePackages(); + backupManagerService.getBackupAgentConnectionManager().clearNoRestrictedModePackages(); // If we have a PM token, we must under all circumstances be sure to // handshake when we've finished. @@ -1838,7 +1838,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { } packageNames = transport.getPackagesThatShouldNotUseRestrictedMode(packageNames, RESTORE); - backupManagerService.setNoRestrictedModePackages(packageNames, RESTORE); + backupManagerService.getBackupAgentConnectionManager().setNoRestrictedModePackages( + packageNames, RESTORE); } catch (RemoteException e) { Slog.i(TAG, "Failed to retrieve restricted mode packages from transport"); } |