Loading services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +16 −3 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; Loading Loading @@ -322,9 +323,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr + " is not in a task belong to the organizer app."); return null; } if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED) { if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED || !task.isAllowedToEmbedActivityInTrustedMode(activity, mOrganizerUid)) { Slog.d(TAG, "Reparent activity=" + activity.token + " is not allowed to be embedded."); + " is not allowed to be embedded in trusted mode."); return null; } Loading @@ -350,7 +352,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr activity.token, task.mTaskId); return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK) .setTaskId(task.mTaskId) .setActivityIntent(activity.intent) .setActivityIntent(trimIntent(activity.intent)) .setActivityToken(activityToken); } Loading Loading @@ -1095,4 +1097,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return false; } } /** * Trims the given Intent to only those that are needed to for embedding rules. This helps to * make it safer for cross-uid embedding even if we only send the Intent for trusted embedding. */ private static Intent trimIntent(@NonNull Intent intent) { return new Intent() .setComponent(intent.getComponent()) .setPackage(intent.getPackage()) .setAction(intent.getAction()); } } services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +74 −2 Original line number Diff line number Diff line Loading @@ -62,10 +62,12 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; Loading Loading @@ -403,7 +405,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { final TaskFragmentTransaction.Change change = changes.get(0); assertEquals(TYPE_ACTIVITY_REPARENTED_TO_TASK, change.getType()); assertEquals(task.mTaskId, change.getTaskId()); assertEquals(activity.intent, change.getActivityIntent()); assertIntentsEqualForOrganizer(activity.intent, change.getActivityIntent()); assertNotEquals(activity.token, change.getActivityToken()); mTransaction.reparentActivityToTaskFragment(mFragmentToken, change.getActivityToken()); assertApplyTransactionAllowed(mTransaction); Loading @@ -414,6 +416,62 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { change.getActivityToken())); } @Test public void testOnActivityReparentedToTask_untrustedEmbed_notReported() { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid, DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME); mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment); final Task task = createTask(mDisplayContent); task.addChild(mTaskFragment, POSITION_TOP); final ActivityRecord activity = createActivityRecord(task); // Make sure the activity is embedded in untrusted mode. activity.info.applicationInfo.uid = uid + 1; doReturn(pid + 1).when(activity).getPid(); task.effectiveUid = uid; doReturn(EMBEDDING_ALLOWED).when(task).isAllowedToEmbedActivity(activity, uid); doReturn(false).when(task).isAllowedToEmbedActivityInTrustedMode(activity, uid); doReturn(true).when(task).isAllowedToEmbedActivityInUntrustedMode(activity); // Notify organizer if it was embedded before entered Pip. // Create a temporary token since the activity doesn't belong to the same process. clearInvocations(mOrganizer); activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer; mController.onActivityReparentedToTask(activity); mController.dispatchPendingEvents(); // Disallow organizer to reparent activity that is untrusted embedded. verify(mOrganizer, never()).onTransactionReady(mTransactionCaptor.capture()); } @Test public void testOnActivityReparentedToTask_trimReportedIntent() { // Make sure the activity pid/uid is the same as the organizer caller. final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final ActivityRecord activity = createActivityRecord(mDisplayContent); final Task task = activity.getTask(); activity.info.applicationInfo.uid = uid; doReturn(pid).when(activity).getPid(); task.effectiveUid = uid; activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer; // Test the Intent trim in #assertIntentTrimmed activity.intent.setComponent(new ComponentName("TestPackage", "TestClass")) .setPackage("TestPackage") .setAction("TestAction") .setData(mock(Uri.class)) .putExtra("Test", 123) .setFlags(10); mController.onActivityReparentedToTask(activity); mController.dispatchPendingEvents(); assertActivityReparentedToTaskTransaction(task.mTaskId, activity.intent, activity.token); } @Test public void testRegisterRemoteAnimations() { mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition); Loading Loading @@ -1425,7 +1483,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { final TaskFragmentTransaction.Change change = changes.remove(0); assertEquals(TYPE_ACTIVITY_REPARENTED_TO_TASK, change.getType()); assertEquals(taskId, change.getTaskId()); assertEquals(intent, change.getActivityIntent()); assertIntentsEqualForOrganizer(intent, change.getActivityIntent()); assertIntentTrimmed(change.getActivityIntent()); assertEquals(activityToken, change.getActivityToken()); } Loading @@ -1452,4 +1511,17 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mockParent.lastActiveTime = 100; doReturn(true).when(mockParent).shouldBeVisible(any()); } private static void assertIntentsEqualForOrganizer(@NonNull Intent expected, @NonNull Intent actual) { assertEquals(expected.getComponent(), actual.getComponent()); assertEquals(expected.getPackage(), actual.getPackage()); assertEquals(expected.getAction(), actual.getAction()); } private static void assertIntentTrimmed(@NonNull Intent intent) { assertNull(intent.getData()); assertNull(intent.getExtras()); assertEquals(0, intent.getFlags()); } } Loading
services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +16 −3 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; Loading Loading @@ -322,9 +323,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr + " is not in a task belong to the organizer app."); return null; } if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED) { if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED || !task.isAllowedToEmbedActivityInTrustedMode(activity, mOrganizerUid)) { Slog.d(TAG, "Reparent activity=" + activity.token + " is not allowed to be embedded."); + " is not allowed to be embedded in trusted mode."); return null; } Loading @@ -350,7 +352,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr activity.token, task.mTaskId); return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK) .setTaskId(task.mTaskId) .setActivityIntent(activity.intent) .setActivityIntent(trimIntent(activity.intent)) .setActivityToken(activityToken); } Loading Loading @@ -1095,4 +1097,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return false; } } /** * Trims the given Intent to only those that are needed to for embedding rules. This helps to * make it safer for cross-uid embedding even if we only send the Intent for trusted embedding. */ private static Intent trimIntent(@NonNull Intent intent) { return new Intent() .setComponent(intent.getComponent()) .setPackage(intent.getPackage()) .setAction(intent.getAction()); } }
services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +74 −2 Original line number Diff line number Diff line Loading @@ -62,10 +62,12 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; Loading Loading @@ -403,7 +405,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { final TaskFragmentTransaction.Change change = changes.get(0); assertEquals(TYPE_ACTIVITY_REPARENTED_TO_TASK, change.getType()); assertEquals(task.mTaskId, change.getTaskId()); assertEquals(activity.intent, change.getActivityIntent()); assertIntentsEqualForOrganizer(activity.intent, change.getActivityIntent()); assertNotEquals(activity.token, change.getActivityToken()); mTransaction.reparentActivityToTaskFragment(mFragmentToken, change.getActivityToken()); assertApplyTransactionAllowed(mTransaction); Loading @@ -414,6 +416,62 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { change.getActivityToken())); } @Test public void testOnActivityReparentedToTask_untrustedEmbed_notReported() { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid, DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME); mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment); final Task task = createTask(mDisplayContent); task.addChild(mTaskFragment, POSITION_TOP); final ActivityRecord activity = createActivityRecord(task); // Make sure the activity is embedded in untrusted mode. activity.info.applicationInfo.uid = uid + 1; doReturn(pid + 1).when(activity).getPid(); task.effectiveUid = uid; doReturn(EMBEDDING_ALLOWED).when(task).isAllowedToEmbedActivity(activity, uid); doReturn(false).when(task).isAllowedToEmbedActivityInTrustedMode(activity, uid); doReturn(true).when(task).isAllowedToEmbedActivityInUntrustedMode(activity); // Notify organizer if it was embedded before entered Pip. // Create a temporary token since the activity doesn't belong to the same process. clearInvocations(mOrganizer); activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer; mController.onActivityReparentedToTask(activity); mController.dispatchPendingEvents(); // Disallow organizer to reparent activity that is untrusted embedded. verify(mOrganizer, never()).onTransactionReady(mTransactionCaptor.capture()); } @Test public void testOnActivityReparentedToTask_trimReportedIntent() { // Make sure the activity pid/uid is the same as the organizer caller. final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final ActivityRecord activity = createActivityRecord(mDisplayContent); final Task task = activity.getTask(); activity.info.applicationInfo.uid = uid; doReturn(pid).when(activity).getPid(); task.effectiveUid = uid; activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer; // Test the Intent trim in #assertIntentTrimmed activity.intent.setComponent(new ComponentName("TestPackage", "TestClass")) .setPackage("TestPackage") .setAction("TestAction") .setData(mock(Uri.class)) .putExtra("Test", 123) .setFlags(10); mController.onActivityReparentedToTask(activity); mController.dispatchPendingEvents(); assertActivityReparentedToTaskTransaction(task.mTaskId, activity.intent, activity.token); } @Test public void testRegisterRemoteAnimations() { mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition); Loading Loading @@ -1425,7 +1483,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { final TaskFragmentTransaction.Change change = changes.remove(0); assertEquals(TYPE_ACTIVITY_REPARENTED_TO_TASK, change.getType()); assertEquals(taskId, change.getTaskId()); assertEquals(intent, change.getActivityIntent()); assertIntentsEqualForOrganizer(intent, change.getActivityIntent()); assertIntentTrimmed(change.getActivityIntent()); assertEquals(activityToken, change.getActivityToken()); } Loading @@ -1452,4 +1511,17 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mockParent.lastActiveTime = 100; doReturn(true).when(mockParent).shouldBeVisible(any()); } private static void assertIntentsEqualForOrganizer(@NonNull Intent expected, @NonNull Intent actual) { assertEquals(expected.getComponent(), actual.getComponent()); assertEquals(expected.getPackage(), actual.getPackage()); assertEquals(expected.getAction(), actual.getAction()); } private static void assertIntentTrimmed(@NonNull Intent intent) { assertNull(intent.getData()); assertNull(intent.getExtras()); assertEquals(0, intent.getFlags()); } }