Merge "Report the failure back to the organizer" into sc-v2-dev

This commit is contained in:
Jeff Chang
2021-07-22 10:46:46 +00:00
committed by Android (Google) Code Review
4 changed files with 120 additions and 32 deletions

View File

@@ -490,9 +490,16 @@ public class ActivityStartController {
return START_SUCCESS;
}
void startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
/**
* Starts an activity in the TaskFragment.
* @param taskFragment TaskFragment {@link TaskFragment} to start the activity in.
* @param activityIntent intent to start the activity.
* @param activityOptions ActivityOptions to start the activity with.
* @return the start result.
*/
int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
@NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
obtainStarter(activityIntent, "startActivityInTaskFragment")
return obtainStarter(activityIntent, "startActivityInTaskFragment")
.setActivityOptions(activityOptions)
.setInTaskFragment(taskFragment)
.setCallingUid(Binder.getCallingUid())

View File

@@ -16,6 +16,8 @@
package com.android.server.wm;
import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
@@ -23,6 +25,7 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -190,6 +193,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
}
}
void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
Throwable exception) {
final Bundle exceptionBundle = putExceptionInBundle(exception);
try {
organizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onTaskFragmentError callback", e);
}
}
}
@Override
@@ -289,6 +302,14 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
state.removeTaskFragment(taskFragment);
}
void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
Throwable exception) {
validateAndGetState(organizer);
PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(organizer,
errorCallbackToken, exception, PendingTaskFragmentEvent.EVENT_ERROR);
mPendingTaskFragmentEvents.add(pendingEvent);
}
private void removeOrganizer(ITaskFragmentOrganizer organizer) {
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
// remove all of the children of the organized TaskFragment
@@ -321,25 +342,45 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
static final int EVENT_VANISHED = 1;
static final int EVENT_INFO_CHANGED = 2;
static final int EVENT_PARENT_INFO_CHANGED = 3;
static final int EVENT_ERROR = 4;
@IntDef(prefix = "EVENT_", value = {
EVENT_APPEARED,
EVENT_VANISHED,
EVENT_INFO_CHANGED,
EVENT_PARENT_INFO_CHANGED
EVENT_PARENT_INFO_CHANGED,
EVENT_ERROR
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
@EventType
final int mEventType;
final TaskFragment mTaskFragment;
final ITaskFragmentOrganizer mTaskFragmentOrg;
private final int mEventType;
private final ITaskFragmentOrganizer mTaskFragmentOrg;
private final TaskFragment mTaskFragment;
private final IBinder mErrorCallback;
private final Throwable mException;
PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg,
private PendingTaskFragmentEvent(TaskFragment taskFragment,
ITaskFragmentOrganizer taskFragmentOrg, @EventType int eventType) {
this(taskFragment, taskFragmentOrg, null /* errorCallback */,
null /* exception */, eventType);
}
private PendingTaskFragmentEvent(ITaskFragmentOrganizer taskFragmentOrg,
IBinder errorCallback, Throwable exception, @EventType int eventType) {
this(null /* taskFragment */, taskFragmentOrg, errorCallback, exception,
eventType);
}
private PendingTaskFragmentEvent(TaskFragment taskFragment,
ITaskFragmentOrganizer taskFragmentOrg, IBinder errorCallback, Throwable exception,
@EventType int eventType) {
mTaskFragment = taskFragment;
mTaskFragmentOrg = taskFragmentOrg;
mErrorCallback = errorCallback;
mException = exception;
mEventType = eventType;
}
@@ -407,6 +448,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
break;
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment);
break;
case PendingTaskFragmentEvent.EVENT_ERROR:
state.onTaskFragmentError(taskFragmentOrg, event.mErrorCallback,
event.mException);
}
}
mPendingTaskFragmentEvents.clear();

View File

