Loading services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java +74 −21 Original line number Original line Diff line number Diff line Loading @@ -101,11 +101,16 @@ public class BackupAgentConnectionManager { private static final class BackupAgentConnection { private static final class BackupAgentConnection { public final ApplicationInfo appInfo; public final ApplicationInfo appInfo; public final int backupMode; public final boolean inRestrictedMode; public IBackupAgent backupAgent; public IBackupAgent backupAgent; public boolean connecting = true; // Assume we are trying to connect on creation. public boolean connecting = true; // Assume we are trying to connect on creation. private BackupAgentConnection(ApplicationInfo appInfo) { private BackupAgentConnection(ApplicationInfo appInfo, int backupMode, boolean inRestrictedMode) { this.appInfo = appInfo; this.appInfo = appInfo; this.backupMode = backupMode; this.inRestrictedMode = inRestrictedMode; } } } } Loading @@ -113,26 +118,31 @@ public class BackupAgentConnectionManager { * Fires off a backup agent, blocking until it attaches (i.e. ActivityManager calls * Fires off a backup agent, blocking until it attaches (i.e. ActivityManager calls * {@link #agentConnected(String, IBinder)}) or until this operation times out. * {@link #agentConnected(String, IBinder)}) or until this operation times out. * * * @param mode a {@code BACKUP_MODE} from {@link android.app.ApplicationThreadConstants}. * @param backupMode a {@code BACKUP_MODE} from {@link android.app.ApplicationThreadConstants}. */ */ @Nullable @Nullable public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode, public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int backupMode, @BackupAnnotations.BackupDestination int backupDestination) { @BackupAnnotations.BackupDestination int backupDestination) { if (app == null) { Slog.w(TAG, mUserIdMsg + "bindToAgentSynchronous for null app"); return null; } synchronized (mAgentConnectLock) { synchronized (mAgentConnectLock) { boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(mode, boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(backupMode, app.packageName); app.packageName); if (mCurrentConnection != null) { if (mCurrentConnection != null) { Slog.e(TAG, mUserIdMsg + "binding to new agent before unbinding from old one: " Slog.e(TAG, mUserIdMsg + "binding to new agent before unbinding from old one: " + mCurrentConnection.appInfo.packageName); + mCurrentConnection.appInfo.packageName); } } mCurrentConnection = new BackupAgentConnection(app); mCurrentConnection = new BackupAgentConnection(app, backupMode, useRestrictedMode); // bindBackupAgent() is an async API. It will kick off the app's process and call // bindBackupAgent() is an async API. It will kick off the app's process and call // agentConnected() when it receives the agent from the app. // agentConnected() when it receives the agent from the app. boolean startedBindSuccessfully = false; boolean startedBindSuccessfully = false; try { try { startedBindSuccessfully = mActivityManager.bindBackupAgent(app.packageName, mode, startedBindSuccessfully = mActivityManager.bindBackupAgent(app.packageName, mUserId, backupDestination, useRestrictedMode); backupMode, mUserId, backupDestination, useRestrictedMode); } catch (RemoteException e) { } catch (RemoteException e) { // can't happen - ActivityManager is local // can't happen - ActivityManager is local } } Loading Loading @@ -173,28 +183,66 @@ public class BackupAgentConnectionManager { /** /** * Tell the ActivityManager that we are done with the {@link IBackupAgent} of this {@code app}. * Tell the ActivityManager that we are done with the {@link IBackupAgent} of this {@code app}. * It will tell the app to destroy the agent. * It will tell the app to destroy the agent. * * <p>If {@code allowKill} is set, this will kill the app's process if the app is in restricted * mode or if it was started for restore and specified {@code android:killAfterRestore} in its * manifest. * * @see #shouldUseRestrictedBackupModeForPackage(int, String) */ */ public void unbindAgent(ApplicationInfo app) { public void unbindAgent(ApplicationInfo app, boolean allowKill) { if (app == null) { Slog.w(TAG, mUserIdMsg + "unbindAgent for null app"); return; } synchronized (mAgentConnectLock) { synchronized (mAgentConnectLock) { // Even if we weren't expecting to be bound to this agent, we should still call // ActivityManager just in case. It will ignore the call if it also wasn't expecting it. try { mActivityManager.unbindBackupAgent(app); // Evaluate this before potentially setting mCurrentConnection = null. boolean willKill = allowKill && shouldKillAppOnUnbind(app); if (mCurrentConnection == null) { if (mCurrentConnection == null) { Slog.w(TAG, mUserIdMsg + "unbindAgent but no current connection"); Slog.w(TAG, mUserIdMsg + "unbindAgent but no current connection"); } else if (!mCurrentConnection.appInfo.packageName.equals(app.packageName)) { } else if (!mCurrentConnection.appInfo.packageName.equals(app.packageName)) { Slog.w(TAG, mUserIdMsg + "unbindAgent for unexpected package: " + app.packageName Slog.w(TAG, mUserIdMsg + "unbindAgent for unexpected package: " + app.packageName + " expected: " + mCurrentConnection.appInfo.packageName); + " expected: " + mCurrentConnection.appInfo.packageName); } else { } else { mCurrentConnection = null; mCurrentConnection = null; } } // Even if we weren't expecting to be bound to this agent, we should still call if (willKill) { // ActivityManager just in case. It will ignore the call if it also wasn't expecting it. Slog.i(TAG, mUserIdMsg + "Killing agent host process"); try { mActivityManager.killApplicationProcess(app.processName, app.uid); mActivityManager.unbindBackupAgent(app); } } catch (RemoteException e) { } catch (RemoteException e) { // Can't happen - activity manager is local // Can't happen - activity manager is local } } } } } } @GuardedBy("mAgentConnectLock") private boolean shouldKillAppOnUnbind(ApplicationInfo app) { // We don't ask system UID processes to be killed. if (UserHandle.isCore(app.uid)) { return false; } // If the app is in restricted mode or if we're not sure if it is because our internal // state is messed up, we need to avoid it being stuck in it. if (mCurrentConnection == null || mCurrentConnection.inRestrictedMode) { return true; } // App was doing restore and asked to be killed afterwards. return isBackupModeRestore(mCurrentConnection.backupMode) && (app.flags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0; } /** /** * Callback: a requested backup agent has been instantiated. This should only be called from * 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 * the {@link ActivityManager} when it's telling us that an agent is ready after a call to Loading Loading @@ -307,16 +355,16 @@ public class BackupAgentConnectionManager { */ */ private boolean shouldUseRestrictedBackupModeForPackage( private boolean shouldUseRestrictedBackupModeForPackage( @BackupAnnotations.OperationType int mode, String packageName) { @BackupAnnotations.OperationType int mode, String packageName) { if (!Flags.enableRestrictedModeChanges()) { return true; } // Key/Value apps are never put in restricted mode. // Key/Value apps are never put in restricted mode. if (mode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL if (mode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL || mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) { || mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) { return false; return false; } } if (!Flags.enableRestrictedModeChanges()) { return true; } try { try { PackageManager.Property property = mPackageManager.getPropertyAsUser( PackageManager.Property property = mPackageManager.getPropertyAsUser( PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, Loading Loading @@ -352,6 +400,11 @@ public class BackupAgentConnectionManager { return true; return true; } } private static boolean isBackupModeRestore(int backupMode) { return backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE || backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL; } @VisibleForTesting @VisibleForTesting Thread getThreadForCancellation(Runnable operation) { Thread getThreadForCancellation(Runnable operation) { return new Thread(operation, /* operationName */ "agent-disconnected"); return new Thread(operation, /* operationName */ "agent-disconnected"); Loading services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -300,7 +300,8 @@ public class KeyValueAdbBackupEngine { } } private void cleanup() { private void cleanup() { mBackupManagerService.tearDownAgentAndKill(mCurrentPackage.applicationInfo); mBackupManagerService.getBackupAgentConnectionManager().unbindAgent( mCurrentPackage.applicationInfo, /* allowKill= */ true); mBlankStateName.delete(); mBlankStateName.delete(); mNewStateName.delete(); mNewStateName.delete(); mBackupDataName.delete(); mBackupDataName.delete(); Loading services/backup/java/com/android/server/backup/UserBackupManagerService.java +0 −33 Original line number Original line Diff line number Diff line Loading @@ -1998,39 +1998,6 @@ public class UserBackupManagerService { return mOperationStorage.isBackupOperationInProgress(); return mOperationStorage.isBackupOperationInProgress(); } } /** Unbind the backup agent and kill the app if it's a non-system app. */ public void tearDownAgentAndKill(ApplicationInfo app) { if (app == null) { // Null means the system package, so just quietly move on. :) return; } try { // unbind and tidy up even on timeout or failure, just in case mActivityManager.unbindBackupAgent(app); // The agent was running with a stub Application object, so shut it down. // !!! We hardcode the confirmation UI's package name here rather than use a // manifest flag! TODO something less direct. if (!UserHandle.isCore(app.uid) && !app.packageName.equals("com.android.backupconfirm")) { if (MORE_DEBUG) { Slog.d(TAG, addUserIdToLogMessage(mUserId, "Killing agent host process")); } mActivityManager.killApplicationProcess(app.processName, app.uid); } else { if (MORE_DEBUG) { Slog.d( TAG, addUserIdToLogMessage( mUserId, "Not killing after operation: " + app.processName)); } } } catch (RemoteException e) { Slog.d(TAG, addUserIdToLogMessage(mUserId, "Lost app trying to shut down")); } } // ----- Full-data backup scheduling ----- // ----- Full-data backup scheduling ----- /** /** Loading services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -323,7 +323,8 @@ public class FullBackupEngine { private void tearDown() { private void tearDown() { if (mPkg != null) { if (mPkg != null) { backupManagerService.tearDownAgentAndKill(mPkg.applicationInfo); backupManagerService.getBackupAgentConnectionManager().unbindAgent( mPkg.applicationInfo, /* allowKill= */ true); } } } } } } services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -503,7 +503,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor Slog.w(TAG, "adb backup cancel of " + target); Slog.w(TAG, "adb backup cancel of " + target); } } if (target != null) { if (target != null) { mUserBackupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo); mUserBackupManagerService.getBackupAgentConnectionManager().unbindAgent( target.applicationInfo, /* allowKill= */ true); } } mOperationStorage.removeOperation(mCurrentOpToken); mOperationStorage.removeOperation(mCurrentOpToken); } } Loading Loading
services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java +74 −21 Original line number Original line Diff line number Diff line Loading @@ -101,11 +101,16 @@ public class BackupAgentConnectionManager { private static final class BackupAgentConnection { private static final class BackupAgentConnection { public final ApplicationInfo appInfo; public final ApplicationInfo appInfo; public final int backupMode; public final boolean inRestrictedMode; public IBackupAgent backupAgent; public IBackupAgent backupAgent; public boolean connecting = true; // Assume we are trying to connect on creation. public boolean connecting = true; // Assume we are trying to connect on creation. private BackupAgentConnection(ApplicationInfo appInfo) { private BackupAgentConnection(ApplicationInfo appInfo, int backupMode, boolean inRestrictedMode) { this.appInfo = appInfo; this.appInfo = appInfo; this.backupMode = backupMode; this.inRestrictedMode = inRestrictedMode; } } } } Loading @@ -113,26 +118,31 @@ public class BackupAgentConnectionManager { * Fires off a backup agent, blocking until it attaches (i.e. ActivityManager calls * Fires off a backup agent, blocking until it attaches (i.e. ActivityManager calls * {@link #agentConnected(String, IBinder)}) or until this operation times out. * {@link #agentConnected(String, IBinder)}) or until this operation times out. * * * @param mode a {@code BACKUP_MODE} from {@link android.app.ApplicationThreadConstants}. * @param backupMode a {@code BACKUP_MODE} from {@link android.app.ApplicationThreadConstants}. */ */ @Nullable @Nullable public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode, public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int backupMode, @BackupAnnotations.BackupDestination int backupDestination) { @BackupAnnotations.BackupDestination int backupDestination) { if (app == null) { Slog.w(TAG, mUserIdMsg + "bindToAgentSynchronous for null app"); return null; } synchronized (mAgentConnectLock) { synchronized (mAgentConnectLock) { boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(mode, boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(backupMode, app.packageName); app.packageName); if (mCurrentConnection != null) { if (mCurrentConnection != null) { Slog.e(TAG, mUserIdMsg + "binding to new agent before unbinding from old one: " Slog.e(TAG, mUserIdMsg + "binding to new agent before unbinding from old one: " + mCurrentConnection.appInfo.packageName); + mCurrentConnection.appInfo.packageName); } } mCurrentConnection = new BackupAgentConnection(app); mCurrentConnection = new BackupAgentConnection(app, backupMode, useRestrictedMode); // bindBackupAgent() is an async API. It will kick off the app's process and call // bindBackupAgent() is an async API. It will kick off the app's process and call // agentConnected() when it receives the agent from the app. // agentConnected() when it receives the agent from the app. boolean startedBindSuccessfully = false; boolean startedBindSuccessfully = false; try { try { startedBindSuccessfully = mActivityManager.bindBackupAgent(app.packageName, mode, startedBindSuccessfully = mActivityManager.bindBackupAgent(app.packageName, mUserId, backupDestination, useRestrictedMode); backupMode, mUserId, backupDestination, useRestrictedMode); } catch (RemoteException e) { } catch (RemoteException e) { // can't happen - ActivityManager is local // can't happen - ActivityManager is local } } Loading Loading @@ -173,28 +183,66 @@ public class BackupAgentConnectionManager { /** /** * Tell the ActivityManager that we are done with the {@link IBackupAgent} of this {@code app}. * Tell the ActivityManager that we are done with the {@link IBackupAgent} of this {@code app}. * It will tell the app to destroy the agent. * It will tell the app to destroy the agent. * * <p>If {@code allowKill} is set, this will kill the app's process if the app is in restricted * mode or if it was started for restore and specified {@code android:killAfterRestore} in its * manifest. * * @see #shouldUseRestrictedBackupModeForPackage(int, String) */ */ public void unbindAgent(ApplicationInfo app) { public void unbindAgent(ApplicationInfo app, boolean allowKill) { if (app == null) { Slog.w(TAG, mUserIdMsg + "unbindAgent for null app"); return; } synchronized (mAgentConnectLock) { synchronized (mAgentConnectLock) { // Even if we weren't expecting to be bound to this agent, we should still call // ActivityManager just in case. It will ignore the call if it also wasn't expecting it. try { mActivityManager.unbindBackupAgent(app); // Evaluate this before potentially setting mCurrentConnection = null. boolean willKill = allowKill && shouldKillAppOnUnbind(app); if (mCurrentConnection == null) { if (mCurrentConnection == null) { Slog.w(TAG, mUserIdMsg + "unbindAgent but no current connection"); Slog.w(TAG, mUserIdMsg + "unbindAgent but no current connection"); } else if (!mCurrentConnection.appInfo.packageName.equals(app.packageName)) { } else if (!mCurrentConnection.appInfo.packageName.equals(app.packageName)) { Slog.w(TAG, mUserIdMsg + "unbindAgent for unexpected package: " + app.packageName Slog.w(TAG, mUserIdMsg + "unbindAgent for unexpected package: " + app.packageName + " expected: " + mCurrentConnection.appInfo.packageName); + " expected: " + mCurrentConnection.appInfo.packageName); } else { } else { mCurrentConnection = null; mCurrentConnection = null; } } // Even if we weren't expecting to be bound to this agent, we should still call if (willKill) { // ActivityManager just in case. It will ignore the call if it also wasn't expecting it. Slog.i(TAG, mUserIdMsg + "Killing agent host process"); try { mActivityManager.killApplicationProcess(app.processName, app.uid); mActivityManager.unbindBackupAgent(app); } } catch (RemoteException e) { } catch (RemoteException e) { // Can't happen - activity manager is local // Can't happen - activity manager is local } } } } } } @GuardedBy("mAgentConnectLock") private boolean shouldKillAppOnUnbind(ApplicationInfo app) { // We don't ask system UID processes to be killed. if (UserHandle.isCore(app.uid)) { return false; } // If the app is in restricted mode or if we're not sure if it is because our internal // state is messed up, we need to avoid it being stuck in it. if (mCurrentConnection == null || mCurrentConnection.inRestrictedMode) { return true; } // App was doing restore and asked to be killed afterwards. return isBackupModeRestore(mCurrentConnection.backupMode) && (app.flags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0; } /** /** * Callback: a requested backup agent has been instantiated. This should only be called from * 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 * the {@link ActivityManager} when it's telling us that an agent is ready after a call to Loading Loading @@ -307,16 +355,16 @@ public class BackupAgentConnectionManager { */ */ private boolean shouldUseRestrictedBackupModeForPackage( private boolean shouldUseRestrictedBackupModeForPackage( @BackupAnnotations.OperationType int mode, String packageName) { @BackupAnnotations.OperationType int mode, String packageName) { if (!Flags.enableRestrictedModeChanges()) { return true; } // Key/Value apps are never put in restricted mode. // Key/Value apps are never put in restricted mode. if (mode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL if (mode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL || mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) { || mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) { return false; return false; } } if (!Flags.enableRestrictedModeChanges()) { return true; } try { try { PackageManager.Property property = mPackageManager.getPropertyAsUser( PackageManager.Property property = mPackageManager.getPropertyAsUser( PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, Loading Loading @@ -352,6 +400,11 @@ public class BackupAgentConnectionManager { return true; return true; } } private static boolean isBackupModeRestore(int backupMode) { return backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE || backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL; } @VisibleForTesting @VisibleForTesting Thread getThreadForCancellation(Runnable operation) { Thread getThreadForCancellation(Runnable operation) { return new Thread(operation, /* operationName */ "agent-disconnected"); return new Thread(operation, /* operationName */ "agent-disconnected"); Loading
services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -300,7 +300,8 @@ public class KeyValueAdbBackupEngine { } } private void cleanup() { private void cleanup() { mBackupManagerService.tearDownAgentAndKill(mCurrentPackage.applicationInfo); mBackupManagerService.getBackupAgentConnectionManager().unbindAgent( mCurrentPackage.applicationInfo, /* allowKill= */ true); mBlankStateName.delete(); mBlankStateName.delete(); mNewStateName.delete(); mNewStateName.delete(); mBackupDataName.delete(); mBackupDataName.delete(); Loading
services/backup/java/com/android/server/backup/UserBackupManagerService.java +0 −33 Original line number Original line Diff line number Diff line Loading @@ -1998,39 +1998,6 @@ public class UserBackupManagerService { return mOperationStorage.isBackupOperationInProgress(); return mOperationStorage.isBackupOperationInProgress(); } } /** Unbind the backup agent and kill the app if it's a non-system app. */ public void tearDownAgentAndKill(ApplicationInfo app) { if (app == null) { // Null means the system package, so just quietly move on. :) return; } try { // unbind and tidy up even on timeout or failure, just in case mActivityManager.unbindBackupAgent(app); // The agent was running with a stub Application object, so shut it down. // !!! We hardcode the confirmation UI's package name here rather than use a // manifest flag! TODO something less direct. if (!UserHandle.isCore(app.uid) && !app.packageName.equals("com.android.backupconfirm")) { if (MORE_DEBUG) { Slog.d(TAG, addUserIdToLogMessage(mUserId, "Killing agent host process")); } mActivityManager.killApplicationProcess(app.processName, app.uid); } else { if (MORE_DEBUG) { Slog.d( TAG, addUserIdToLogMessage( mUserId, "Not killing after operation: " + app.processName)); } } } catch (RemoteException e) { Slog.d(TAG, addUserIdToLogMessage(mUserId, "Lost app trying to shut down")); } } // ----- Full-data backup scheduling ----- // ----- Full-data backup scheduling ----- /** /** Loading
services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -323,7 +323,8 @@ public class FullBackupEngine { private void tearDown() { private void tearDown() { if (mPkg != null) { if (mPkg != null) { backupManagerService.tearDownAgentAndKill(mPkg.applicationInfo); backupManagerService.getBackupAgentConnectionManager().unbindAgent( mPkg.applicationInfo, /* allowKill= */ true); } } } } } }
services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -503,7 +503,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor Slog.w(TAG, "adb backup cancel of " + target); Slog.w(TAG, "adb backup cancel of " + target); } } if (target != null) { if (target != null) { mUserBackupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo); mUserBackupManagerService.getBackupAgentConnectionManager().unbindAgent( target.applicationInfo, /* allowKill= */ true); } } mOperationStorage.removeOperation(mCurrentOpToken); mOperationStorage.removeOperation(mCurrentOpToken); } } Loading