From 2a51ba9bf1ac8b7776c08311bce2d956b2dfda83 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Thu, 28 Apr 2022 17:33:31 +0800 Subject: [PATCH] Toggle orientation sensor outside of WM lock Otherwise when turning on/off, the toggling of orientation sensor may spend time in IPC to HIDL::ISensors, which may block other callers to window manager service. Now the enable/disable are moved to the same thread (android.ui) that receives sensor events. Also remove UpdateRunnable because onProposedRotationChanged is already called on the handler thread. The original code just posts one more time. Bug: 225183104 Test: atest DisplayRotationTests Change-Id: I3d3b774fae1f5981533b79ebdbf6f651c803d511 --- .../android/server/wm/DisplayRotation.java | 63 +++++++------------ .../server/wm/DisplayRotationTests.java | 9 ++- 2 files changed, 30 insertions(+), 42 deletions(-) diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 5aacb094207ef..d111baea45b54 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -56,7 +56,6 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; -import android.util.SparseArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.view.IDisplayWindowRotationCallback; @@ -1024,13 +1023,7 @@ public class DisplayRotation { disable = false; // Enable listener if not already enabled. if (!mOrientationListener.mEnabled) { - // Don't clear the current sensor orientation if the keyguard is going away in - // dismiss mode. This allows window manager to use the last sensor reading to - // determine the orientation vs. falling back to the last known orientation if - // the sensor reading was cleared which can cause it to relaunch the app that - // will show in the wrong orientation first before correcting leading to app - // launch delays. - mOrientationListener.enable(true /* clearCurrentRotation */); + mOrientationListener.enable(); } } } @@ -1560,35 +1553,13 @@ public class DisplayRotation { proto.end(token); } - private class OrientationListener extends WindowOrientationListener { - final SparseArray mRunnableCache = new SparseArray<>(5); - boolean mEnabled; + private class OrientationListener extends WindowOrientationListener implements Runnable { + transient boolean mEnabled; OrientationListener(Context context, Handler handler) { super(context, handler); } - private class UpdateRunnable implements Runnable { - final int mRotation; - - UpdateRunnable(int rotation) { - mRotation = rotation; - } - - @Override - public void run() { - // Send interaction power boost to improve redraw performance. - mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); - if (isRotationChoicePossible(mCurrentAppOrientation)) { - final boolean isValid = isValidRotationChoice(mRotation); - sendProposedRotationChangeToStatusBarInternal(mRotation, isValid); - } else { - mService.updateRotation(false /* alwaysSendConfiguration */, - false /* forceRelayout */); - } - } - } - @Override public boolean isKeyguardLocked() { return mService.isKeyguardLocked(); @@ -1605,27 +1576,39 @@ public class DisplayRotation { @Override public void onProposedRotationChanged(int rotation) { ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation); - Runnable r = mRunnableCache.get(rotation, null); - if (r == null) { - r = new UpdateRunnable(rotation); - mRunnableCache.put(rotation, r); + // Send interaction power boost to improve redraw performance. + mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); + if (isRotationChoicePossible(mCurrentAppOrientation)) { + final boolean isValid = isValidRotationChoice(rotation); + sendProposedRotationChangeToStatusBarInternal(rotation, isValid); + } else { + mService.updateRotation(false /* alwaysSendConfiguration */, + false /* forceRelayout */); } - getHandler().post(r); } @Override - public void enable(boolean clearCurrentRotation) { - super.enable(clearCurrentRotation); + public void enable() { mEnabled = true; + getHandler().post(this); ProtoLog.v(WM_DEBUG_ORIENTATION, "Enabling listeners"); } @Override public void disable() { - super.disable(); mEnabled = false; + getHandler().post(this); ProtoLog.v(WM_DEBUG_ORIENTATION, "Disabling listeners"); } + + @Override + public void run() { + if (mEnabled) { + super.enable(); + } else { + super.disable(); + } + } } private class SettingsObserver extends ContentObserver { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index 25cff61c3b785..f981e6d98aa40 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -318,6 +318,7 @@ public class DisplayRotationTests { private void verifyOrientationListenerRegistration(int numOfInvocation) { final ArgumentCaptor listenerCaptor = ArgumentCaptor.forClass( SensorEventListener.class); + waitForUiHandler(); verify(mMockSensorManager, times(numOfInvocation)).registerListener( listenerCaptor.capture(), same(mFakeSensor), @@ -478,10 +479,14 @@ public class DisplayRotationTests { SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); } - private boolean waitForUiHandler() throws Exception { + private boolean waitForUiHandler() { final CountDownLatch latch = new CountDownLatch(1); UiThread.getHandler().post(latch::countDown); - return latch.await(UI_HANDLER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + try { + return latch.await(UI_HANDLER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException ignored) { + } + throw new AssertionError("Failed to wait for ui handler"); } @Test