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

Commit 0709a084 authored by Simon Bowden's avatar Simon Bowden
Browse files

Don't expose vibrator controllers via VibrationThread.

Also move "toSequential" into VibrationStepConductor - there's no reason
for that to be outside.

Bug: 193792066
Test: atest
Change-Id: I3de6343871ac5269daab9698b66563b4fc394a68
parent ad20c09c
Loading
Loading
Loading
Loading
+14 −5
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.server.vibrator;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Build;
import android.os.CombinedVibration;
@@ -130,16 +129,17 @@ final class VibrationStepConductor {
                previousStepVibratorOffTimeout);
    }

    public void initializeForEffect(@NonNull CombinedVibration.Sequential vibration) {
    /** Called when this conductor is going to be started running by the VibrationThread. */
    public void prepareToStart() {
        if (Build.IS_DEBUGGABLE) {
            expectIsVibrationThread(true);
        }

        CombinedVibration.Sequential sequentialEffect = toSequential(mVibration.getEffect());
        synchronized (mLock) {
            mPendingVibrateSteps++;
            // This count is decremented at the completion of the step, so we don't subtract one.
            mRemainingStartSequentialEffectSteps = vibration.getEffects().size();
            mNextSteps.offer(new StartSequentialEffectStep(this, vibration));
            mRemainingStartSequentialEffectSteps = sequentialEffect.getEffects().size();
            mNextSteps.offer(new StartSequentialEffectStep(this, sequentialEffect));
        }
    }

@@ -447,6 +447,15 @@ final class VibrationStepConductor {
        }
    }

    private static CombinedVibration.Sequential toSequential(CombinedVibration effect) {
        if (effect instanceof CombinedVibration.Sequential) {
            return (CombinedVibration.Sequential) effect;
        }
        return (CombinedVibration.Sequential) CombinedVibration.startSequential()
                .addNext(effect)
                .combine();
    }

    /**
     * This check is used for debugging and documentation to indicate the thread that's expected
     * to invoke a given public method on this class. Most methods are only invoked by
+1 −21
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.server.vibrator;

import android.os.CombinedVibration;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.Process;
@@ -26,8 +25,6 @@ import android.os.WorkSource;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.VisibleForTesting;

import java.util.NoSuchElementException;

/** Plays a {@link Vibration} in dedicated thread. */
@@ -106,11 +103,6 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
        return mStepConductor.getVibration();
    }

    @VisibleForTesting
    SparseArray<VibratorController> getVibrators() {
        return mStepConductor.getVibrators();
    }

    @Override
    public void binderDied() {
        if (DEBUG) {
@@ -224,9 +216,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
    private void playVibration() {
        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playVibration");
        try {
            CombinedVibration.Sequential sequentialEffect =
                    toSequential(mStepConductor.getVibration().getEffect());
            mStepConductor.initializeForEffect(sequentialEffect);
            mStepConductor.prepareToStart();

            while (!mStepConductor.isFinished()) {
                // Skip wait and next step if mForceStop already happened.
@@ -265,14 +255,4 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
        }
    }

    private static CombinedVibration.Sequential toSequential(CombinedVibration effect) {
        if (effect instanceof CombinedVibration.Sequential) {
            return (CombinedVibration.Sequential) effect;
        }
        return (CombinedVibration.Sequential) CombinedVibration.startSequential()
                .addNext(effect)
                .combine();
    }

}
+52 −48
Original line number Diff line number Diff line
@@ -113,6 +113,9 @@ public class VibrationThreadTest {
    private TestLooper mTestLooper;
    private TestLooperAutoDispatcher mCustomTestLooperDispatcher;

    // Setup from the providers when VibrationThread is initialized.
    private SparseArray<VibratorController> mControllers;

    @Before
    public void setUp() throws Exception {
        mTestLooper = new TestLooper();
@@ -178,7 +181,7 @@ public class VibrationThreadTest {
        verify(mManagerHooks).noteVibratorOff(eq(UID));
        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());

        assertEquals(Arrays.asList(expectedOneShot(10)),
                mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -197,7 +200,7 @@ public class VibrationThreadTest {
        verify(mManagerHooks).noteVibratorOff(eq(UID));
        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());

        assertEquals(Arrays.asList(expectedOneShot(10)),
                mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -219,7 +222,7 @@ public class VibrationThreadTest {
        verify(mManagerHooks).noteVibratorOff(eq(UID));
        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());

        assertEquals(Arrays.asList(expectedOneShot(15)),
                mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -243,7 +246,7 @@ public class VibrationThreadTest {
                        thread, TEST_TIMEOUT_MILLIS));
        // Vibration still running after 2 cycles.
        assertTrue(thread.isAlive());
        assertTrue(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());

        thread.cancel();
        waitForCompletion(thread);
@@ -251,7 +254,7 @@ public class VibrationThreadTest {
        verify(mManagerHooks).noteVibratorOn(eq(UID), anyLong());
        verify(mManagerHooks).noteVibratorOff(eq(UID));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());

        List<Float> playedAmplitudes = fakeVibrator.getAmplitudes();
        assertFalse(fakeVibrator.getEffectSegments().isEmpty());
@@ -280,7 +283,7 @@ public class VibrationThreadTest {
        waitForCompletion(thread);

        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
        assertEquals(Arrays.asList(expectedOneShot(1000)), fakeVibrator.getEffectSegments());
    }

@@ -302,7 +305,7 @@ public class VibrationThreadTest {
        waitForCompletion(thread);

        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
        assertEquals(Arrays.asList(expectedOneShot(5550)), fakeVibrator.getEffectSegments());
    }

@@ -325,7 +328,7 @@ public class VibrationThreadTest {
        waitForCompletion(thread);

        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
        assertEquals(2, fakeVibrator.getEffectSegments().size());
        // First time turn vibrator ON for minimum of 1s.
        assertEquals(1000L, fakeVibrator.getEffectSegments().get(0).getDuration());
@@ -350,7 +353,7 @@ public class VibrationThreadTest {
                .compose();
        VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);

        assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), vibrationThread,
        assertTrue(waitUntil(t -> mControllers.get(VIBRATOR_ID).isVibrating(), vibrationThread,
                TEST_TIMEOUT_MILLIS));
        assertTrue(vibrationThread.isAlive());

@@ -363,7 +366,7 @@ public class VibrationThreadTest {
        waitForCompletion(cancellingThread);

        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
    }

    @Test
@@ -375,7 +378,7 @@ public class VibrationThreadTest {
        VibrationEffect effect = VibrationEffect.createWaveform(new long[]{100}, new int[]{100}, 0);
        VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);

        assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), vibrationThread,
        assertTrue(waitUntil(t -> mControllers.get(VIBRATOR_ID).isVibrating(), vibrationThread,
                TEST_TIMEOUT_MILLIS));
        assertTrue(vibrationThread.isAlive());

@@ -388,7 +391,7 @@ public class VibrationThreadTest {
        waitForCompletion(cancellingThread);

        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
    }

    @Test
@@ -404,7 +407,7 @@ public class VibrationThreadTest {
        verify(mManagerHooks).noteVibratorOff(eq(UID));
        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());

        assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_THUD)),
                mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -427,7 +430,7 @@ public class VibrationThreadTest {
        verify(mManagerHooks).noteVibratorOff(eq(UID));
        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());

        assertEquals(Arrays.asList(expectedOneShot(10)),
                mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -466,7 +469,7 @@ public class VibrationThreadTest {
        verify(mManagerHooks).noteVibratorOff(eq(UID));
        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
        assertEquals(Arrays.asList(
                expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0),
                expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f, 0)),
@@ -536,7 +539,7 @@ public class VibrationThreadTest {
        verify(mManagerHooks).noteVibratorOff(eq(UID));
        verify(mControllerCallbacks, times(4)).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
        assertEquals(Arrays.asList(
                expectedOneShot(10),
                expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0),
@@ -573,7 +576,7 @@ public class VibrationThreadTest {
        verify(mManagerHooks).noteVibratorOff(eq(UID));
        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
        assertEquals(Arrays.asList(
                expectedRamp(/* amplitude= */ 1, /* frequencyHz= */ 150, /* duration= */ 10),
                expectedRamp(/* startAmplitude= */ 1, /* endAmplitude= */ 0,
@@ -626,11 +629,11 @@ public class VibrationThreadTest {
                TEST_TIMEOUT_MILLIS));
        // Vibration still running after 2 cycles.
        assertTrue(thread.isAlive());
        assertTrue(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());

        thread.binderDied();
        waitForCompletion(thread);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());

        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
    }
@@ -667,7 +670,7 @@ public class VibrationThreadTest {
        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
        verify(mControllerCallbacks, never()).onComplete(eq(2), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());

        assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_TICK)),
                mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -692,9 +695,9 @@ public class VibrationThreadTest {
        verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
        verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(1).isVibrating());
        assertFalse(thread.getVibrators().get(2).isVibrating());
        assertFalse(thread.getVibrators().get(3).isVibrating());
        assertFalse(mControllers.get(1).isVibrating());
        assertFalse(mControllers.get(2).isVibrating());
        assertFalse(mControllers.get(3).isVibrating());

        VibrationEffectSegment expected = expectedPrebaked(VibrationEffect.EFFECT_CLICK);
        assertEquals(Arrays.asList(expected), mVibratorProviders.get(1).getEffectSegments());
@@ -731,10 +734,10 @@ public class VibrationThreadTest {
        verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
        verify(mControllerCallbacks).onComplete(eq(4), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(1).isVibrating());
        assertFalse(thread.getVibrators().get(2).isVibrating());
        assertFalse(thread.getVibrators().get(3).isVibrating());
        assertFalse(thread.getVibrators().get(4).isVibrating());
        assertFalse(mControllers.get(1).isVibrating());
        assertFalse(mControllers.get(2).isVibrating());
        assertFalse(mControllers.get(3).isVibrating());
        assertFalse(mControllers.get(4).isVibrating());

        assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)),
                mVibratorProviders.get(1).getEffectSegments());
@@ -782,9 +785,9 @@ public class VibrationThreadTest {
        batteryVerifier.verify(mManagerHooks).noteVibratorOff(eq(UID));

        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(1).isVibrating());
        assertFalse(thread.getVibrators().get(2).isVibrating());
        assertFalse(thread.getVibrators().get(3).isVibrating());
        assertFalse(mControllers.get(1).isVibrating());
        assertFalse(mControllers.get(2).isVibrating());
        assertFalse(mControllers.get(3).isVibrating());

        assertEquals(Arrays.asList(expectedOneShot(10)),
                mVibratorProviders.get(1).getEffectSegments());
@@ -941,9 +944,9 @@ public class VibrationThreadTest {

        // All vibrators are turned on in parallel.
        assertTrue(waitUntil(
                t -> t.getVibrators().get(1).isVibrating()
                        && t.getVibrators().get(2).isVibrating()
                        && t.getVibrators().get(3).isVibrating(),
                t -> mControllers.get(1).isVibrating()
                        && mControllers.get(2).isVibrating()
                        && mControllers.get(3).isVibrating(),
                thread, TEST_TIMEOUT_MILLIS));

        waitForCompletion(thread);
@@ -954,9 +957,9 @@ public class VibrationThreadTest {
        verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
        verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
        assertFalse(thread.getVibrators().get(1).isVibrating());
        assertFalse(thread.getVibrators().get(2).isVibrating());
        assertFalse(thread.getVibrators().get(3).isVibrating());
        assertFalse(mControllers.get(1).isVibrating());
        assertFalse(mControllers.get(2).isVibrating());
        assertFalse(mControllers.get(3).isVibrating());

        assertEquals(Arrays.asList(expectedOneShot(25)),
                mVibratorProviders.get(1).getEffectSegments());
@@ -1031,7 +1034,7 @@ public class VibrationThreadTest {
        // After the vibrator call ends the vibration is cancelled and the vibrator is turned off.
        waitForCompletion(vibrationThread, /* timeout= */ latency + TEST_TIMEOUT_MILLIS);
        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
    }

    @Test
@@ -1051,7 +1054,7 @@ public class VibrationThreadTest {
                .combine();
        VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);

        assertTrue(waitUntil(t -> t.getVibrators().get(2).isVibrating(), vibrationThread,
        assertTrue(waitUntil(t -> mControllers.get(2).isVibrating(), vibrationThread,
                TEST_TIMEOUT_MILLIS));
        assertTrue(vibrationThread.isAlive());

@@ -1064,8 +1067,8 @@ public class VibrationThreadTest {
        waitForCompletion(cancellingThread);

        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(vibrationThread.getVibrators().get(1).isVibrating());
        assertFalse(vibrationThread.getVibrators().get(2).isVibrating());
        assertFalse(mControllers.get(1).isVibrating());
        assertFalse(mControllers.get(2).isVibrating());
    }

    @Test
@@ -1082,8 +1085,8 @@ public class VibrationThreadTest {
                .combine();
        VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);

        assertTrue(waitUntil(t -> t.getVibrators().get(1).isVibrating()
                        && t.getVibrators().get(2).isVibrating(),
        assertTrue(waitUntil(t -> mControllers.get(1).isVibrating()
                        && mControllers.get(2).isVibrating(),
                vibrationThread, TEST_TIMEOUT_MILLIS));
        assertTrue(vibrationThread.isAlive());

@@ -1096,8 +1099,8 @@ public class VibrationThreadTest {
        waitForCompletion(cancellingThread);

        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(vibrationThread.getVibrators().get(1).isVibrating());
        assertFalse(vibrationThread.getVibrators().get(2).isVibrating());
        assertFalse(mControllers.get(1).isVibrating());
        assertFalse(mControllers.get(2).isVibrating());
    }

    @Test
@@ -1106,7 +1109,7 @@ public class VibrationThreadTest {
        VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0);
        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);

        assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), thread,
        assertTrue(waitUntil(t -> mControllers.get(VIBRATOR_ID).isVibrating(), thread,
                TEST_TIMEOUT_MILLIS));
        assertTrue(thread.isAlive());

@@ -1117,7 +1120,7 @@ public class VibrationThreadTest {
        verify(mVibrationToken).unlinkToDeath(same(thread), eq(0));
        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
        assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments().isEmpty());
        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
    }

    @Test
@@ -1188,7 +1191,7 @@ public class VibrationThreadTest {
        long vibrationId = 1;
        VibrationEffect effect = VibrationEffect.createOneShot(10_000, 240);
        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
        assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), thread,
        assertTrue(waitUntil(t -> mControllers.get(VIBRATOR_ID).isVibrating(), thread,
                TEST_TIMEOUT_MILLIS));
        thread.cancel();
        waitForCompletion(thread);
@@ -1295,8 +1298,9 @@ public class VibrationThreadTest {
    }

    private VibrationThread startThreadAndDispatcher(Vibration vib) {
        mControllers = createVibratorControllers();
        VibrationThread thread = new VibrationThread(vib, mVibrationSettings, mEffectAdapter,
                createVibratorControllers(), mWakeLock, mManagerHooks);
                mControllers, mWakeLock, mManagerHooks);
        doAnswer(answer -> {
            thread.vibratorComplete(answer.getArgument(0));
            return null;