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

Commit 1d8f49f3 authored by Jeff Chang's avatar Jeff Chang Committed by Android (Google) Code Review
Browse files

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

parents f6357101 5db29137
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -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())
+50 −5
Original line number Diff line number Diff line
@@ -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;

        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) {
            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();
+57 −20
Original line number Diff line number Diff line
@@ -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);
    }
}
+4 −5
Original line number Diff line number Diff line
@@ -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));
    }