Merge "Fix exception when opening App info on work profile" into tm-dev am: 9b6a9578a1

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18989968

Change-Id: I388deec6b843c8b38299ba656cc8ff7cbcdb4462
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Charles Chen
2022-07-07 02:16:18 +00:00
committed by Automerger Merge Worker
6 changed files with 180 additions and 56 deletions

View File

@@ -78,6 +78,10 @@ import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT; import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.POSITION_TOP;
import android.annotation.NonNull; import android.annotation.NonNull;
@@ -131,6 +135,7 @@ import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.NeededUriGrants; import com.android.server.uri.NeededUriGrants;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState; import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.LaunchParamsController.LaunchParams; import com.android.server.wm.LaunchParamsController.LaunchParams;
import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.text.DateFormat; import java.text.DateFormat;
@@ -2038,12 +2043,6 @@ class ActivityStarter {
} }
} }
if (mInTaskFragment != null && !canEmbedActivity(mInTaskFragment, r, newTask, targetTask)) {
Slog.e(TAG, "Permission denied: Cannot embed " + r + " to " + mInTaskFragment.getTask()
+ " targetTask= " + targetTask);
return START_PERMISSION_DENIED;
}
// Do not start the activity if target display's DWPC does not allow it. // Do not start the activity if target display's DWPC does not allow it.
// We can't return fatal error code here because it will crash the caller of // We can't return fatal error code here because it will crash the caller of
// startActivity() if they don't catch the exception. We don't expect 3P apps to make // startActivity() if they don't catch the exception. We don't expect 3P apps to make
@@ -2070,19 +2069,21 @@ class ActivityStarter {
} }
/** /**
* Return {@code true} if an activity can be embedded to the TaskFragment. * Returns whether embedding of {@code starting} is allowed.
*
* @param taskFragment the TaskFragment for embedding. * @param taskFragment the TaskFragment for embedding.
* @param starting the starting activity. * @param starting the starting activity.
* @param newTask whether the starting activity is going to be launched on a new task.
* @param targetTask the target task for launching activity, which could be different from * @param targetTask the target task for launching activity, which could be different from
* the one who hosting the embedding. * the one who hosting the embedding.
*/ */
private boolean canEmbedActivity(@NonNull TaskFragment taskFragment, @VisibleForTesting
@NonNull ActivityRecord starting, boolean newTask, Task targetTask) { @EmbeddingCheckResult
static int canEmbedActivity(@NonNull TaskFragment taskFragment,
@NonNull ActivityRecord starting, @NonNull Task targetTask) {
final Task hostTask = taskFragment.getTask(); final Task hostTask = taskFragment.getTask();
// Not allowed embedding a separate task or without host task. // Not allowed embedding a separate task or without host task.
if (hostTask == null || newTask || targetTask != hostTask) { if (hostTask == null || targetTask != hostTask) {
return false; return EMBEDDING_DISALLOWED_NEW_TASK;
} }
return taskFragment.isAllowedToEmbedActivity(starting); return taskFragment.isAllowedToEmbedActivity(starting);
@@ -2894,19 +2895,16 @@ class ActivityStarter {
mIntentDelivered = true; mIntentDelivered = true;
} }
/** Places {@link #mStartActivity} in {@code task} or an embedded {@link TaskFragment}. */
private void addOrReparentStartingActivity(@NonNull Task task, String reason) { private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
TaskFragment newParent = task; TaskFragment newParent = task;
if (mInTaskFragment != null) { if (mInTaskFragment != null) {
// TODO(b/234351413): remove remaining embedded Task logic. int embeddingCheckResult = canEmbedActivity(mInTaskFragment, mStartActivity, task);
// mInTaskFragment is created and added to the leaf task by task fragment organizer's if (embeddingCheckResult == EMBEDDING_ALLOWED) {
// request. If the task was resolved and different than mInTaskFragment, reparent the
// task to mInTaskFragment for embedding.
if (mInTaskFragment.getTask() != task) {
if (shouldReparentInTaskFragment(task)) {
task.reparent(mInTaskFragment, POSITION_TOP);
}
} else {
newParent = mInTaskFragment; newParent = mInTaskFragment;
} else {
// Start mStartActivity to task instead if it can't be embedded to mInTaskFragment.
sendCanNotEmbedActivityError(mInTaskFragment, embeddingCheckResult);
} }
} else { } else {
TaskFragment candidateTf = mAddingToTaskFragment != null ? mAddingToTaskFragment : null; TaskFragment candidateTf = mAddingToTaskFragment != null ? mAddingToTaskFragment : null;
@@ -2918,20 +2916,12 @@ class ActivityStarter {
} }
} }
if (candidateTf != null && candidateTf.isEmbedded() if (candidateTf != null && candidateTf.isEmbedded()
&& canEmbedActivity(candidateTf, mStartActivity, false /* newTask */, task)) { && canEmbedActivity(candidateTf, mStartActivity, task) == EMBEDDING_ALLOWED) {
// Use the embedded TaskFragment of the top activity as the new parent if the // Use the embedded TaskFragment of the top activity as the new parent if the
// activity can be embedded. // activity can be embedded.
newParent = candidateTf; newParent = candidateTf;
} }
} }
// Start Activity to the Task if mStartActivity's min dimensions are not satisfied.
if (newParent.isEmbedded() && newParent.smallerThanMinDimension(mStartActivity)) {
reason += " - MinimumDimensionViolation";
mService.mWindowOrganizerController.sendMinimumDimensionViolation(
newParent, mStartActivity.getMinDimensions(), mRequest.errorCallbackToken,
reason);
newParent = task;
}
if (mStartActivity.getTaskFragment() == null if (mStartActivity.getTaskFragment() == null
|| mStartActivity.getTaskFragment() == newParent) { || mStartActivity.getTaskFragment() == newParent) {
newParent.addChild(mStartActivity, POSITION_TOP); newParent.addChild(mStartActivity, POSITION_TOP);
@@ -2940,16 +2930,41 @@ class ActivityStarter {
} }
} }
private boolean shouldReparentInTaskFragment(Task task) { /**
// The task has not been embedded. We should reparent the task to TaskFragment. * Notifies the client side that {@link #mStartActivity} cannot be embedded to
if (!task.isEmbedded()) { * {@code taskFragment}.
return true; */
private void sendCanNotEmbedActivityError(TaskFragment taskFragment,
@EmbeddingCheckResult int result) {
final String errMsg;
switch(result) {
case EMBEDDING_DISALLOWED_NEW_TASK: {
errMsg = "Cannot embed " + mStartActivity + " that launched on another task"
+ ",mLaunchMode=" + mLaunchMode
+ ",mLaunchFlag=" + Integer.toHexString(mLaunchFlags);
break;
}
case EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION: {
errMsg = "Cannot embed " + mStartActivity
+ ". TaskFragment's bounds:" + taskFragment.getBounds()
+ ", minimum dimensions:" + mStartActivity.getMinDimensions();
break;
}
case EMBEDDING_DISALLOWED_UNTRUSTED_HOST: {
errMsg = "The app:" + mCallingUid + "is not trusted to " + mStartActivity;
break;
}
default:
errMsg = "Unhandled embed result:" + result;
}
if (taskFragment.isOrganized()) {
mService.mWindowOrganizerController.sendTaskFragmentOperationFailure(
taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken,
new SecurityException(errMsg));
} else {
// If the taskFragment is not organized, just dump error message as warning logs.
Slog.w(TAG, errMsg);
} }
WindowContainer<?> parent = task.getParent();
// If the Activity is going to launch on top of embedded Task in the same TaskFragment,
// we don't need to reparent the Task. Otherwise, the embedded Task should reparent to
// another TaskFragment.
return parent.asTaskFragment() != mInTaskFragment;
} }
private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance, private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,

