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
This commit is contained in:
Riddle Hsu
2022-04-28 17:33:31 +08:00
parent 9736fb2a2b
commit 2a51ba9bf1
2 changed files with 30 additions and 42 deletions

View File

@@ -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<Runnable> 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 {

View File

@@ -318,6 +318,7 @@ public class DisplayRotationTests {
private void verifyOrientationListenerRegistration(int numOfInvocation) {
final ArgumentCaptor<SensorEventListener> 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