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

Commit 9c96573c authored by Simon Bowden's avatar Simon Bowden Committed by Automerger Merge Worker
Browse files

Merge "Ensure unlinkToDeath when cancelling external vibrations." into tm-dev...

Merge "Ensure unlinkToDeath when cancelling external vibrations." into tm-dev am: 4dfe4924 am: baaf4942

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17071468

Change-Id: I547750fda5e5c4ff920d3eea7ba8c520ed25d5cc
parents ef718496 baaf4942
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -47,7 +47,13 @@ public class ExternalVibration implements Parcelable {
        this(uid, pkg, attrs, controller, new Binder());
    }

    private ExternalVibration(int uid, @NonNull String pkg, @NonNull AudioAttributes attrs,
    /**
     * Full constructor, but exposed to construct the ExternalVibration with an explicit binder
     * token (for mocks).
     *
     * @hide
     */
    public ExternalVibration(int uid, @NonNull String pkg, @NonNull AudioAttributes attrs,
            @NonNull IExternalVibrationController controller, @NonNull IBinder token) {
        mUid = uid;
        mPkg = Preconditions.checkNotNull(pkg);
@@ -166,7 +172,7 @@ public class ExternalVibration implements Parcelable {
            + "pkg=" + mPkg + ", "
            + "attrs=" + mAttrs + ", "
            + "controller=" + mController
            + "token=" + mController
            + "token=" + mToken
            + "}";
    }

+52 −46
Original line number Diff line number Diff line
@@ -464,10 +464,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                            && shouldCancelVibration(
                            mCurrentExternalVibration.externalVibration.getVibrationAttributes(),
                            usageFilter)) {
                        endVibrationLocked(mCurrentExternalVibration, Vibration.Status.CANCELLED);
                        mCurrentExternalVibration.externalVibration.mute();
                        mCurrentExternalVibration = null;
                        setExternalControl(false);
                        endExternalVibrateLocked(Vibration.Status.CANCELLED,
                                /* continueExternalControl= */ false);
                    }
                } finally {
                    Binder.restoreCallingIdentity(ident);
@@ -1283,7 +1282,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
    }

    /** Holder for a {@link ExternalVibration}. */
    private final class ExternalVibrationHolder {
    private final class ExternalVibrationHolder implements IBinder.DeathRecipient {

        public final ExternalVibration externalVibration;
        public int scale;
@@ -1308,6 +1307,18 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            mEndTimeDebug = System.currentTimeMillis();
        }

        public void binderDied() {
            synchronized (mLock) {
                if (mCurrentExternalVibration != null) {
                    if (DEBUG) {
                        Slog.d(TAG, "External vibration finished because binder died");
                    }
                    endExternalVibrateLocked(Vibration.Status.CANCELLED,
                            /* continueExternalControl= */ false);
                }
            }
        }

        public Vibration.DebugInfo getDebugInfo() {
            return new Vibration.DebugInfo(
                    mStartTimeDebug, mEndTimeDebug, /* effect= */ null, /* originalEffect= */ null,
@@ -1450,10 +1461,36 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
        }
    }

    /**
     * Ends the external vibration, and clears related service state.
     *
     * @param status the status to end the associated Vibration with
     * @param continueExternalControl indicates whether external control will continue. If not, the
     *                                HAL will have external control turned off.
     */
    @GuardedBy("mLock")
    private void endExternalVibrateLocked(Vibration.Status status,
            boolean continueExternalControl) {
        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "endExternalVibrateLocked");
        try {
            if (mCurrentExternalVibration == null) {
                return;
            }
            endVibrationLocked(mCurrentExternalVibration, status);
            mCurrentExternalVibration.externalVibration.unlinkToDeath(
                    mCurrentExternalVibration);
            mCurrentExternalVibration = null;
            if (!continueExternalControl) {
                setExternalControl(false);
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
        }
    }

    /** Implementation of {@link IExternalVibratorService} to be triggered on external control. */
    @VisibleForTesting
    final class ExternalVibratorService extends IExternalVibratorService.Stub {
        ExternalVibrationDeathRecipient mCurrentExternalDeathRecipient;

        @Override
        public int onExternalVibrationStart(ExternalVibration vib) {
@@ -1469,7 +1506,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                return IExternalVibratorService.SCALE_MUTE;
            }

            ExternalVibrationHolder cancelingExternalVibration = null;
            boolean alreadyUnderExternalControl = false;
            boolean waitForCompletion = false;
            int scale;
            synchronized (mLock) {
@@ -1504,13 +1541,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                    //
                    // Note that this doesn't support multiple concurrent external controls, as we
                    // would need to mute the old one still if it came from a different controller.
                    alreadyUnderExternalControl = true;
                    mCurrentExternalVibration.externalVibration.mute();
                    endVibrationLocked(mCurrentExternalVibration, Vibration.Status.CANCELLED);
                    cancelingExternalVibration = mCurrentExternalVibration;
                    endExternalVibrateLocked(Vibration.Status.CANCELLED,
                            /* continueExternalControl= */ true);
                }
                mCurrentExternalVibration = new ExternalVibrationHolder(vib);
                mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient();
                vib.linkToDeath(mCurrentExternalDeathRecipient);
                vib.linkToDeath(mCurrentExternalVibration);
                mCurrentExternalVibration.scale = mVibrationScaler.getExternalVibrationScale(
                        vib.getVibrationAttributes().getUsage());
                scale = mCurrentExternalVibration.scale;
@@ -1520,14 +1557,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) {
                    Slog.e(TAG, "Timed out waiting for vibration to cancel");
                    synchronized (mLock) {
                        stopExternalVibrateLocked(Vibration.Status.IGNORED_ERROR_CANCELLING);
                        endExternalVibrateLocked(Vibration.Status.IGNORED_ERROR_CANCELLING,
                                /* continueExternalControl= */ false);
                    }
                    return IExternalVibratorService.SCALE_MUTE;
                }
            }
            if (cancelingExternalVibration == null) {
                // We only need to set external control if it was not already set by another
                // external vibration.
            if (!alreadyUnderExternalControl) {
                if (DEBUG) {
                    Slog.d(TAG, "Vibrator going under external control.");
                }
@@ -1547,29 +1583,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                    if (DEBUG) {
                        Slog.e(TAG, "Stopping external vibration" + vib);
                    }
                    stopExternalVibrateLocked(Vibration.Status.FINISHED);
                    endExternalVibrateLocked(Vibration.Status.FINISHED,
                            /* continueExternalControl= */ false);
                }
            }
        }

        @GuardedBy("mLock")
        private void stopExternalVibrateLocked(Vibration.Status status) {
            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "stopExternalVibrateLocked");
            try {
                if (mCurrentExternalVibration == null) {
                    return;
                }
                endVibrationLocked(mCurrentExternalVibration, status);
                mCurrentExternalVibration.externalVibration.unlinkToDeath(
                        mCurrentExternalDeathRecipient);
                mCurrentExternalDeathRecipient = null;
                mCurrentExternalVibration = null;
                setExternalControl(false);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
            }
        }

        private boolean hasExternalControlCapability() {
            for (int i = 0; i < mVibrators.size(); i++) {
                if (mVibrators.valueAt(i).hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
@@ -1578,19 +1597,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            }
            return false;
        }

        private class ExternalVibrationDeathRecipient implements IBinder.DeathRecipient {
            public void binderDied() {
                synchronized (mLock) {
                    if (mCurrentExternalVibration != null) {
                        if (DEBUG) {
                            Slog.d(TAG, "External vibration finished because binder died");
                        }
                        stopExternalVibrateLocked(Vibration.Status.CANCELLED);
                    }
                }
            }
        }
    }

    /** Provide limited functionality from {@link VibratorManagerService} as shell commands. */
