From 9fdaad5598a35bce58bfc8192f2bf19aa83adbc9 Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Tue, 31 Aug 2021 18:47:20 +0100 Subject: [PATCH] Set external control to false on VibratorManagerService init The VibratorManagerService turns off all vibrators during initialization to handle the scenario where the system server has restarted (e.g. after being killed by watchdog after a deadlock) but the vibrator hardware was still performing a previous vibrate command. This also sets the external control state to false, so the service won't attemp to vibrate when the hardware is actually set for external control. Bug: 197165183 Test: VibratorManagerServiceTest Change-Id: If4f0df57333fb5863fe9c1e781575634606ee662 --- .../server/vibrator/VibratorController.java | 11 +++++++++- .../vibrator/VibratorManagerService.java | 2 +- .../FakeVibratorControllerProvider.java | 7 +++++++ .../vibrator/VibratorControllerTest.java | 15 +++++++++++++ .../vibrator/VibratorManagerServiceTest.java | 21 ++++++++++++++++--- 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java index 69cc90bf381ec..efccd57d2fc3e 100644 --- a/services/core/java/com/android/server/vibrator/VibratorController.java +++ b/services/core/java/com/android/server/vibrator/VibratorController.java @@ -304,7 +304,7 @@ final class VibratorController { } } - /** Turns off the vibrator.This will affect the state of {@link #isVibrating()}. */ + /** Turns off the vibrator. This will affect the state of {@link #isVibrating()}. */ public void off() { synchronized (mLock) { mNativeWrapper.off(); @@ -313,6 +313,15 @@ final class VibratorController { } } + /** + * Resets the vibrator hardware to a default state. + * This turns the vibrator off, which will affect the state of {@link #isVibrating()}. + */ + public void reset() { + setExternalControl(false); + off(); + } + @Override public String toString() { synchronized (mLock) { diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index c5c0325e55907..567463fd7725d 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -219,7 +219,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { // fresh boot. mNativeWrapper.cancelSynced(); for (int i = 0; i < mVibrators.size(); i++) { - mVibrators.valueAt(i).off(); + mVibrators.valueAt(i).reset(); } IntentFilter filter = new IntentFilter(); diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java index 75f8a44c6f865..378304d024e53 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java @@ -52,6 +52,7 @@ final class FakeVibratorControllerProvider { private boolean mIsAvailable = true; private long mLatency; + private int mOffCount; private int mCapabilities; private int[] mSupportedEffects; @@ -93,6 +94,7 @@ final class FakeVibratorControllerProvider { @Override public void off() { + mOffCount++; } @Override @@ -308,6 +310,11 @@ final class FakeVibratorControllerProvider { return mExternalControlStates; } + /** Returns the number of times the vibrator was turned off. */ + public int getOffCount() { + return mOffCount; + } + /** * Return the {@link PrebakedSegment} effect enabled with given id, or {@code null} if * missing or disabled. diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java index a732bd18676ab..9fb8b38a706e5 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java @@ -258,6 +258,21 @@ public class VibratorControllerTest { verify(mNativeWrapperMock, times(2)).off(); } + @Test + public void reset_turnsOffVibratorAndDisablesExternalControl() { + mockVibratorCapabilities(IVibrator.CAP_EXTERNAL_CONTROL); + when(mNativeWrapperMock.on(anyLong(), anyLong())).thenAnswer(args -> args.getArgument(0)); + VibratorController controller = createController(); + + controller.on(100, 1); + assertTrue(controller.isVibrating()); + + controller.reset(); + assertFalse(controller.isVibrating()); + verify(mNativeWrapperMock).setExternalControl(eq(false)); + verify(mNativeWrapperMock).off(); + } + @Test public void registerVibratorStateListener_callbacksAreTriggered() throws Exception { when(mNativeWrapperMock.on(anyLong(), anyLong())).thenAnswer(args -> args.getArgument(0)); diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index 2c5159aef1e25..f9e63d1b1d0ac 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -232,6 +232,19 @@ public class VibratorManagerServiceTest { assertTrue(mVibratorProviders.get(2).isInitialized()); } + @Test + public void createService_resetsVibrators() { + mockVibrators(1, 2); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL); + mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL); + + createService(); + assertEquals(1, mVibratorProviders.get(1).getOffCount()); + assertEquals(1, mVibratorProviders.get(2).getOffCount()); + assertEquals(Arrays.asList(false), mVibratorProviders.get(1).getExternalControlStates()); + assertEquals(Arrays.asList(false), mVibratorProviders.get(2).getExternalControlStates()); + } + @Test public void createService_doNotCrashIfUsedBeforeSystemReady() { mockVibrators(1, 2); @@ -991,7 +1004,7 @@ public class VibratorManagerServiceTest { mExternalVibratorService.onExternalVibrationStop(externalVibration); assertEquals(IExternalVibratorService.SCALE_NONE, scale); - assertEquals(Arrays.asList(true, false), + assertEquals(Arrays.asList(false, true, false), mVibratorProviders.get(1).getExternalControlStates()); } @@ -1017,7 +1030,8 @@ public class VibratorManagerServiceTest { verify(firstController).mute(); verify(secondController, never()).mute(); // Set external control called only once. - assertEquals(Arrays.asList(true), mVibratorProviders.get(1).getExternalControlStates()); + assertEquals(Arrays.asList(false, true), + mVibratorProviders.get(1).getExternalControlStates()); } @Test @@ -1039,7 +1053,8 @@ public class VibratorManagerServiceTest { // Vibration is cancelled. assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); - assertEquals(Arrays.asList(true), mVibratorProviders.get(1).getExternalControlStates()); + assertEquals(Arrays.asList(false, true), + mVibratorProviders.get(1).getExternalControlStates()); } private VibrationEffectSegment expectedPrebaked(int effectId) {