Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35c010ed authored by Jeff Chang's avatar Jeff Chang Committed by Automerger Merge Worker
Browse files

Merge "Report the failure back to the organizer" into sc-v2-dev am: 1d8f49f3 am: e4e364c4

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

Change-Id: I31d4fb231134f0773a44d739b29c9b54a77ab27c
parents 440e8e8f e4e364c4
Loading
Loading
Loading
Loading
+9 −2
Original line number Original line Diff line number Diff line
@@ -490,9 +490,16 @@ public class ActivityStartController {
        return START_SUCCESS;
        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) {
            @NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
        obtainStarter(activityIntent, "startActivityInTaskFragment")
        return obtainStarter(activityIntent, "startActivityInTaskFragment")
                .setActivityOptions(activityOptions)
                .setActivityOptions(activityOptions)
                .setInTaskFragment(taskFragment)
                .setInTaskFragment(taskFragment)
                .setCallingUid(Binder.getCallingUid())
                .setCallingUid(Binder.getCallingUid())
+50 −5
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


package com.android.server.wm;
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.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;


@@ -23,6 +25,7 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArrayMap;
@@ -190,6 +193,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
                Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
                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
    @Override
@@ -289,6 +302,14 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
        state.removeTaskFragment(taskFragment);
        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) {
    private void removeOrganizer(ITaskFragmentOrganizer organizer) {
        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
        // remove all of the children of the organized TaskFragment
        // 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_VANISHED = 1;
        static final int EVENT_INFO_CHANGED = 2;
        static final int EVENT_INFO_CHANGED = 2;
        static final int EVENT_PARENT_INFO_CHANGED = 3;
        static final int EVENT_PARENT_INFO_CHANGED = 3;
        static final int EVENT_ERROR = 4;


        @IntDef(prefix = "EVENT_", value = {
        @IntDef(prefix = "EVENT_", value = {
                EVENT_APPEARED,
                EVENT_APPEARED,
                EVENT_VANISHED,
                EVENT_VANISHED,
                EVENT_INFO_CHANGED,
                EVENT_INFO_CHANGED,
                EVENT_PARENT_INFO_CHANGED
                EVENT_PARENT_INFO_CHANGED,
                EVENT_ERROR
        })
        })
        @Retention(RetentionPolicy.SOURCE)
        @Retention(RetentionPolicy.SOURCE)
        public @interface EventType {}
        public @interface EventType {}


        @EventType
        @EventType
        final int mEventType;
        private final int mEventType;
        final TaskFragment mTaskFragment;
        private final ITaskFragmentOrganizer mTaskFragmentOrg;
        final ITaskFragmentOrganizer mTaskFragmentOrg;
        private final TaskFragment mTaskFragment;
        private final IBinder mErrorCallback;
        private final Throwable mException;

        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);
        }


        PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg,
        private PendingTaskFragmentEvent(TaskFragment taskFragment,
                ITaskFragmentOrganizer taskFragmentOrg, IBinder errorCallback, Throwable exception,
                @EventType int eventType) {
                @EventType int eventType) {
            mTaskFragment = taskFragment;
            mTaskFragment = taskFragment;
            mTaskFragmentOrg = taskFragmentOrg;
            mTaskFragmentOrg = taskFragmentOrg;
            mErrorCallback = errorCallback;
            mException = exception;
            mEventType = eventType;
            mEventType = eventType;
        }
        }


@@ -407,6 +448,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
                    break;
                    break;
                case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
                case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
                    state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment);
                    state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment);
                    break;
                case PendingTaskFragmentEvent.EVENT_ERROR:
                    state.onTaskFragmentError(taskFragmentOrg, event.mErrorCallback,
                            event.mException);
            }
            }
        }
        }
        mPendingTaskFragmentEvents.clear();
        mPendingTaskFragmentEvents.clear();
+57 −20
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.wm;
package com.android.server.wm;


