Merge "Sending TaskFragmentInfo and operation type in #onTaskFragmentError" into tm-qpr-dev am: 8be2f81086

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

Change-Id: I8aad77caa6cb353a7fa926461aea9eb940178568
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Louis Chang
2022-07-28 06:11:40 +00:00
committed by Automerger Merge Worker
10 changed files with 204 additions and 54 deletions

View File

@@ -3351,7 +3351,8 @@ package android.window {
method @NonNull public java.util.concurrent.Executor getExecutor(); method @NonNull public java.util.concurrent.Executor getExecutor();
method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken(); method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken();
method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentInfo); method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentInfo);
method public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable); method @Deprecated public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable);
method public void onTaskFragmentError(@NonNull android.os.IBinder, @Nullable android.window.TaskFragmentInfo, int, @NonNull Throwable);
method public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo); method public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo);
method public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration); method public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration);
method public void onTaskFragmentVanished(@NonNull android.window.TaskFragmentInfo); method public void onTaskFragmentVanished(@NonNull android.window.TaskFragmentInfo);

View File

@@ -45,10 +45,11 @@ oneway interface ITaskFragmentOrganizer {
* *
* @param errorCallbackToken Token set through {@link * @param errorCallbackToken Token set through {@link
* WindowContainerTransaction#setErrorCallbackToken(IBinder)} * WindowContainerTransaction#setErrorCallbackToken(IBinder)}
* @param exceptionBundle Bundle containing the exception. Should be created with * @param errorBundle Bundle containing the exception, operation type and TaskFragmentInfo
* {@link TaskFragmentOrganizer#putExceptionInBundle}. * if any. Should be created with
* {@link TaskFragmentOrganizer#putErrorInfoInBundle}.
*/ */
void onTaskFragmentError(in IBinder errorCallbackToken, in Bundle exceptionBundle); void onTaskFragmentError(in IBinder errorCallbackToken, in Bundle errorBundle);
/** /**
* Called when an Activity is reparented to the Task with organized TaskFragment. For example, * Called when an Activity is reparented to the Task with organized TaskFragment. For example,

View File

@@ -18,6 +18,7 @@ package android.window;
import android.annotation.CallSuper; import android.annotation.CallSuper;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi; import android.annotation.TestApi;
import android.content.Intent; import android.content.Intent;
import android.content.res.Configuration; import android.content.res.Configuration;
@@ -39,16 +40,23 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
* Key to the exception in {@link Bundle} in {@link ITaskFragmentOrganizer#onTaskFragmentError}. * Key to the exception in {@link Bundle} in {@link ITaskFragmentOrganizer#onTaskFragmentError}.
*/ */
private static final String KEY_ERROR_CALLBACK_EXCEPTION = "fragment_exception"; private static final String KEY_ERROR_CALLBACK_EXCEPTION = "fragment_exception";
private static final String KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO = "task_fragment_info";
private static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type";
/** /**
* Creates a {@link Bundle} with an exception that can be passed to * Creates a {@link Bundle} with an exception, operation type and TaskFragmentInfo (if any)
* {@link ITaskFragmentOrganizer#onTaskFragmentError}. * that can be passed to {@link ITaskFragmentOrganizer#onTaskFragmentError}.
* @hide * @hide
*/ */
public static Bundle putExceptionInBundle(@NonNull Throwable exception) { public static @NonNull Bundle putErrorInfoInBundle(@NonNull Throwable exception,
final Bundle exceptionBundle = new Bundle(); @Nullable TaskFragmentInfo info, int opType) {
exceptionBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception); final Bundle errorBundle = new Bundle();
return exceptionBundle; errorBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception);
if (info != null) {
errorBundle.putParcelable(KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, info);
}
errorBundle.putInt(KEY_ERROR_CALLBACK_OP_TYPE, opType);
return errorBundle;
} }
/** /**
@@ -151,10 +159,33 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
* @param errorCallbackToken token set in * @param errorCallbackToken token set in
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)}
* @param exception exception from the server side. * @param exception exception from the server side.
*
* @deprecated Use {@link #onTaskFragmentError(IBinder, TaskFragmentInfo, int, Throwable)}
* instead.
*/ */
@Deprecated
public void onTaskFragmentError( public void onTaskFragmentError(
@NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {} @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {}
/**
* Called when the {@link WindowContainerTransaction} created with
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
*
* @param errorCallbackToken token set in
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)}
* @param taskFragmentInfo The {@link TaskFragmentInfo}. This could be {@code null} if no
* TaskFragment created.
* @param opType The {@link WindowContainerTransaction.HierarchyOp} of the failed
* transaction operation.
* @param exception exception from the server side.
*/
public void onTaskFragmentError(
@NonNull IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo,
int opType, @NonNull Throwable exception) {
// Doing so to keep compatibility. This will be removed in the next release.
onTaskFragmentError(errorCallbackToken, exception);
}
/** /**
* Called when an Activity is reparented to the Task with organized TaskFragment. For example, * Called when an Activity is reparented to the Task with organized TaskFragment. For example,
* when an Activity enters and then exits Picture-in-picture, it will be reparented back to its * when an Activity enters and then exits Picture-in-picture, it will be reparented back to its
@@ -217,10 +248,16 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
@Override @Override
public void onTaskFragmentError( public void onTaskFragmentError(
@NonNull IBinder errorCallbackToken, @NonNull Bundle exceptionBundle) { @NonNull IBinder errorCallbackToken, @NonNull Bundle errorBundle) {
mExecutor.execute(() -> TaskFragmentOrganizer.this.onTaskFragmentError( mExecutor.execute(() -> {
errorCallbackToken, final TaskFragmentInfo info = errorBundle.getParcelable(
(Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION))); KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, TaskFragmentInfo.class);
TaskFragmentOrganizer.this.onTaskFragmentError(
errorCallbackToken, info,
errorBundle.getInt(KEY_ERROR_CALLBACK_OP_TYPE),
(Throwable) errorBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION,
java.lang.Throwable.class));
});
} }
@Override @Override

View File

@@ -72,6 +72,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
@NonNull Configuration parentConfig); @NonNull Configuration parentConfig);
void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent, void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
@NonNull IBinder activityToken); @NonNull IBinder activityToken);
void onTaskFragmentError(@Nullable TaskFragmentInfo taskFragmentInfo, int opType);
} }
/** /**
@@ -323,4 +324,18 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
mCallback.onActivityReparentToTask(taskId, activityIntent, activityToken); mCallback.onActivityReparentToTask(taskId, activityIntent, activityToken);
} }
} }
@Override
public void onTaskFragmentError(@NonNull IBinder errorCallbackToken,
@Nullable TaskFragmentInfo taskFragmentInfo,
int opType, @NonNull Throwable exception) {
if (taskFragmentInfo != null) {
final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
mFragmentInfos.put(fragmentToken, taskFragmentInfo);
}
if (mCallback != null) {
mCallback.onTaskFragmentError(taskFragmentInfo, opType);
}
}
} }

View File

@@ -19,6 +19,8 @@ package androidx.window.extensions.embedding;
import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_SUCCESS;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior; import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior;
import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior; import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior;
@@ -296,6 +298,37 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
} }
} }
@Override
public void onTaskFragmentError(@Nullable TaskFragmentInfo taskFragmentInfo, int opType) {
synchronized (mLock) {
switch (opType) {
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
final TaskFragmentContainer container;
if (taskFragmentInfo != null) {
container = getContainer(taskFragmentInfo.getFragmentToken());
} else {
container = null;
}
if (container == null) {
break;
}
// Update the latest taskFragmentInfo and perform necessary clean-up
container.setInfo(taskFragmentInfo);
container.clearPendingAppearedActivities();
if (container.isEmpty()) {
mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
}
break;
}
default:
Log.e(TAG, "onTaskFragmentError: taskFragmentInfo = " + taskFragmentInfo
+ ", opType = " + opType);
}
}
}
/** Called on receiving {@link #onTaskFragmentVanished(TaskFragmentInfo)} for cleanup. */ /** Called on receiving {@link #onTaskFragmentVanished(TaskFragmentInfo)} for cleanup. */
private void cleanupTaskFragment(@NonNull IBinder taskFragmentToken) { private void cleanupTaskFragment(@NonNull IBinder taskFragmentToken) {
for (int i = mTaskContainers.size() - 1; i >= 0; i--) { for (int i = mTaskContainers.size() - 1; i >= 0; i--) {

View File

@@ -193,6 +193,11 @@ class TaskFragmentContainer {
mPendingAppearedActivities.remove(pendingAppearedActivity); mPendingAppearedActivities.remove(pendingAppearedActivity);
} }
void clearPendingAppearedActivities() {
mPendingAppearedActivities.clear();
mPendingAppearedIntent = null;
}
@Nullable @Nullable
Intent getPendingAppearedIntent() { Intent getPendingAppearedIntent() {
return mPendingAppearedIntent; return mPendingAppearedIntent;

View File

@@ -56,6 +56,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.INVALID_UID; import static android.os.Process.INVALID_UID;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
@@ -3015,6 +3016,7 @@ class ActivityStarter {
if (taskFragment.isOrganized()) { if (taskFragment.isOrganized()) {
mService.mWindowOrganizerController.sendTaskFragmentOperationFailure( mService.mWindowOrganizerController.sendTaskFragmentOperationFailure(
taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken, taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken,
taskFragment, HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT,
new SecurityException(errMsg)); new SecurityException(errMsg));
} else { } else {
// If the taskFragment is not organized, just dump error message as warning logs. // If the taskFragment is not organized, just dump error message as warning logs.

View File

@@ -16,7 +16,7 @@
package com.android.server.wm; package com.android.server.wm;
import static android.window.TaskFragmentOrganizer.putExceptionInBundle; import static android.window.TaskFragmentOrganizer.putErrorInfoInBundle;
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.TaskFragment.EMBEDDING_ALLOWED;
@@ -214,12 +214,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
} }
} }
void onTaskFragmentError(IBinder errorCallbackToken, Throwable exception) { void onTaskFragmentError(IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
int opType, Throwable exception) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
"Sending TaskFragment error exception=%s", exception.toString()); "Sending TaskFragment error exception=%s", exception.toString());
final Bundle exceptionBundle = putExceptionInBundle(exception); final TaskFragmentInfo info =
taskFragment != null ? taskFragment.getTaskFragmentInfo() : null;
final Bundle errorBundle = putErrorInfoInBundle(exception, info, opType);
try { try {
mOrganizer.onTaskFragmentError(errorCallbackToken, exceptionBundle); mOrganizer.onTaskFragmentError(errorCallbackToken, errorBundle);
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.d(TAG, "Exception sending onTaskFragmentError callback", e); Slog.d(TAG, "Exception sending onTaskFragmentError callback", e);
} }
@@ -462,13 +465,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
} }
void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken, void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
Throwable exception) { TaskFragment taskFragment, int opType, Throwable exception) {
validateAndGetState(organizer); validateAndGetState(organizer);
Slog.w(TAG, "onTaskFragmentError ", exception); Slog.w(TAG, "onTaskFragmentError ", exception);
final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder( final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder(
PendingTaskFragmentEvent.EVENT_ERROR, organizer) PendingTaskFragmentEvent.EVENT_ERROR, organizer)
.setErrorCallbackToken(errorCallbackToken) .setErrorCallbackToken(errorCallbackToken)
.setTaskFragment(taskFragment)
.setException(exception) .setException(exception)
.setOpType(opType)
.build(); .build();
mPendingTaskFragmentEvents.add(pendingEvent); mPendingTaskFragmentEvents.add(pendingEvent);
// Make sure the error event will be dispatched if there are no other changes. // Make sure the error event will be dispatched if there are no other changes.
@@ -567,19 +572,22 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
// Set when the event is deferred due to the host task is invisible. The defer time will // Set when the event is deferred due to the host task is invisible. The defer time will
// be the last active time of the host task. // be the last active time of the host task.
private long mDeferTime; private long mDeferTime;
private int mOpType;
private PendingTaskFragmentEvent(@EventType int eventType, private PendingTaskFragmentEvent(@EventType int eventType,
ITaskFragmentOrganizer taskFragmentOrg, ITaskFragmentOrganizer taskFragmentOrg,
@Nullable TaskFragment taskFragment, @Nullable TaskFragment taskFragment,
@Nullable IBinder errorCallbackToken, @Nullable IBinder errorCallbackToken,
@Nullable Throwable exception, @Nullable Throwable exception,
@Nullable ActivityRecord activity) { @Nullable ActivityRecord activity,
int opType) {
mEventType = eventType; mEventType = eventType;
mTaskFragmentOrg = taskFragmentOrg; mTaskFragmentOrg = taskFragmentOrg;
mTaskFragment = taskFragment; mTaskFragment = taskFragment;
mErrorCallbackToken = errorCallbackToken; mErrorCallbackToken = errorCallbackToken;
mException = exception; mException = exception;
mActivity = activity; mActivity = activity;
mOpType = opType;
} }
/** /**
@@ -610,6 +618,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private Throwable mException; private Throwable mException;
@Nullable @Nullable
private ActivityRecord mActivity; private ActivityRecord mActivity;
private int mOpType;
Builder(@EventType int eventType, ITaskFragmentOrganizer taskFragmentOrg) { Builder(@EventType int eventType, ITaskFragmentOrganizer taskFragmentOrg) {
mEventType = eventType; mEventType = eventType;
@@ -636,9 +645,14 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return this; return this;
} }
Builder setOpType(int opType) {
mOpType = opType;
return this;
}
PendingTaskFragmentEvent build() { PendingTaskFragmentEvent build() {
return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment, return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment,
mErrorCallbackToken, mException, mActivity); mErrorCallbackToken, mException, mActivity, mOpType);
} }
} }
} }
@@ -667,6 +681,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
} }
private boolean shouldSendEventWhenTaskInvisible(@NonNull PendingTaskFragmentEvent event) { private boolean shouldSendEventWhenTaskInvisible(@NonNull PendingTaskFragmentEvent event) {
if (event.mEventType == PendingTaskFragmentEvent.EVENT_ERROR) {
return true;
}
final TaskFragmentOrganizerState state = final TaskFragmentOrganizerState state =
mTaskFragmentOrganizerState.get(event.mTaskFragmentOrg.asBinder()); mTaskFragmentOrganizerState.get(event.mTaskFragmentOrg.asBinder());
final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos.get(event.mTaskFragment); final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos.get(event.mTaskFragment);
@@ -757,7 +775,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
state.onTaskFragmentParentInfoChanged(taskFragment); state.onTaskFragmentParentInfoChanged(taskFragment);
break; break;
case PendingTaskFragmentEvent.EVENT_ERROR: case PendingTaskFragmentEvent.EVENT_ERROR:
state.onTaskFragmentError(event.mErrorCallbackToken, event.mException); state.onTaskFragmentError(event.mErrorCallbackToken, taskFragment, event.mOpType,
event.mException);
break; break;
case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK: case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK:
state.onActivityReparentToTask(event.mActivity); state.onActivityReparentToTask(event.mActivity);

View File

@@ -765,7 +765,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
bottomActivity)) { bottomActivity)) {
Slog.w(TAG, "Skip removing TaskFragment due in lock task mode."); Slog.w(TAG, "Skip removing TaskFragment due in lock task mode.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
new IllegalStateException( taskFragment, type, new IllegalStateException(
"Not allow to delete task fragment in lock task mode.")); "Not allow to delete task fragment in lock task mode."));
break; break;
} }
@@ -779,13 +779,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (tf == null) { if (tf == null) {
final Throwable exception = new IllegalArgumentException( final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token"); "Not allowed to operate with invalid fragment token");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type,
exception);
break; break;
} }
if (tf.isEmbeddedTaskFragmentInPip()) { if (tf.isEmbeddedTaskFragmentInPip()) {
final Throwable exception = new IllegalArgumentException( final Throwable exception = new IllegalArgumentException(
"Not allowed to start activity in PIP TaskFragment"); "Not allowed to start activity in PIP TaskFragment");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type,
exception);
break; break;
} }
final Intent activityIntent = hop.getActivityIntent(); final Intent activityIntent = hop.getActivityIntent();
@@ -795,7 +797,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
hop.getCallingActivity(), caller.mUid, caller.mPid, hop.getCallingActivity(), caller.mUid, caller.mPid,
errorCallbackToken); errorCallbackToken);
if (!isStartResultSuccessful(result)) { if (!isStartResultSuccessful(result)) {
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type,
convertStartFailureToThrowable(result, activityIntent)); convertStartFailureToThrowable(result, activityIntent));
} else { } else {
effects |= TRANSACT_EFFECTS_LIFECYCLE; effects |= TRANSACT_EFFECTS_LIFECYCLE;
@@ -816,25 +818,29 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (parent == null || activity == null) { if (parent == null || activity == null) {
final Throwable exception = new IllegalArgumentException( final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token or activity."); "Not allowed to operate with invalid fragment token or activity.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
exception);
break; break;
} }
if (parent.isEmbeddedTaskFragmentInPip()) { if (parent.isEmbeddedTaskFragmentInPip()) {
final Throwable exception = new IllegalArgumentException( final Throwable exception = new IllegalArgumentException(
"Not allowed to reparent activity to PIP TaskFragment"); "Not allowed to reparent activity to PIP TaskFragment");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
exception);
break; break;
} }
if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) { if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) {
final Throwable exception = new SecurityException( final Throwable exception = new SecurityException(
"The task fragment is not allowed to embed the given activity."); "The task fragment is not allowed to embed the given activity.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
exception);
break; break;
} }
if (parent.getTask() != activity.getTask()) { if (parent.getTask() != activity.getTask()) {
final Throwable exception = new SecurityException("The reparented activity is" final Throwable exception = new SecurityException("The reparented activity is"
+ " not in the same Task as the target TaskFragment."); + " not in the same Task as the target TaskFragment.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
exception);
break; break;
} }
@@ -854,14 +860,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (tf1 == null || (adjacentFragmentToken != null && tf2 == null)) { if (tf1 == null || (adjacentFragmentToken != null && tf2 == null)) {
final Throwable exception = new IllegalArgumentException( final Throwable exception = new IllegalArgumentException(
"Not allowed to set adjacent on invalid fragment tokens"); "Not allowed to set adjacent on invalid fragment tokens");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type,
exception);
break; break;
} }
if (tf1.isEmbeddedTaskFragmentInPip() if (tf1.isEmbeddedTaskFragmentInPip()
|| (tf2 != null && tf2.isEmbeddedTaskFragmentInPip())) { || (tf2 != null && tf2.isEmbeddedTaskFragmentInPip())) {
final Throwable exception = new IllegalArgumentException( final Throwable exception = new IllegalArgumentException(
"Not allowed to set adjacent on TaskFragment in PIP Task"); "Not allowed to set adjacent on TaskFragment in PIP Task");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type,
exception);
break; break;
} }
tf1.setAdjacentTaskFragment(tf2); tf1.setAdjacentTaskFragment(tf2);
@@ -1109,7 +1117,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
+ taskFragment.getBounds() + " does not satisfy minimum dimensions:" + taskFragment.getBounds() + " does not satisfy minimum dimensions:"
+ minDimensions + " " + reason); + minDimensions + " " + reason);
sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(), sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
errorCallbackToken, exception); errorCallbackToken, taskFragment, -1 /* opType */, exception);
} }
/** /**
@@ -1662,13 +1670,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (ownerActivity == null || ownerActivity.getTask() == null) { if (ownerActivity == null || ownerActivity.getTask() == null) {
final Throwable exception = final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid ownerToken"); new IllegalArgumentException("Not allowed to operate with invalid ownerToken");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return; return;
} }
if (!ownerActivity.isResizeable()) { if (!ownerActivity.isResizeable()) {
final IllegalArgumentException exception = new IllegalArgumentException("Not allowed" final IllegalArgumentException exception = new IllegalArgumentException("Not allowed"
+ " to operate with non-resizable owner Activity"); + " to operate with non-resizable owner Activity");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return; return;
} }
// The ownerActivity has to belong to the same app as the target Task. // The ownerActivity has to belong to the same app as the target Task.
@@ -1678,13 +1688,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final Throwable exception = final Throwable exception =
new SecurityException("Not allowed to operate with the ownerToken while " new SecurityException("Not allowed to operate with the ownerToken while "
+ "the root activity of the target task belong to the different app"); + "the root activity of the target task belong to the different app");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return; return;
} }
if (ownerTask.inPinnedWindowingMode()) { if (ownerTask.inPinnedWindowingMode()) {
final Throwable exception = new IllegalArgumentException( final Throwable exception = new IllegalArgumentException(
"Not allowed to create TaskFragment in PIP Task"); "Not allowed to create TaskFragment in PIP Task");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return; return;
} }
final TaskFragment taskFragment = new TaskFragment(mService, final TaskFragment taskFragment = new TaskFragment(mService,
@@ -1712,7 +1724,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (newParentTF == null) { if (newParentTF == null) {
final Throwable exception = final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid container"); new IllegalArgumentException("Not allowed to operate with invalid container");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
return; return;
} }
if (newParentTF.getTaskFragmentOrganizer() != null) { if (newParentTF.getTaskFragmentOrganizer() != null) {
@@ -1723,20 +1736,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (isEmbeddingDisallowed) { if (isEmbeddingDisallowed) {
final Throwable exception = new SecurityException( final Throwable exception = new SecurityException(
"The new parent is not allowed to embed the activities."); "The new parent is not allowed to embed the activities.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
return; return;
} }
} }
if (newParentTF.isEmbeddedTaskFragmentInPip() || oldParent.isEmbeddedTaskFragmentInPip()) { if (newParentTF.isEmbeddedTaskFragmentInPip() || oldParent.isEmbeddedTaskFragmentInPip()) {
final Throwable exception = new SecurityException( final Throwable exception = new SecurityException(
"Not allow to reparent in TaskFragment in PIP Task."); "Not allow to reparent in TaskFragment in PIP Task.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
return; return;
} }
if (newParentTF.getTask() != oldParent.getTask()) { if (newParentTF.getTask() != oldParent.getTask()) {
final Throwable exception = new SecurityException( final Throwable exception = new SecurityException(
"The new parent is not in the same Task as the old parent."); "The new parent is not in the same Task as the old parent.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
return; return;
} }
while (oldParent.hasChild()) { while (oldParent.hasChild()) {
@@ -1751,7 +1767,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final Throwable exception = final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid " new IllegalArgumentException("Not allowed to operate with invalid "
+ "taskFragment"); + "taskFragment");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception);
return 0; return 0;
} }
if (taskFragment.isEmbeddedTaskFragmentInPip() if (taskFragment.isEmbeddedTaskFragmentInPip()
@@ -1760,7 +1777,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
&& taskFragment.getTopNonFinishingActivity() != null) { && taskFragment.getTopNonFinishingActivity() != null) {
final Throwable exception = new IllegalArgumentException( final Throwable exception = new IllegalArgumentException(
"Not allowed to delete TaskFragment in PIP Task"); "Not allowed to delete TaskFragment in PIP Task");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception);
return 0; return 0;
} }
mLaunchTaskFragments.removeAt(index); mLaunchTaskFragments.removeAt(index);
@@ -1788,12 +1806,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
} }
void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer, void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer,
@Nullable IBinder errorCallbackToken, @NonNull Throwable exception) { @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, int opType,
@NonNull Throwable exception) {
if (organizer == null) { if (organizer == null) {
throw new IllegalArgumentException("Not allowed to operate with invalid organizer"); throw new IllegalArgumentException("Not allowed to operate with invalid organizer");
} }
mService.mTaskFragmentOrganizerController mService.mTaskFragmentOrganizerController
.onTaskFragmentError(organizer, errorCallbackToken, exception); .onTaskFragmentError(organizer, errorCallbackToken, taskFragment, opType,
exception);
} }
private Throwable convertStartFailureToThrowable(int result, Intent intent) { private Throwable convertStartFailureToThrowable(int result, Intent intent) {

View File

@@ -18,6 +18,12 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
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;
@@ -237,10 +243,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mController.registerOrganizer(mIOrganizer); mController.registerOrganizer(mIOrganizer);
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(), mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
mErrorToken, exception); mErrorToken, null /* taskFragment */, -1 /* opType */, exception);
mController.dispatchPendingEvents(); mController.dispatchPendingEvents();
verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), eq(exception)); verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), eq(null), eq(-1), eq(exception));
} }
@Test @Test
@@ -604,7 +610,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(), verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(),
any(), any(), anyInt(), anyInt(), any()); any(), any(), anyInt(), anyInt(), any());
verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), any(IllegalArgumentException.class)); eq(mErrorToken), eq(mTaskFragment),
eq(HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
any(IllegalArgumentException.class));
} }
@Test @Test
@@ -619,7 +627,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mWindowOrganizerController.applyTransaction(mTransaction); mWindowOrganizerController.applyTransaction(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), any(IllegalArgumentException.class)); eq(mErrorToken), eq(mTaskFragment),
eq(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT),
any(IllegalArgumentException.class));
assertNull(activity.getOrganizedTaskFragment()); assertNull(activity.getOrganizedTaskFragment());
} }
@@ -635,7 +645,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mWindowOrganizerController.applyTransaction(mTransaction); mWindowOrganizerController.applyTransaction(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), any(IllegalArgumentException.class)); eq(mErrorToken), eq(mTaskFragment),
eq(HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS),
any(IllegalArgumentException.class));
verify(mTaskFragment, never()).setAdjacentTaskFragment(any()); verify(mTaskFragment, never()).setAdjacentTaskFragment(any());
} }
@@ -654,7 +666,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mWindowOrganizerController.applyTransaction(mTransaction); mWindowOrganizerController.applyTransaction(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), any(IllegalArgumentException.class)); eq(mErrorToken), eq(null), eq(HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT),
any(IllegalArgumentException.class));
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken)); assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
} }
@@ -669,7 +682,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mWindowOrganizerController.applyTransaction(mTransaction); mWindowOrganizerController.applyTransaction(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), any(IllegalArgumentException.class)); eq(mErrorToken), eq(mTaskFragment), eq(HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT),
any(IllegalArgumentException.class));
assertNotNull(mWindowOrganizerController.getTaskFragment(mFragmentToken)); assertNotNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
// Allow organizer to delete empty TaskFragment for cleanup. // Allow organizer to delete empty TaskFragment for cleanup.
@@ -931,7 +945,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// The pending event will be dispatched on the handler (from requestTraversal). // The pending event will be dispatched on the handler (from requestTraversal).
waitHandlerIdle(mWm.mAnimationHandler); waitHandlerIdle(mWm.mAnimationHandler);
verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(SecurityException.class)); verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(),
eq(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT),
any(SecurityException.class));
} }
@Test @Test
@@ -968,7 +984,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// The pending event will be dispatched on the handler (from requestTraversal). // The pending event will be dispatched on the handler (from requestTraversal).
waitHandlerIdle(mWm.mAnimationHandler); waitHandlerIdle(mWm.mAnimationHandler);
verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(SecurityException.class)); verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(),
eq(HIERARCHY_OP_TYPE_REPARENT_CHILDREN), any(SecurityException.class));
} }
@Test @Test