+21 −4
Original line number Diff line number Diff line
@@ -1136,19 +1136,23 @@ public class VibratorManagerServiceTest {
    }

    @Test
    public void onExternalVibration_setsExternalControl() {
    public void onExternalVibration_setsExternalControl() throws Exception {
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        createSystemReadyService();

        IBinder binderToken = mock(IBinder.class);
        ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS,
                mock(IExternalVibrationController.class));
                mock(IExternalVibrationController.class), binderToken);
        int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
        mExternalVibratorService.onExternalVibrationStop(externalVibration);

        assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
        assertEquals(Arrays.asList(false, true, false),
                mVibratorProviders.get(1).getExternalControlStates());

        verify(binderToken).linkToDeath(any(), eq(0));
        verify(binderToken).unlinkToDeath(any(), eq(0));
    }

    @Test
@@ -1160,17 +1164,19 @@ public class VibratorManagerServiceTest {
        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
        createSystemReadyService();

        IBinder firstToken = mock(IBinder.class);
        IBinder secondToken = mock(IBinder.class);
        IExternalVibrationController firstController = mock(IExternalVibrationController.class);
        IExternalVibrationController secondController = mock(IExternalVibrationController.class);
        ExternalVibration firstVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS,
                firstController);
                firstController, firstToken);
        int firstScale = mExternalVibratorService.onExternalVibrationStart(firstVibration);

        AudioAttributes ringtoneAudioAttrs = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
                .build();
        ExternalVibration secondVibration = new ExternalVibration(UID, PACKAGE_NAME,
                ringtoneAudioAttrs, secondController);
                ringtoneAudioAttrs, secondController, secondToken);
        int secondScale = mExternalVibratorService.onExternalVibrationStart(secondVibration);

        assertNotEquals(IExternalVibratorService.SCALE_MUTE, firstScale);
@@ -1180,6 +1186,17 @@ public class VibratorManagerServiceTest {
        // Set external control called only once.
        assertEquals(Arrays.asList(false, true),
                mVibratorProviders.get(1).getExternalControlStates());

        mExternalVibratorService.onExternalVibrationStop(secondVibration);
        mExternalVibratorService.onExternalVibrationStop(firstVibration);
        assertEquals(Arrays.asList(false, true, false),
                mVibratorProviders.get(1).getExternalControlStates());

        verify(firstToken).linkToDeath(any(), eq(0));
        verify(firstToken).unlinkToDeath(any(), eq(0));

        verify(secondToken).linkToDeath(any(), eq(0));
        verify(secondToken).unlinkToDeath(any(), eq(0));
    }

    @Test