Merge "Synchronize DeviceStateController on WindowManagerGlobalLock" into udc-dev
This commit is contained in:
@@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user