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

Commit 4300398b authored by Tiger Huang's avatar Tiger Huang Committed by Android (Google) Code Review
Browse files

Merge "Remove the local insets sources if the owner dies" into udc-qpr-dev

parents aaff159b 83939656
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -688,6 +688,7 @@ public final class WindowContainerTransaction implements Parcelable {
                        .setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type)
                                .setSource(InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE)
                                .setArbitraryRectangle(frame))
                        .setInsetsFrameOwner(owner)
                        .build();
        mHierarchyOps.add(hierarchyOp);
        return this;
@@ -712,6 +713,7 @@ public final class WindowContainerTransaction implements Parcelable {
                new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER)
                        .setContainer(receiver.asBinder())
                        .setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type))
                        .setInsetsFrameOwner(owner)
                        .build();
        mHierarchyOps.add(hierarchyOp);
        return this;
@@ -1344,8 +1346,12 @@ public final class WindowContainerTransaction implements Parcelable {
        @Nullable
        private IBinder mReparent;

        @Nullable
        private InsetsFrameProvider mInsetsFrameProvider;

        @Nullable
        private IBinder mInsetsFrameOwner;

        // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
        private boolean mToTop;

@@ -1478,6 +1484,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mContainer = copy.mContainer;
            mReparent = copy.mReparent;
            mInsetsFrameProvider = copy.mInsetsFrameProvider;
            mInsetsFrameOwner = copy.mInsetsFrameOwner;
            mToTop = copy.mToTop;
            mReparentTopOnly = copy.mReparentTopOnly;
            mWindowingModes = copy.mWindowingModes;
@@ -1496,6 +1503,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mContainer = in.readStrongBinder();
            mReparent = in.readStrongBinder();
            mInsetsFrameProvider = in.readTypedObject(InsetsFrameProvider.CREATOR);
            mInsetsFrameOwner = in.readStrongBinder();
            mToTop = in.readBoolean();
            mReparentTopOnly = in.readBoolean();
            mWindowingModes = in.createIntArray();
@@ -1527,6 +1535,11 @@ public final class WindowContainerTransaction implements Parcelable {
            return mInsetsFrameProvider;
        }

        @Nullable
        public IBinder getInsetsFrameOwner() {
            return mInsetsFrameOwner;
        }

        @NonNull
        public IBinder getContainer() {
            return mContainer;
@@ -1657,7 +1670,8 @@ public final class WindowContainerTransaction implements Parcelable {
                case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER:
                case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER:
                    sb.append("container=").append(mContainer)
                            .append(" provider=").append(mInsetsFrameProvider);
                            .append(" provider=").append(mInsetsFrameProvider)
                            .append(" owner=").append(mInsetsFrameOwner);
                    break;
                case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
                    sb.append("container=").append(mContainer)
@@ -1697,6 +1711,7 @@ public final class WindowContainerTransaction implements Parcelable {
            dest.writeStrongBinder(mContainer);
            dest.writeStrongBinder(mReparent);
            dest.writeTypedObject(mInsetsFrameProvider, flags);
            dest.writeStrongBinder(mInsetsFrameOwner);
            dest.writeBoolean(mToTop);
            dest.writeBoolean(mReparentTopOnly);
            dest.writeIntArray(mWindowingModes);
@@ -1737,8 +1752,12 @@ public final class WindowContainerTransaction implements Parcelable {
            @Nullable
            private IBinder mReparent;

            @Nullable
            private InsetsFrameProvider mInsetsFrameProvider;

            @Nullable
            private IBinder mInsetsFrameOwner;

            private boolean mToTop;

            private boolean mReparentTopOnly;
@@ -1782,8 +1801,13 @@ public final class WindowContainerTransaction implements Parcelable {
                return this;
            }

            Builder setInsetsFrameProvider(InsetsFrameProvider providers) {
                mInsetsFrameProvider = providers;
            Builder setInsetsFrameProvider(InsetsFrameProvider provider) {
                mInsetsFrameProvider = provider;
                return this;
            }

            Builder setInsetsFrameOwner(IBinder owner) {
                mInsetsFrameOwner = owner;
                return this;
            }

@@ -1854,6 +1878,7 @@ public final class WindowContainerTransaction implements Parcelable {
                        ? Arrays.copyOf(mActivityTypes, mActivityTypes.length)
                        : null;
                hierarchyOp.mInsetsFrameProvider = mInsetsFrameProvider;
                hierarchyOp.mInsetsFrameOwner = mInsetsFrameOwner;
                hierarchyOp.mToTop = mToTop;
                hierarchyOp.mReparentTopOnly = mReparentTopOnly;
                hierarchyOp.mLaunchOptions = mLaunchOptions;
+90 −18
Original line number Diff line number Diff line
@@ -81,7 +81,9 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Pools;
@@ -174,6 +176,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     */
    protected SparseArray<InsetsSourceProvider> mInsetsSourceProviders = null;

    @Nullable
    private ArrayMap<IBinder, DeathRecipient> mInsetsOwnerDeathRecipientMap;

    // List of children for this window container. List is in z-order as the children appear on
    // screen with the top-most window container at the tail of the list.
    protected final WindowList<E> mChildren = new WindowList<E>();
@@ -419,11 +424,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     * Adds an {@link InsetsFrameProvider} which describes what insets should be provided to
     * this {@link WindowContainer} and its children.
     *
     * @param provider describes the insets types and the frames.
     * @param provider describes the insets type and the frame.
     * @param owner owns the insets source which only exists when the owner is alive.
     */
    void addLocalInsetsFrameProvider(InsetsFrameProvider provider) {
        if (provider == null) {
            throw new IllegalArgumentException("Insets type not specified.");
    void addLocalInsetsFrameProvider(InsetsFrameProvider provider, IBinder owner) {
        if (provider == null || owner == null) {
            throw new IllegalArgumentException("Insets provider or owner not specified.");
        }
        if (mDisplayContent == null) {
            // This is possible this container is detached when WM shell is responding to a previous
@@ -432,10 +438,26 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
            Slog.w(TAG, "Can't add insets frame provider when detached. " + this);
            return;
        }

        if (mInsetsOwnerDeathRecipientMap == null) {
            mInsetsOwnerDeathRecipientMap = new ArrayMap<>();
        }
        DeathRecipient deathRecipient = mInsetsOwnerDeathRecipientMap.get(owner);
        if (deathRecipient == null) {
            deathRecipient = new DeathRecipient(owner);
            try {
                owner.linkToDeath(deathRecipient, 0);
            } catch (RemoteException e) {
                Slog.w(TAG, "Failed to add source for " + provider + " since the owner has died.");
                return;
            }
            mInsetsOwnerDeathRecipientMap.put(owner, deathRecipient);
        }
        final int id = provider.getId();
        deathRecipient.addSourceId(id);
        if (mLocalInsetsSources == null) {
            mLocalInsetsSources = new SparseArray<>();
        }
        final int id = provider.getId();
        if (mLocalInsetsSources.get(id) != null) {
            if (DEBUG) {
                Slog.d(TAG, "The local insets source for this " + provider
@@ -448,27 +470,77 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
    }

    void removeLocalInsetsFrameProvider(InsetsFrameProvider provider) {
        if (provider == null) {
            throw new IllegalArgumentException("Insets type not specified.");
    private class DeathRecipient implements IBinder.DeathRecipient {

        private final IBinder mOwner;
        private final ArraySet<Integer> mSourceIds = new ArraySet<>();

        DeathRecipient(IBinder owner) {
            mOwner = owner;
        }

        void addSourceId(int id) {
            mSourceIds.add(id);
        }

        void removeSourceId(int id) {
            mSourceIds.remove(id);
        }

        boolean hasSource() {
            return !mSourceIds.isEmpty();
        }

        @Override
        public void binderDied() {
            synchronized (mWmService.mGlobalLock) {
                boolean changed = false;
                for (int i = mSourceIds.size() - 1; i >= 0; i--) {
                    changed |= removeLocalInsetsSource(mSourceIds.valueAt(i));
                }
                mSourceIds.clear();
                mOwner.unlinkToDeath(this, 0);
                mInsetsOwnerDeathRecipientMap.remove(mOwner);
                if (changed && mDisplayContent != null) {
                    mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
                }
            }
        }
        if (mLocalInsetsSources == null) {
            return;
    }

    void removeLocalInsetsFrameProvider(InsetsFrameProvider provider, IBinder owner) {
        if (provider == null || owner == null) {
            throw new IllegalArgumentException("Insets provider or owner not specified.");
        }
        final int id = provider.getId();
        if (mLocalInsetsSources.get(id) == null) {
            if (DEBUG) {
                Slog.d(TAG, "Given " + provider + " doesn't have a local insets source.");
        if (removeLocalInsetsSource(id) && mDisplayContent != null) {
            mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
        }
        if (mInsetsOwnerDeathRecipientMap == null) {
            return;
        }
        mLocalInsetsSources.remove(id);
        final DeathRecipient deathRecipient = mInsetsOwnerDeathRecipientMap.get(owner);
        if (deathRecipient == null) {
            return;
        }
        deathRecipient.removeSourceId(id);
        if (!deathRecipient.hasSource()) {
            owner.unlinkToDeath(deathRecipient, 0);
            mInsetsOwnerDeathRecipientMap.remove(owner);
        }
    }

        // Update insets if this window is attached.
        if (mDisplayContent != null) {
            mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
    private boolean removeLocalInsetsSource(int id) {
        if (mLocalInsetsSources == null) {
            return false;
        }
        if (mLocalInsetsSources.removeReturnOld(id) == null) {
            if (DEBUG) {
                Slog.d(TAG, "Given id " + Integer.toHexString(id) + " doesn't exist.");
            }
            return false;
        }
        return true;
    }

    /**
+4 −2
Original line number Diff line number Diff line
@@ -1090,7 +1090,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                            + container);
                    break;
                }
                container.addLocalInsetsFrameProvider(hop.getInsetsFrameProvider());
                container.addLocalInsetsFrameProvider(
                        hop.getInsetsFrameProvider(), hop.getInsetsFrameOwner());
                break;
            }
            case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER: {
@@ -1100,7 +1101,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                                    + container);
                    break;
                }
                container.removeLocalInsetsFrameProvider(hop.getInsetsFrameProvider());
                container.removeLocalInsetsFrameProvider(
                        hop.getInsetsFrameProvider(), hop.getInsetsFrameOwner());
                break;
            }
            case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: {
+169 −16
Original line number Diff line number Diff line
@@ -64,10 +64,19 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.clearInvocations;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.platform.test.annotations.Presubmit;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -87,8 +96,10 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.NoSuchElementException;


/**
@@ -1404,7 +1415,7 @@ public class WindowContainerTests extends WindowTestsBase {
    }

    @Test
    public void testAddLocalInsetsSourceProvider() {
    public void testAddLocalInsetsFrameProvider() {
         /*
                ___ rootTask _______________________________________________
               |        |                |                                  |
@@ -1435,19 +1446,20 @@ public class WindowContainerTests extends WindowTestsBase {
                TYPE_BASE_APPLICATION);
        attrs2.setTitle("AppWindow2");
        activity2.addWindow(createWindowState(attrs2, activity2));
        final Binder owner = new Binder();
        Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700);
        Rect genericOverlayInsetsRect2 = new Rect(0, 0, 1080, 200);
        final InsetsFrameProvider provider1 =
                new InsetsFrameProvider(null, 1, WindowInsets.Type.systemOverlays())
                new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
                        .setArbitraryRectangle(genericOverlayInsetsRect1);
        final InsetsFrameProvider provider2 =
                new InsetsFrameProvider(null, 2, WindowInsets.Type.systemOverlays())
                new InsetsFrameProvider(owner, 2, WindowInsets.Type.systemOverlays())
                        .setArbitraryRectangle(genericOverlayInsetsRect2);
        final int sourceId1 = provider1.getId();
        final int sourceId2 = provider2.getId();

        rootTask.addLocalInsetsFrameProvider(provider1);
        container.addLocalInsetsFrameProvider(provider2);
        rootTask.addLocalInsetsFrameProvider(provider1, owner);
        container.addLocalInsetsFrameProvider(provider2, owner);

        InsetsSource genericOverlayInsetsProvider1Source = new InsetsSource(
                sourceId1, systemOverlays());
@@ -1479,7 +1491,7 @@ public class WindowContainerTests extends WindowTestsBase {
    }

    @Test
    public void testAddLocalInsetsSourceProvider_sameType_replacesInsets() {
    public void testAddLocalInsetsFrameProvider_sameType_replacesInsets() {
         /*
                ___ rootTask ________________________________________
               |                  |                                  |
@@ -1494,24 +1506,25 @@ public class WindowContainerTests extends WindowTestsBase {
        attrs.setTitle("AppWindow0");
        activity0.addWindow(createWindowState(attrs, activity0));

        final Binder owner = new Binder();
        final Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700);
        final Rect genericOverlayInsetsRect2 = new Rect(0, 0, 1080, 200);
        final InsetsFrameProvider provider1 =
                new InsetsFrameProvider(null, 1, WindowInsets.Type.systemOverlays())
                new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
                        .setArbitraryRectangle(genericOverlayInsetsRect1);
        final InsetsFrameProvider provider2 =
                new InsetsFrameProvider(null, 1, WindowInsets.Type.systemOverlays())
                new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
                        .setArbitraryRectangle(genericOverlayInsetsRect2);
        final int sourceId1 = provider1.getId();
        final int sourceId2 = provider2.getId();

        rootTask.addLocalInsetsFrameProvider(provider1);
        rootTask.addLocalInsetsFrameProvider(provider1, owner);
        activity0.forAllWindows(window -> {
            assertEquals(genericOverlayInsetsRect1,
                    window.getInsetsState().peekSource(sourceId1).getFrame());
        }, true);

        rootTask.addLocalInsetsFrameProvider(provider2);
        rootTask.addLocalInsetsFrameProvider(provider2, owner);

        activity0.forAllWindows(window -> {
            assertEquals(genericOverlayInsetsRect2,
@@ -1520,7 +1533,7 @@ public class WindowContainerTests extends WindowTestsBase {
    }

    @Test
    public void testRemoveLocalInsetsSourceProvider() {
    public void testRemoveLocalInsetsFrameProvider() {
         /*
                ___ rootTask _______________________________________________
               |        |                |                                  |
@@ -1554,21 +1567,22 @@ public class WindowContainerTests extends WindowTestsBase {

        activity2.addWindow(createWindowState(attrs2, activity2));

        final Binder owner = new Binder();
        final Rect navigationBarInsetsRect1 = new Rect(0, 200, 1080, 700);
        final Rect navigationBarInsetsRect2 = new Rect(0, 0, 1080, 200);
        final InsetsFrameProvider provider1 =
                new InsetsFrameProvider(null, 1, WindowInsets.Type.systemOverlays())
                new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
                        .setArbitraryRectangle(navigationBarInsetsRect1);
        final InsetsFrameProvider provider2 =
                new InsetsFrameProvider(null, 2, WindowInsets.Type.systemOverlays())
                new InsetsFrameProvider(owner, 2, WindowInsets.Type.systemOverlays())
                        .setArbitraryRectangle(navigationBarInsetsRect2);
        final int sourceId1 = provider1.getId();
        final int sourceId2 = provider2.getId();

        rootTask.addLocalInsetsFrameProvider(provider1);
        container.addLocalInsetsFrameProvider(provider2);
        rootTask.addLocalInsetsFrameProvider(provider1, owner);
        container.addLocalInsetsFrameProvider(provider2, owner);
        mDisplayContent.getInsetsStateController().onPostLayout();
        rootTask.removeLocalInsetsFrameProvider(provider1);
        rootTask.removeLocalInsetsFrameProvider(provider1, owner);
        mDisplayContent.getInsetsStateController().onPostLayout();

        activity0.forAllWindows(window -> {
@@ -1593,6 +1607,67 @@ public class WindowContainerTests extends WindowTestsBase {
        }, true);
    }

    @Test
    public void testAddLocalInsetsFrameProvider_ownerDiesAfterAdding() {
        final Task task = createTask(mDisplayContent);
        final TestBinder owner = new TestBinder();
        final InsetsFrameProvider provider =
                new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays())
                        .setArbitraryRectangle(new Rect());
        task.addLocalInsetsFrameProvider(provider, owner);

        assertTrue("The death recipient must exist.", owner.hasDeathRecipient());
        assertTrue("The source must be added.", hasLocalSource(task, provider.getId()));

        // The owner dies after adding the source.
        owner.die();

        assertFalse("The death recipient must be removed.", owner.hasDeathRecipient());
        assertFalse("The source must be removed.", hasLocalSource(task, provider.getId()));
    }

    @Test
    public void testAddLocalInsetsFrameProvider_ownerDiesBeforeAdding() {
        final Task task = createTask(mDisplayContent);
        final TestBinder owner = new TestBinder();

        // The owner dies before adding the source.
        owner.die();

        final InsetsFrameProvider provider =
                new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays())
                        .setArbitraryRectangle(new Rect());
        task.addLocalInsetsFrameProvider(provider, owner);

        assertFalse("The death recipient must not exist.", owner.hasDeathRecipient());
        assertFalse("The source must not be added.", hasLocalSource(task, provider.getId()));
    }

    @Test
    public void testRemoveLocalInsetsFrameProvider_removeDeathRecipient() {
        final Task task = createTask(mDisplayContent);
        final TestBinder owner = new TestBinder();
        final InsetsFrameProvider provider =
                new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays())
                        .setArbitraryRectangle(new Rect());
        task.addLocalInsetsFrameProvider(provider, owner);

        assertTrue("The death recipient must exist.", owner.hasDeathRecipient());
        assertTrue("The source must be added.", hasLocalSource(task, provider.getId()));

        task.removeLocalInsetsFrameProvider(provider, owner);

        assertFalse("The death recipient must be removed.", owner.hasDeathRecipient());
        assertFalse("The source must be removed.", hasLocalSource(task, provider.getId()));
    }

    private static boolean hasLocalSource(WindowContainer container, int sourceId) {
        if (container.mLocalInsetsSources == null) {
            return false;
        }
        return container.mLocalInsetsSources.contains(sourceId);
    }

    /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
    private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
        private final int mLayer;
@@ -1797,4 +1872,82 @@ public class WindowContainerTests extends WindowTestsBase {
            mIsVisibleRequested = isVisibleRequested;
        }
    }

    private static class TestBinder implements IBinder {

        private boolean mDead;
        private final ArrayList<IBinder.DeathRecipient> mDeathRecipients = new ArrayList<>();

        public void die() {
            mDead = true;
            for (int i = mDeathRecipients.size() - 1; i >= 0; i--) {
                final DeathRecipient recipient = mDeathRecipients.get(i);
                recipient.binderDied(this);
            }
        }

        public boolean hasDeathRecipient() {
            return !mDeathRecipients.isEmpty();
        }

        @Override
        public void linkToDeath(@NonNull DeathRecipient recipient, int flags)
                throws RemoteException {
            if (mDead) {
                throw new DeadObjectException();
            }
            mDeathRecipients.add(recipient);
        }

        @Override
        public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
            final boolean successes = mDeathRecipients.remove(recipient);
            if (successes || mDead) {
                return successes;
            }
            throw new NoSuchElementException("Given recipient has not been registered.");
        }

        @Override
        public boolean isBinderAlive() {
            return !mDead;
        }

        @Override
        public boolean pingBinder() {
            return !mDead;
        }

        @Nullable
        @Override
        public String getInterfaceDescriptor() throws RemoteException {
            return null;
        }

        @Nullable
        @Override
        public IInterface queryLocalInterface(@NonNull String descriptor) {
            return null;
        }

        @Override
        public void dump(@NonNull FileDescriptor fd, @Nullable String[] args)
                throws RemoteException { }

        @Override
        public void dumpAsync(@NonNull FileDescriptor fd, @Nullable String[] args)
                throws RemoteException { }

        @Override
        public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
                @Nullable FileDescriptor err, @NonNull String[] args,
                @Nullable ShellCallback shellCallback,
                @NonNull ResultReceiver resultReceiver) throws RemoteException { }

        @Override
        public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
                throws RemoteException {
            return false;
        }
    }
}