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

Commit 3d325942 authored by Jiaming Liu's avatar Jiaming Liu
Browse files

Allow untrusted embedding for EMBED_ANY_APP_IN_UNTRUSTED_MODE

Bug: 289199433
Test: atest TaskFragmentTest
Change-Id: Idb8e13d0e9357960a9ca92a225e4e979222d2e69
parent 0cb06c72
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -899,6 +899,9 @@
    <!-- Permission required for Cts test - CtsNotificationTestCases -->
    <uses-permission android:name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" />

    <!-- Permission required for Cts test - CtsWindowManagerJetpackTestCases -->
    <uses-permission android:name="android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE" />

    <!-- Permission required for BinaryTransparencyService shell API and host test -->
    <uses-permission android:name="android.permission.GET_BACKGROUND_INSTALLED_PACKAGES" />

+13 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.Manifest.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE;
import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
@@ -725,6 +726,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {
            // TaskFragment to have bounds outside of the parent bounds.
            return false;
        }
        if (hasEmbedAnyAppInUntrustedModePermission(mTaskFragmentOrganizerUid)) {
            return true;
        }
        return (a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
                == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
    }
@@ -795,6 +799,15 @@ class TaskFragment extends WindowContainer<WindowContainer> {
                == PackageManager.PERMISSION_GRANTED;
    }

    /**
     * Checks if a particular app uid has the {@link EMBED_ANY_APP_IN_UNTRUSTED_MODE} permission.
     */
    private static boolean hasEmbedAnyAppInUntrustedModePermission(int uid) {
        return Flags.untrustedEmbeddingAnyAppPermission()
                && checkPermission(EMBED_ANY_APP_IN_UNTRUSTED_MODE,
                PermissionChecker.PID_UNKNOWN, uid) == PackageManager.PERMISSION_GRANTED;
    }

    /**
     * Checks if all activities in the task fragment are embedded as fully trusted.
     * @see #isFullyTrustedEmbedding(ActivityRecord, int)
+71 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.wm;

import static android.Manifest.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE;
import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -24,11 +26,14 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -65,12 +70,14 @@ import android.window.TaskFragmentOrganizer;
import androidx.test.filters.MediumTest;

import com.android.server.pm.pkg.AndroidPackage;
import com.android.window.flags.Flags;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;

import java.util.Collections;
import java.util.Set;
@@ -591,6 +598,70 @@ public class TaskFragmentTest extends WindowTestsBase {
                activity, hostPackage));
    }

    @Test
    public void testIsAllowedToBeEmbeddedInTrustedMode_withManageActivityTasksPermission() {
        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
                .setCreateParentTask()
                .createActivityCount(1)
                .build();
        final ActivityRecord activity = taskFragment.getTopMostActivity();

        // Not allow embedding activity if not a trusted host.
        assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
                taskFragment.isAllowedToEmbedActivity(activity));

        MockitoSession session =
                mockitoSession().spyStatic(ActivityTaskManagerService.class).startMocking();
        try {
            doReturn(PERMISSION_GRANTED).when(() -> {
                return ActivityTaskManagerService.checkPermission(
                        eq(MANAGE_ACTIVITY_TASKS), anyInt(), anyInt());
            });
            // With the MANAGE_ACTIVITY_TASKS permission, trusted embedding is always allowed.
            assertTrue(taskFragment.isAllowedToBeEmbeddedInTrustedMode());
        } finally {
            session.finishMocking();
        }
    }

    @Test
    public void testIsAllowedToEmbedActivityInUntrustedMode_withUntrustedEmbeddingAnyAppPermission(
    ) {
        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
                .setCreateParentTask()
                .createActivityCount(1)
                .build();
        final ActivityRecord activity = taskFragment.getTopMostActivity();

        // Not allow embedding activity if not a trusted host.
        assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
                taskFragment.isAllowedToEmbedActivity(activity));

        MockitoSession session =
                mockitoSession()
                        .spyStatic(ActivityTaskManagerService.class)
                        .spyStatic(Flags.class)
                        .startMocking();
        try {
            doReturn(PERMISSION_GRANTED).when(() -> {
                return ActivityTaskManagerService.checkPermission(
                        eq(EMBED_ANY_APP_IN_UNTRUSTED_MODE), anyInt(), anyInt());
            });
            // With the EMBED_ANY_APP_IN_UNTRUSTED_MODE permission, untrusted embedding is always
            // allowed, but it doesn't always allow trusted embedding.
            doReturn(true).when(() -> Flags.untrustedEmbeddingAnyAppPermission());
            assertTrue(taskFragment.isAllowedToEmbedActivityInUntrustedMode(activity));
            assertFalse(taskFragment.isAllowedToEmbedActivityInTrustedMode(activity));

            // If the flag is disabled, the permission doesn't have effect.
            doReturn(false).when(() -> Flags.untrustedEmbeddingAnyAppPermission());
            assertFalse(taskFragment.isAllowedToEmbedActivityInUntrustedMode(activity));
            assertFalse(taskFragment.isAllowedToEmbedActivityInTrustedMode(activity));
        } finally {
            session.finishMocking();
        }
    }

    @Test
    public void testIgnoreRequestedOrientationForActivityEmbeddingSplit() {
        // Setup two activities in ActivityEmbedding split.