Merge "Fix exception when opening App info on work profile" into tm-qpr-dev
This commit is contained in:
@@ -79,6 +79,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;
|
||||||
@@ -132,6 +136,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;
|
||||||
@@ -2074,24 +2079,6 @@ class ActivityStarter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mInTaskFragment != null && !canEmbedActivity(mInTaskFragment, r, newTask, targetTask)) {
|
|
||||||
final StringBuilder errorMsg = new StringBuilder("Permission denied: Cannot embed " + r
|
|
||||||
+ " to " + mInTaskFragment.getTask() + ". newTask=" + newTask + ", targetTask= "
|
|
||||||
+ targetTask);
|
|
||||||
if (newTask && isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE,
|
|
||||||
LAUNCH_SINGLE_INSTANCE_PER_TASK, LAUNCH_SINGLE_TASK)) {
|
|
||||||
errorMsg.append("\nActivity tries to launch on a new task because the launch mode"
|
|
||||||
+ " is " + launchModeToString(mLaunchMode));
|
|
||||||
} else if (newTask && (mLaunchFlags & (FLAG_ACTIVITY_NEW_DOCUMENT
|
|
||||||
| FLAG_ACTIVITY_NEW_TASK)) != 0) {
|
|
||||||
errorMsg.append("\nActivity tries to launch on a new task because the launch flags"
|
|
||||||
+ " contains FLAG_ACTIVITY_NEW_DOCUMENT or FLAG_ACTIVITY_NEW_TASK. "
|
|
||||||
+ "mLaunchFlag=" + mLaunchFlags);
|
|
||||||
}
|
|
||||||
Slog.e(TAG, errorMsg.toString());
|
|
||||||
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
|
||||||
@@ -2118,19 +2105,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);
|
||||||
@@ -2970,19 +2959,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;
|
||||||
@@ -2994,20 +2980,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);
|
||||||
@@ -3016,16 +2994,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=" + launchModeToString(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,
|
||||||
|
|||||||
@@ -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.
|
||||||
*
|
*
|
||||||
@@ -509,20 +548,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) {
|
||||||
@@ -539,9 +587,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -598,7 +645,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CON
|
|||||||
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_PINNED_TASK;
|
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
|
||||||
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;
|
||||||
|
|
||||||
@@ -814,7 +815,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);
|
||||||
@@ -1057,7 +1058,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;
|
||||||
@@ -1672,7 +1673,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.");
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
@@ -1171,6 +1179,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
|
||||||
@@ -1341,6 +1350,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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
@@ -530,7 +531,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);
|
||||||
@@ -920,7 +921,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);
|
||||||
|
|
||||||
// Reparent activity to mTaskFragment, which is smaller than activity's
|
// Reparent activity to mTaskFragment, which is smaller than activity's
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user