import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
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.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_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
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.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Configuration;
@@ -369,7 +371,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                final boolean isInLockTaskMode = mService.isInLockTaskMode();
                final boolean isInLockTaskMode = mService.isInLockTaskMode();
                for (int i = 0; i < hopSize; ++i) {
                for (int i = 0; i < hopSize; ++i) {
                    effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
                    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
            // 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,
    private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
            int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
            int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
            @Nullable CallerInfo caller) {
            @Nullable CallerInfo caller, @Nullable IBinder errorCallbackToken,
            @Nullable ITaskFragmentOrganizer organizer) {
        final int type = hop.getType();
        final int type = hop.getType();
        switch (type) {
        switch (type) {
            case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
            case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
@@ -652,7 +656,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
            case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
            case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
                final TaskFragmentCreationParams taskFragmentCreationOptions =
                final TaskFragmentCreationParams taskFragmentCreationOptions =
                        hop.getTaskFragmentCreationOptions();
                        hop.getTaskFragmentCreationOptions();
                createTaskFragment(taskFragmentCreationOptions);
                createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
                break;
                break;
            case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
            case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
                wc = WindowContainer.fromBinder(hop.getContainer());
                wc = WindowContainer.fromBinder(hop.getContainer());
@@ -665,28 +669,36 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                    throw new IllegalArgumentException(
                    throw new IllegalArgumentException(
                            "Can only delete organized TaskFragment, but not Task.");
                            "Can only delete organized TaskFragment, but not Task.");
                }
                }
                deleteTaskFragment(taskFragment);
                deleteTaskFragment(taskFragment, errorCallbackToken);
                break;
                break;
            case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
            case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
                fragmentToken = hop.getContainer();
                fragmentToken = hop.getContainer();
                if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
                if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
                    throw 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);
                    break;
                }
                }
                final Intent activityIntent = hop.getActivityIntent();
                final Intent activityIntent = hop.getActivityIntent();
                final Bundle activityOptions = hop.getLaunchOptions();
                final Bundle activityOptions = hop.getLaunchOptions();
                mService.getActivityStartController()
                final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
                        .startActivityInTaskFragment(mLaunchTaskFragments.get(fragmentToken),
                final int result = mService.getActivityStartController()
                                activityIntent, activityOptions);
                        .startActivityInTaskFragment(tf, activityIntent, activityOptions);
                // TODO(b/189385246) : report the failure back to the organizer if the activity
                if (!isStartResultSuccessful(result)) {
                // start failed
                    final Throwable exception =
                            new ActivityNotFoundException("start activity in taskFragment failed");
                    sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
                            errorCallbackToken, exception);
                }
                break;
                break;
            case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
            case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
                fragmentToken = hop.getNewParent();
                fragmentToken = hop.getNewParent();
                final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
                final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
                if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
                if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
                    throw 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);
                    break;
                }
                }
                activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
                activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
                break;
                break;
@@ -700,7 +712,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                            + oldParent);
                            + oldParent);
                    break;
                    break;
                }
                }
                reparentTaskFragment(oldParent, newParent);
                reparentTaskFragment(oldParent, newParent, errorCallbackToken);
                break;
                break;
        }
        }
        return effects;
        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 =
        final ActivityRecord ownerActivity =
                ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
                ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
        if (ownerActivity == null || ownerActivity.getTask() == null) {
        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;
            return;
        }
        }
        // The ownerActivity has to belong to the same app as the root Activity of the target Task.
        // The ownerActivity has to belong to the same app as the root Activity of the target Task.
        final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
        final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
        if (rootActivity.getUid() != ownerActivity.getUid()) {
        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;
            return;
        }
        }
        final TaskFragment taskFragment = new TaskFragment(mService,
        final TaskFragment taskFragment = new TaskFragment(mService,
@@ -1102,13 +1122,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
    }
    }


    void reparentTaskFragment(@NonNull WindowContainer oldParent,
    void reparentTaskFragment(@NonNull WindowContainer oldParent,
            @Nullable WindowContainer newParent) {
            @Nullable WindowContainer newParent,  @Nullable IBinder errorCallbackToken) {
        WindowContainer parent = newParent;
        WindowContainer parent = newParent;
        if (parent == null && oldParent.asTaskFragment() != null) {
        if (parent == null && oldParent.asTaskFragment() != null) {
            parent = oldParent.asTaskFragment().getTask();
            parent = oldParent.asTaskFragment().getTask();
        }
        }
        if (parent == null) {
        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;
            return;
        }
        }
        while (oldParent.hasChild()) {
        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);
        final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
        if (index < 0) {
        if (index < 0) {
            throw new IllegalArgumentException(
            final Throwable exception =
                    "Not allowed to operate with invalid taskFragment");
                    new IllegalArgumentException("Not allowed to operate with invalid "
                            + "taskFragment");
            sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
                    errorCallbackToken, exception);
            return;
        }
        }
        mLaunchTaskFragments.removeAt(index);
        mLaunchTaskFragments.removeAt(index);
        taskFragment.removeImmediately();
        taskFragment.removeImmediately();
@@ -1135,4 +1163,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
            mUid = Binder.getCallingUid();
            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);
    }
}
}
+4 −5
Original line number Original line Diff line number Diff line
@@ -16,8 +16,6 @@


package com.android.server.wm;
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.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.testing.Assert.assertThrows;
import static com.android.server.wm.testing.Assert.assertThrows;
@@ -35,7 +33,6 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.Presubmit;
@@ -198,9 +195,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
    public void testOnTaskFragmentError() throws RemoteException {
    public void testOnTaskFragmentError() throws RemoteException {
        final IBinder errorCallbackToken = new Binder();
        final IBinder errorCallbackToken = new Binder();
        final Throwable exception = new IllegalArgumentException("Test exception");
        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));
        verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception));
    }
    }