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

Commit f2c23a11 authored by Charles Chen's avatar Charles Chen
Browse files

Forward the TaskFragment info in IntentSender

... so that the original intent can be launched on
the original target TaskFragment.

Bug: 233578672
Test: atest ActivityStarterInterceptorTest
Change-Id: Iac9afb24d3df53fb6c667728ad39c93afa2ed21a
parent b4bf0a85
Loading
Loading
Loading
Loading
+48 −4
Original line number Original line Diff line number Diff line
@@ -49,6 +49,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
@@ -64,7 +65,7 @@ import com.android.server.am.ActivityManagerService;
import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult;
import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult;


/**
/**
 * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
 * A class that contains activity intercepting logic for {@link ActivityStarter#execute()}
 * It's initialized via setStates and interception occurs via the intercept method.
 * It's initialized via setStates and interception occurs via the intercept method.
 *
 *
 * Note that this class is instantiated when {@link ActivityManagerService} gets created so there
 * Note that this class is instantiated when {@link ActivityManagerService} gets created so there
@@ -104,6 +105,7 @@ class ActivityStartInterceptor {
    ActivityInfo mAInfo;
    ActivityInfo mAInfo;
    String mResolvedType;
    String mResolvedType;
    Task mInTask;
    Task mInTask;
    TaskFragment mInTaskFragment;
    ActivityOptions mActivityOptions;
    ActivityOptions mActivityOptions;


    ActivityStartInterceptor(
    ActivityStartInterceptor(
@@ -135,15 +137,46 @@ class ActivityStartInterceptor {
    }
    }


    private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
    private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
        Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary();
        Bundle bOptions = deferCrossProfileAppsAnimationIfNecessary();
        final TaskFragment taskFragment = getLaunchTaskFragment();
        // If the original intent is going to be embedded, try to forward the embedding TaskFragment
        // and its task id to embed back the original intent.
        if (taskFragment != null) {
            ActivityOptions activityOptions = bOptions != null
                    ? ActivityOptions.fromBundle(bOptions)
                    : ActivityOptions.makeBasic();
            activityOptions.setLaunchTaskFragmentToken(taskFragment.getFragmentToken());
            bOptions = activityOptions.toBundle();
        }
        final IIntentSender target = mService.getIntentSenderLocked(
        final IIntentSender target = mService.getIntentSenderLocked(
                INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingFeatureId, callingUid, mUserId,
                INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingFeatureId, callingUid, mUserId,
                null /*token*/, null /*resultCode*/, 0 /*requestCode*/,
                null /*token*/, null /*resultCode*/, 0 /*requestCode*/,
                new Intent[] { mIntent }, new String[] { mResolvedType },
                new Intent[] { mIntent }, new String[] { mResolvedType },
                flags, activityOptions);
                flags, bOptions);
        return new IntentSender(target);
        return new IntentSender(target);
    }
    }



    /**
     * A helper function to obtain the targeted {@link TaskFragment} during
     * {@link #intercept(Intent, ResolveInfo, ActivityInfo, String, Task, TaskFragment, int, int,
     * ActivityOptions)} if any.
     */
    @Nullable
    private TaskFragment getLaunchTaskFragment() {
        if (mInTaskFragment != null) {
            return mInTaskFragment;
        }
        if (mActivityOptions == null) {
            return null;
        }
        final IBinder taskFragToken = mActivityOptions.getLaunchTaskFragmentToken();
        if (taskFragToken == null) {
            return null;
        }
        return TaskFragment.fromTaskFragmentToken(taskFragToken, mService);
    }

    /**
    /**
     * Intercept the launch intent based on various signals. If an interception happened the
     * Intercept the launch intent based on various signals. If an interception happened the
     * internal variables get assigned and need to be read explicitly by the caller.
     * internal variables get assigned and need to be read explicitly by the caller.
@@ -151,7 +184,8 @@ class ActivityStartInterceptor {
     * @return true if an interception occurred
     * @return true if an interception occurred
     */
     */
    boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
    boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
            Task inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
            Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid,
            ActivityOptions activityOptions) {
        mUserManager = UserManager.get(mServiceContext);
        mUserManager = UserManager.get(mServiceContext);


        mIntent = intent;
        mIntent = intent;
@@ -161,6 +195,7 @@ class ActivityStartInterceptor {
        mAInfo = aInfo;
        mAInfo = aInfo;
        mResolvedType = resolvedType;
        mResolvedType = resolvedType;
        mInTask = inTask;
        mInTask = inTask;
        mInTaskFragment = inTaskFragment;
        mActivityOptions = activityOptions;
        mActivityOptions = activityOptions;


        if (interceptQuietProfileIfNeeded()) {
        if (interceptQuietProfileIfNeeded()) {
@@ -332,12 +367,21 @@ class ActivityStartInterceptor {
        mCallingPid = mRealCallingPid;
        mCallingPid = mRealCallingPid;
        mCallingUid = mRealCallingUid;
        mCallingUid = mRealCallingUid;
        mResolvedType = null;
        mResolvedType = null;
        final TaskFragment taskFragment = getLaunchTaskFragment();
        // If we are intercepting and there was a task, convert it into an extra for the
        // If we are intercepting and there was a task, convert it into an extra for the
        // ConfirmCredentials intent and unassign it, as otherwise the task will move to
        // ConfirmCredentials intent and unassign it, as otherwise the task will move to
        // front even if ConfirmCredentials is cancelled.
        // front even if ConfirmCredentials is cancelled.
        if (mInTask != null) {
        if (mInTask != null) {
            mIntent.putExtra(EXTRA_TASK_ID, mInTask.mTaskId);
            mIntent.putExtra(EXTRA_TASK_ID, mInTask.mTaskId);
            mInTask = null;
            mInTask = null;
        } else if (taskFragment != null) {
            // If the original intent is started to an embedded TaskFragment, append its parent task
            // id to extra. It is to embed back the original intent to the TaskFragment with the
            // same task.
            final Task parentTask = taskFragment.getTask();
            if (parentTask != null) {
                mIntent.putExtra(EXTRA_TASK_ID, parentTask.mTaskId);
            }
        }
        }
        if (mActivityOptions == null) {
        if (mActivityOptions == null) {
            mActivityOptions = ActivityOptions.makeBasic();
            mActivityOptions = ActivityOptions.makeBasic();
+2 −2
Original line number Original line Diff line number Diff line
@@ -1060,8 +1060,8 @@ class ActivityStarter {


        mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
        mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
                callingFeatureId);
                callingFeatureId);
        if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid,
        if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment,
                callingUid, checkedOptions)) {
                callingPid, callingUid, checkedOptions)) {
            // activity start was intercepted, e.g. because the target user is currently in quiet
            // activity start was intercepted, e.g. because the target user is currently in quiet
            // mode (turn off work) or the target application is suspended
            // mode (turn off work) or the target application is suspended
            intent = mInterceptor.mIntent;
            intent = mInterceptor.mIntent;
+11 −11
Original line number Original line Diff line number Diff line
@@ -192,7 +192,7 @@ public class ActivityStartInterceptorTest {
                .thenReturn(PLATFORM_PACKAGE_NAME);
                .thenReturn(PLATFORM_PACKAGE_NAME);


        // THEN calling intercept returns true
        // THEN calling intercept returns true
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));


        // THEN the returned intent is the admin support intent
        // THEN the returned intent is the admin support intent
        assertEquals(ADMIN_SUPPORT_INTENT, mInterceptor.mIntent);
        assertEquals(ADMIN_SUPPORT_INTENT, mInterceptor.mIntent);
@@ -203,7 +203,7 @@ public class ActivityStartInterceptorTest {
        final String suspendingPackage = "com.test.suspending.package";
        final String suspendingPackage = "com.test.suspending.package";
        final SuspendDialogInfo dialogInfo = suspendPackage(suspendingPackage);
        final SuspendDialogInfo dialogInfo = suspendPackage(suspendingPackage);
        // THEN calling intercept returns true
        // THEN calling intercept returns true
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));


        // Check intent parameters
        // Check intent parameters
        assertEquals(dialogInfo,
        assertEquals(dialogInfo,
@@ -234,7 +234,7 @@ public class ActivityStartInterceptorTest {
                TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT))
                TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT))
                .thenReturn(false);
                .thenReturn(false);


        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));


        assertTrue(BlockedAppActivity.createIntent(TEST_USER_ID, TEST_PACKAGE_NAME)
        assertTrue(BlockedAppActivity.createIntent(TEST_USER_ID, TEST_PACKAGE_NAME)
                .filterEquals(mInterceptor.mIntent));
                .filterEquals(mInterceptor.mIntent));
