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

Commit c943c241 authored by Sarp Misoglu's avatar Sarp Misoglu Committed by Android (Google) Code Review
Browse files

Merge "Don't kill apps if they are not in restricted mode" into main

parents e45a169b b87b9792
Loading
Loading
Loading
Loading
+74 −21
Original line number Original line Diff line number Diff line
@@ -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;
        }
        }
    }
    }


@@ -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
            }
            }
@@ -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
@@ -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,
@@ -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");
+2 −1
Original line number Original line Diff line number Diff line
@@ -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();
+0 −33
Original line number Original line Diff line number Diff line
@@ -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 -----


    /**
    /**
+2 −1
Original line number Original line Diff line number Diff line
@@ -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);
        }
        }
    }
    }
}
}
+2 −1
Original line number Original line Diff line number Diff line
@@ -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