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

Commit 9e8b53e3 authored by Kevin Chyn's avatar Kevin Chyn Committed by Automerger Merge Worker
Browse files

Merge "Synchronize DeviceStateController on WindowManagerGlobalLock" into udc-dev am: b02d5b38

parents 276bcea0 b02d5b38
Loading
Loading
Loading
Loading
+35 −10
Original line number Original line Diff line number Diff line
@@ -16,11 +16,13 @@


package com.android.server.wm;
package com.android.server.wm;


import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.content.Context;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Handler;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerExecutor;
import android.util.ArrayMap;


import com.android.internal.R;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
@@ -29,6 +31,8 @@ import com.android.internal.util.ArrayUtils;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.Consumer;


/**
/**
@@ -37,6 +41,9 @@ import java.util.function.Consumer;
 */
 */
final class DeviceStateController implements DeviceStateManager.DeviceStateCallback {
final class DeviceStateController implements DeviceStateManager.DeviceStateCallback {


    // Used to synchronize WindowManager services call paths with DeviceStateManager's callbacks.
    @NonNull
    private final WindowManagerGlobalLock mWmLock;
    @NonNull
    @NonNull
    private final DeviceStateManager mDeviceStateManager;
    private final DeviceStateManager mDeviceStateManager;
    @NonNull
    @NonNull
@@ -50,10 +57,10 @@ final class DeviceStateController implements DeviceStateManager.DeviceStateCallb
    private final int mConcurrentDisplayDeviceState;
    private final int mConcurrentDisplayDeviceState;
    @NonNull
    @NonNull
    private final int[] mReverseRotationAroundZAxisStates;
    private final int[] mReverseRotationAroundZAxisStates;
    @GuardedBy("this")
    @GuardedBy("mWmLock")
    @NonNull
    @NonNull
    @VisibleForTesting
    @VisibleForTesting
    final List<Consumer<DeviceState>> mDeviceStateCallbacks = new ArrayList<>();
    final Map<Consumer<DeviceState>, Executor> mDeviceStateCallbacks = new ArrayMap<>();


    private final boolean mMatchBuiltInDisplayOrientationToDefaultDisplay;
    private final boolean mMatchBuiltInDisplayOrientationToDefaultDisplay;


@@ -70,7 +77,9 @@ final class DeviceStateController implements DeviceStateManager.DeviceStateCallb
        CONCURRENT,
        CONCURRENT,
    }
    }


    DeviceStateController(@NonNull Context context, @NonNull Handler handler) {
    DeviceStateController(@NonNull Context context, @NonNull Handler handler,
            @NonNull WindowManagerGlobalLock wmLock) {
        mWmLock = wmLock;
        mDeviceStateManager = context.getSystemService(DeviceStateManager.class);
        mDeviceStateManager = context.getSystemService(DeviceStateManager.class);


        mOpenDeviceStates = context.getResources()
        mOpenDeviceStates = context.getResources()
@@ -94,14 +103,20 @@ final class DeviceStateController implements DeviceStateManager.DeviceStateCallb
        }
        }
    }
    }


    void registerDeviceStateCallback(@NonNull Consumer<DeviceState> callback) {
    /**
        synchronized (this) {
     * Registers a callback to be notified when the device state changes. Callers should always
            mDeviceStateCallbacks.add(callback);
     * post the work onto their own worker thread to avoid holding the WindowManagerGlobalLock for
     * an extended period of time.
     */
    void registerDeviceStateCallback(@NonNull Consumer<DeviceState> callback,
            @NonNull @CallbackExecutor Executor executor) {
        synchronized (mWmLock) {
            mDeviceStateCallbacks.put(callback, executor);
        }
        }
    }
    }


    void unregisterDeviceStateCallback(@NonNull Consumer<DeviceState> callback) {
    void unregisterDeviceStateCallback(@NonNull Consumer<DeviceState> callback) {
        synchronized (this) {
        synchronized (mWmLock) {
            mDeviceStateCallbacks.remove(callback);
            mDeviceStateCallbacks.remove(callback);
        }
        }
    }
    }