View File

@@ -139,6 +139,45 @@ class TaskFragment extends WindowContainer<WindowContainer> {
/** Set to false to disable the preview that is shown while a new activity is being started. */ /** Set to false to disable the preview that is shown while a new activity is being started. */
static final boolean SHOW_APP_STARTING_PREVIEW = true; static final boolean SHOW_APP_STARTING_PREVIEW = true;
/**
* An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
* indicate that an Activity can be embedded successfully.
*/
static final int EMBEDDING_ALLOWED = 0;
/**
* An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
* indicate that an Activity can't be embedded because either the Activity does not allow
* untrusted embedding, and the embedding host app is not trusted.
*/
static final int EMBEDDING_DISALLOWED_UNTRUSTED_HOST = 1;
/**
* An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
* indicate that an Activity can't be embedded because this taskFragment's bounds are
* {@link #smallerThanMinDimension(ActivityRecord)}.
*/
static final int EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION = 2;
/**
* An embedding check result of
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
* indicate that an Activity can't be embedded because the Activity is started on a new task.
*/
static final int EMBEDDING_DISALLOWED_NEW_TASK = 3;
/**
* Embedding check results of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}.
*/
@IntDef(prefix = {"EMBEDDING_"}, value = {
EMBEDDING_ALLOWED,
EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
EMBEDDING_DISALLOWED_NEW_TASK,
})
@interface EmbeddingCheckResult {}
/** /**
* Indicate that the minimal width/height should use the default value. * Indicate that the minimal width/height should use the default value.
* *
@@ -520,20 +559,29 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return false; return false;
} }
boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a) { @EmbeddingCheckResult
int isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
return isAllowedToEmbedActivity(a, mTaskFragmentOrganizerUid); return isAllowedToEmbedActivity(a, mTaskFragmentOrganizerUid);
} }
/** /**
* Checks if the organized task fragment is allowed to have the specified activity, which is * Checks if the organized task fragment is allowed to have the specified activity, which is
* allowed if an activity allows embedding in untrusted mode, or if the trusted mode can be * allowed if an activity allows embedding in untrusted mode, if the trusted mode can be
* enabled. * enabled, or if the organized task fragment bounds are not
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord) * {@link #smallerThanMinDimension(ActivityRecord)}.
*
* @param uid uid of the TaskFragment organizer. * @param uid uid of the TaskFragment organizer.
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
*/ */
boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a, int uid) { @EmbeddingCheckResult
return isAllowedToEmbedActivityInUntrustedMode(a) int isAllowedToEmbedActivity(@NonNull ActivityRecord a, int uid) {
|| isAllowedToEmbedActivityInTrustedMode(a, uid); if (!isAllowedToEmbedActivityInUntrustedMode(a)
&& !isAllowedToEmbedActivityInTrustedMode(a, uid)) {
return EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
} else if (smallerThanMinDimension(a)) {
return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
}
return EMBEDDING_ALLOWED;
} }
boolean smallerThanMinDimension(@NonNull ActivityRecord activity) { boolean smallerThanMinDimension(@NonNull ActivityRecord activity) {
@@ -550,9 +598,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
} }
final int minWidth = minDimensions.x; final int minWidth = minDimensions.x;
final int minHeight = minDimensions.y; final int minHeight = minDimensions.y;
final boolean smaller = taskFragBounds.width() < minWidth return taskFragBounds.width() < minWidth
|| taskFragBounds.height() < minHeight; || taskFragBounds.height() < minHeight;
return smaller;
} }
/** /**
@@ -609,7 +656,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// The system is trusted to embed other apps securely and for all users. // The system is trusted to embed other apps securely and for all users.
return UserHandle.getAppId(uid) == SYSTEM_UID return UserHandle.getAppId(uid) == SYSTEM_UID
// Activities from the same UID can be embedded freely by the host. // Activities from the same UID can be embedded freely by the host.
|| uid == a.getUid(); || a.isUid(uid);
} }
/** /**

View File

@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.window.TaskFragmentOrganizer.putExceptionInBundle; import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer; import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
import android.annotation.IntDef; import android.annotation.IntDef;
@@ -235,7 +236,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
+ " is not in a task belong to the organizer app."); + " is not in a task belong to the organizer app.");
return; return;
} }
if (!task.isAllowedToEmbedActivity(activity, mOrganizerUid)) { if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED) {
Slog.d(TAG, "Reparent activity=" + activity.token Slog.d(TAG, "Reparent activity=" + activity.token
+ " is not allowed to be embedded."); + " is not allowed to be embedded.");
return; return;

View File

@@ -44,6 +44,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANI
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED; import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -756,7 +757,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break; break;
} }
if (!parent.isAllowedToEmbedActivity(activity)) { if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) {
final Throwable exception = new SecurityException( final Throwable exception = new SecurityException(
"The task fragment is not trusted to embed the given activity."); "The task fragment is not trusted to embed the given activity.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
@@ -988,7 +989,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
} }
/** A helper method to send minimum dimension violation error to the client. */ /** A helper method to send minimum dimension violation error to the client. */
void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions, private void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions,
IBinder errorCallbackToken, String reason) { IBinder errorCallbackToken, String reason) {
if (taskFragment == null || taskFragment.getTaskFragmentOrganizer() == null) { if (taskFragment == null || taskFragment.getTaskFragmentOrganizer() == null) {
return; return;
@@ -1582,7 +1583,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// We are reparenting activities to a new embedded TaskFragment, this operation is only // We are reparenting activities to a new embedded TaskFragment, this operation is only
// allowed if the new parent is trusted by all reparent activities. // allowed if the new parent is trusted by all reparent activities.
final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity -> final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity ->
!newParentTF.isAllowedToEmbedActivity(activity)); newParentTF.isAllowedToEmbedActivity(activity) == EMBEDDING_ALLOWED);
if (isEmbeddingDisallowed) { if (isEmbeddingDisallowed) {
final Throwable exception = new SecurityException( final Throwable exception = new SecurityException(
"The new parent is not trusted to embed the activities."); "The new parent is not trusted to embed the activities.");

View File

@@ -37,6 +37,7 @@ import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED; import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -52,6 +53,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityStarter.canEmbedActivity;
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -59,6 +65,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -87,6 +94,7 @@ import android.os.RemoteException;
import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit;
import android.service.voice.IVoiceInteractionSession; import android.service.voice.IVoiceInteractionSession;
import android.util.Pair; import android.util.Pair;
import android.util.Size;
import android.view.Gravity; import android.view.Gravity;
import android.window.TaskFragmentOrganizerToken; import android.window.TaskFragmentOrganizerToken;
@@ -1172,6 +1180,7 @@ public class ActivityStarterTests extends WindowTestsBase {
null /* inTask */, taskFragment); null /* inTask */, taskFragment);
assertFalse(taskFragment.hasChild()); assertFalse(taskFragment.hasChild());
assertNotNull("Target record must be started on Task.", targetRecord.getParent().asTask());
} }
@Test @Test
@@ -1342,6 +1351,58 @@ public class ActivityStarterTests extends WindowTestsBase {
any()); any());
} }
@Test
public void testCanEmbedActivity() {
final Size minDimensions = new Size(1000, 1000);
final WindowLayout windowLayout = new WindowLayout(0, 0, 0, 0, 0,
minDimensions.getWidth(), minDimensions.getHeight());
final ActivityRecord starting = new ActivityBuilder(mAtm)
.setUid(UNIMPORTANT_UID)
.setWindowLayout(windowLayout)
.build();
// Task fragment hasn't attached to a task yet. Start activity to a new task.
TaskFragment taskFragment = new TaskFragmentBuilder(mAtm).build();
final Task task = new TaskBuilder(mSupervisor).build();
assertEquals(EMBEDDING_DISALLOWED_NEW_TASK,
canEmbedActivity(taskFragment, starting, task));
// Starting activity is going to be started on a task different from task fragment's parent
// task. Start activity to a new task.
task.addChild(taskFragment, POSITION_TOP);
final Task newTask = new TaskBuilder(mSupervisor).build();
assertEquals(EMBEDDING_DISALLOWED_NEW_TASK,
canEmbedActivity(taskFragment, starting, newTask));
// Make task fragment bounds exceed task bounds.
final Rect taskBounds = task.getBounds();
taskFragment.setBounds(taskBounds.left, taskBounds.top, taskBounds.right + 1,
taskBounds.bottom + 1);
assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
canEmbedActivity(taskFragment, starting, task));
taskFragment.setBounds(taskBounds);
starting.info.flags |= FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
assertEquals(EMBEDDING_ALLOWED, canEmbedActivity(taskFragment, starting, task));
starting.info.flags &= ~FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
// Set task fragment's uid as the same as starting activity's uid.
taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
UNIMPORTANT_UID, "test");
assertEquals(EMBEDDING_ALLOWED, canEmbedActivity(taskFragment, starting, task));
// Make task fragment bounds smaller than starting activity's minimum dimensions
taskFragment.setBounds(0, 0, minDimensions.getWidth() - 1, minDimensions.getHeight() - 1);
assertEquals(EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
canEmbedActivity(taskFragment, starting, task));
}
private static void startActivityInner(ActivityStarter starter, ActivityRecord target, private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
ActivityRecord source, ActivityOptions options, Task inTask, ActivityRecord source, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment) { TaskFragment inTaskFragment) {

View File

@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.testing.Assert.assertThrows; import static com.android.server.wm.testing.Assert.assertThrows;
@@ -531,7 +532,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mWindowOrganizerController.mLaunchTaskFragments mWindowOrganizerController.mLaunchTaskFragments
.put(mFragmentToken, mTaskFragment); .put(mFragmentToken, mTaskFragment);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token); mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token);
doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity); doReturn(EMBEDDING_ALLOWED).when(mTaskFragment).isAllowedToEmbedActivity(activity);
clearInvocations(mAtm.mRootWindowContainer); clearInvocations(mAtm.mRootWindowContainer);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction); mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
@@ -921,7 +922,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.setOrganizer(mOrganizer) .setOrganizer(mOrganizer)
.setBounds(mTaskFragBounds) .setBounds(mTaskFragBounds)
.build(); .build();
doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment); mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
clearInvocations(mAtm.mRootWindowContainer); clearInvocations(mAtm.mRootWindowContainer);
@@ -956,7 +956,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.setOrganizer(mOrganizer) .setOrganizer(mOrganizer)
.setBounds(mTaskFragBounds) .setBounds(mTaskFragBounds)
.build(); .build();
doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
mWindowOrganizerController.mLaunchTaskFragments.put(oldFragToken, oldTaskFrag); mWindowOrganizerController.mLaunchTaskFragments.put(oldFragToken, oldTaskFrag);
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment); mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
clearInvocations(mAtm.mRootWindowContainer); clearInvocations(mAtm.mRootWindowContainer);