@@ -246,7 +246,7 @@ public class ActivityStartInterceptorTest {
        when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);
        when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);


        // THEN calling intercept returns true
        // THEN calling intercept returns true
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null,  null, 0, 0, null));


        // THEN the returned intent is the quiet mode intent
        // THEN the returned intent is the quiet mode intent
        assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
        assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
@@ -260,7 +260,7 @@ public class ActivityStartInterceptorTest {
        when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);
        when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);


        // THEN calling intercept returns true
        // THEN calling intercept returns true
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));


        // THEN the returned intent is the quiet mode intent
        // THEN the returned intent is the quiet mode intent
        assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
        assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
@@ -273,7 +273,7 @@ public class ActivityStartInterceptorTest {
        when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true);
        when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true);


        // THEN calling intercept returns true
        // THEN calling intercept returns true
        mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null);
        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);


        // THEN the returned intent is the quiet mode intent
        // THEN the returned intent is the quiet mode intent
        assertTrue(CONFIRM_CREDENTIALS_INTENT.filterEquals(mInterceptor.mIntent));
        assertTrue(CONFIRM_CREDENTIALS_INTENT.filterEquals(mInterceptor.mIntent));
@@ -286,7 +286,7 @@ public class ActivityStartInterceptorTest {
                .thenReturn("This app is bad");
                .thenReturn("This app is bad");


        // THEN calling intercept returns true
        // THEN calling intercept returns true
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));


        // THEN the returned intent is the harmful app warning intent
        // THEN the returned intent is the harmful app warning intent
        assertEquals(HarmfulAppWarningActivity.class.getName(),
        assertEquals(HarmfulAppWarningActivity.class.getName(),
@@ -298,7 +298,7 @@ public class ActivityStartInterceptorTest {
        // GIVEN that none of the interception conditions are met
        // GIVEN that none of the interception conditions are met


        // THEN calling intercept returns false
        // THEN calling intercept returns false
        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
    }
    }


    public void addMockInterceptorCallback(
    public void addMockInterceptorCallback(
@@ -323,7 +323,7 @@ public class ActivityStartInterceptorTest {
                new Intent("android.test.foo"),
                new Intent("android.test.foo"),
                ActivityOptions.makeBasic().setLaunchDisplayId(3));
                ActivityOptions.makeBasic().setLaunchDisplayId(3));


        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
        assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
        assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
        assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
        assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
    }
    }
@@ -332,7 +332,7 @@ public class ActivityStartInterceptorTest {
    public void testInterceptionCallback_singleCallbackReturnsNull() {
    public void testInterceptionCallback_singleCallbackReturnsNull() {
        addMockInterceptorCallback(null, null);
        addMockInterceptorCallback(null, null);


        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
    }
    }


    @Test
    @Test
@@ -340,7 +340,7 @@ public class ActivityStartInterceptorTest {
        addMockInterceptorCallback(null, null);
        addMockInterceptorCallback(null, null);
        addMockInterceptorCallback(new Intent("android.test.second"), null);
        addMockInterceptorCallback(new Intent("android.test.second"), null);


        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
        assertEquals("android.test.second", mInterceptor.mIntent.getAction());
        assertEquals("android.test.second", mInterceptor.mIntent.getAction());
    }
    }