@@ -144,11 +159,21 @@ final class DeviceStateController implements DeviceStateManager.DeviceStateCallb
        if (mCurrentDeviceState == null || !mCurrentDeviceState.equals(deviceState)) {
        if (mCurrentDeviceState == null || !mCurrentDeviceState.equals(deviceState)) {
            mCurrentDeviceState = deviceState;
            mCurrentDeviceState = deviceState;


            synchronized (this) {
            // Make a copy here because it's possible that the consumer tries to remove a callback
                for (Consumer<DeviceState> callback : mDeviceStateCallbacks) {
            // while we're still iterating through the list, which would end up in a
                    callback.accept(mCurrentDeviceState);
            // ConcurrentModificationException.
            final List<Map.Entry<Consumer<DeviceState>, Executor>> entries = new ArrayList<>();
            synchronized (mWmLock) {
                for (Map.Entry<Consumer<DeviceState>, Executor> entry
                        : mDeviceStateCallbacks.entrySet()) {
                    entries.add(entry);
                }
                }
            }
            }

            for (int i = 0; i < entries.size(); i++) {
                Map.Entry<Consumer<DeviceState>, Executor> entry = entries.get(i);
                entry.getValue().execute(() -> entry.getKey().accept(mCurrentDeviceState));
            }
        }
        }
    }
    }
}
}
+3 −1
Original line number Original line Diff line number Diff line
@@ -188,6 +188,7 @@ import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Debug;
import android.os.Debug;
import android.os.Handler;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Message;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager;
@@ -1182,7 +1183,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
                    mDisplaySwitchTransitionLauncher.foldStateChanged(newFoldState);
                    mDisplaySwitchTransitionLauncher.foldStateChanged(newFoldState);
                    mDisplayRotation.foldStateChanged(newFoldState);
                    mDisplayRotation.foldStateChanged(newFoldState);
                };
                };
        mDeviceStateController.registerDeviceStateCallback(mDeviceStateConsumer);
        mDeviceStateController.registerDeviceStateCallback(mDeviceStateConsumer,
                new HandlerExecutor(mWmService.mH));


        mCloseToSquareMaxAspectRatio = mWmService.mContext.getResources().getFloat(
        mCloseToSquareMaxAspectRatio = mWmService.mContext.getResources().getFloat(
                R.dimen.config_closeToSquareDisplayMaxAspectRatio);
                R.dimen.config_closeToSquareDisplayMaxAspectRatio);
+2 −1
Original line number Original line Diff line number Diff line
@@ -438,7 +438,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        mTaskSupervisor = mService.mTaskSupervisor;
        mTaskSupervisor = mService.mTaskSupervisor;
        mTaskSupervisor.mRootWindowContainer = this;
        mTaskSupervisor.mRootWindowContainer = this;
        mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl(DISPLAY_OFF_SLEEP_TOKEN_TAG);
        mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl(DISPLAY_OFF_SLEEP_TOKEN_TAG);
        mDeviceStateController = new DeviceStateController(service.mContext, service.mH);
        mDeviceStateController = new DeviceStateController(service.mContext, service.mH,
                service.mGlobalLock);
        mDisplayRotationCoordinator = new DisplayRotationCoordinator();
        mDisplayRotationCoordinator = new DisplayRotationCoordinator();
    }
    }


+6 −3
Original line number Original line Diff line number Diff line
@@ -34,6 +34,8 @@ import androidx.test.filters.SmallTest;


import com.android.internal.R;
import com.android.internal.R;


import com.google.common.util.concurrent.MoreExecutors;

import org.junit.Before;
import org.junit.Before;
import org.junit.Test;
import org.junit.Test;


@@ -117,7 +119,7 @@ public class DeviceStateControllerTests {
    public void testUnregisterDeviceStateCallback() {
    public void testUnregisterDeviceStateCallback() {
        initialize(true /* supportFold */, true /* supportHalfFolded */);
        initialize(true /* supportFold */, true /* supportHalfFolded */);
        assertEquals(1, mTarget.mDeviceStateCallbacks.size());
        assertEquals(1, mTarget.mDeviceStateCallbacks.size());
        assertEquals(mDelegate, mTarget.mDeviceStateCallbacks.get(0));
        assertTrue(mTarget.mDeviceStateCallbacks.containsKey(mDelegate));


        mTarget.onStateChanged(mOpenDeviceStates[0]);
        mTarget.onStateChanged(mOpenDeviceStates[0]);
        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
@@ -194,8 +196,9 @@ public class DeviceStateControllerTests {
            when(mMockContext.getResources()).thenReturn((mockRes));
            when(mMockContext.getResources()).thenReturn((mockRes));
            mockFold(mSupportFold, mSupportHalfFold);
            mockFold(mSupportFold, mSupportHalfFold);
            Handler mockHandler = mock(Handler.class);
            Handler mockHandler = mock(Handler.class);
            mTarget = new DeviceStateController(mMockContext, mockHandler);
            mTarget = new DeviceStateController(mMockContext, mockHandler,
            mTarget.registerDeviceStateCallback(mDelegate);
                    new WindowManagerGlobalLock());
            mTarget.registerDeviceStateCallback(mDelegate, MoreExecutors.directExecutor());
        }
        }
    }
    }
}
}