@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.isStartResultSuccessful;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
@@ -44,6 +45,7 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -369,7 +371,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final boolean isInLockTaskMode = mService.isInLockTaskMode();
for (int i = 0; i < hopSize; ++i) {
effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
isInLockTaskMode, caller);
isInLockTaskMode, caller, t.getErrorCallbackToken(),
t.getTaskFragmentOrganizer());
}
}
// Queue-up bounds-change transactions for tasks which are now organized. Do
@@ -525,7 +528,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
@Nullable CallerInfo caller) {
@Nullable CallerInfo caller, @Nullable IBinder errorCallbackToken,
@Nullable ITaskFragmentOrganizer organizer) {
final int type = hop.getType();
switch (type) {
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
@@ -652,7 +656,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
final TaskFragmentCreationParams taskFragmentCreationOptions =
hop.getTaskFragmentCreationOptions();
createTaskFragment(taskFragmentCreationOptions);
createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
break;
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
wc = WindowContainer.fromBinder(hop.getContainer());
@@ -665,28 +669,36 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
throw new IllegalArgumentException(
"Can only delete organized TaskFragment, but not Task.");
}
deleteTaskFragment(taskFragment);
deleteTaskFragment(taskFragment, errorCallbackToken);
break;
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
fragmentToken = hop.getContainer();
if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
throw new IllegalArgumentException(
final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break;
}
final Intent activityIntent = hop.getActivityIntent();
final Bundle activityOptions = hop.getLaunchOptions();
mService.getActivityStartController()
.startActivityInTaskFragment(mLaunchTaskFragments.get(fragmentToken),
activityIntent, activityOptions);
// TODO(b/189385246) : report the failure back to the organizer if the activity
// start failed
final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
final int result = mService.getActivityStartController()
.startActivityInTaskFragment(tf, activityIntent, activityOptions);
if (!isStartResultSuccessful(result)) {
final Throwable exception =
new ActivityNotFoundException("start activity in taskFragment failed");
sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
errorCallbackToken, exception);
}
break;
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
fragmentToken = hop.getNewParent();
final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
throw new IllegalArgumentException(
final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token or activity.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break;
}
activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
break;
@@ -700,7 +712,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
+ oldParent);
break;
}
reparentTaskFragment(oldParent, newParent);
reparentTaskFragment(oldParent, newParent, errorCallbackToken);
break;
}
return effects;
@@ -1076,17 +1088,25 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams) {
void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
@Nullable IBinder errorCallbackToken) {
final ActivityRecord ownerActivity =
ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
if (ownerActivity == null || ownerActivity.getTask() == null) {
// TODO(b/189385246) : report the failure back to the organizer
final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid ownerToken");
sendTaskFragmentOperationFailure(creationParams.getOrganizer(), errorCallbackToken,
exception);
return;
}
// The ownerActivity has to belong to the same app as the root Activity of the target Task.
final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
if (rootActivity.getUid() != ownerActivity.getUid()) {
// TODO(b/189385246) : report the failure back to the organizer
final Throwable exception =
new IllegalArgumentException("Not allowed to operate with the ownerToken while "
+ "the root activity of the target task belong to the different app");
sendTaskFragmentOperationFailure(creationParams.getOrganizer(), errorCallbackToken,
exception);
return;
}
final TaskFragment taskFragment = new TaskFragment(mService,
@@ -1102,13 +1122,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
void reparentTaskFragment(@NonNull WindowContainer oldParent,
@Nullable WindowContainer newParent) {
@Nullable WindowContainer newParent, @Nullable IBinder errorCallbackToken) {
WindowContainer parent = newParent;
if (parent == null && oldParent.asTaskFragment() != null) {
parent = oldParent.asTaskFragment().getTask();
}
if (parent == null) {
// TODO(b/189385246) : report the failure back to the organizer
final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid container");
sendTaskFragmentOperationFailure(oldParent.asTaskFragment().getTaskFragmentOrganizer(),
errorCallbackToken, exception);
return;
}
while (oldParent.hasChild()) {
@@ -1116,11 +1139,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
void deleteTaskFragment(@NonNull TaskFragment taskFragment) {
void deleteTaskFragment(@NonNull TaskFragment taskFragment,
@Nullable IBinder errorCallbackToken) {
final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
if (index < 0) {
throw new IllegalArgumentException(
"Not allowed to operate with invalid taskFragment");
final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid "
+ "taskFragment");
sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
errorCallbackToken, exception);
return;
}
mLaunchTaskFragments.removeAt(index);
taskFragment.removeImmediately();
@@ -1135,4 +1163,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mUid = Binder.getCallingUid();
}
}
void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer,
@Nullable IBinder errorCallbackToken, @NonNull Throwable exception) {
if (organizer == null) {
throw new IllegalArgumentException("Not allowed to operate with invalid organizer");
}
mService.mTaskFragmentOrganizerController
.onTaskFragmentError(organizer, errorCallbackToken, exception);
}
}

View File

@@ -16,8 +16,6 @@
package com.android.server.wm;
import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.testing.Assert.assertThrows;
@@ -35,7 +33,6 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -198,9 +195,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
public void testOnTaskFragmentError() throws RemoteException {
final IBinder errorCallbackToken = new Binder();
final Throwable exception = new IllegalArgumentException("Test exception");
final Bundle exceptionBundle = putExceptionInBundle(exception);
mIOrganizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
mController.registerOrganizer(mIOrganizer);
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
errorCallbackToken, exception);
mController.dispatchPendingEvents();
verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception));
}