Loading services/core/java/com/android/server/vibrator/VibrationStepConductor.java +15 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Build; import android.os.CombinedVibration; import android.os.IBinder; import android.os.VibrationEffect; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; Loading @@ -46,7 +47,7 @@ import java.util.Queue; * VibrationThread. The only thread-safe methods for calling from other threads are the "notify" * methods (which should never be used from the VibrationThread thread). */ final class VibrationStepConductor { final class VibrationStepConductor implements IBinder.DeathRecipient { private static final boolean DEBUG = VibrationThread.DEBUG; private static final String TAG = VibrationThread.TAG; Loading Loading @@ -289,6 +290,19 @@ final class VibrationStepConductor { } } /** * Binder death notification. VibrationThread registers this when it's running a conductor. * Note that cancellation could theoretically happen immediately, before the conductor has * started, but in this case it will be processed in the first signals loop. */ @Override public void binderDied() { if (DEBUG) { Slog.d(TAG, "Binder died, cancelling vibration..."); } notifyCancelled(/* immediate= */ false); } /** * Notify the execution that cancellation is requested. This will be acted upon * asynchronously in the VibrationThread. Loading services/core/java/com/android/server/vibrator/VibrationThread.java +3 −20 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ import java.util.NoSuchElementException; import java.util.Objects; /** Plays a {@link Vibration} in dedicated thread. */ final class VibrationThread extends Thread implements IBinder.DeathRecipient { final class VibrationThread extends Thread { static final String TAG = "VibrationThread"; static final boolean DEBUG = false; Loading Loading @@ -118,23 +118,6 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { mVibratorManagerHooks = vibratorManagerHooks; } @Override public void binderDied() { if (DEBUG) { Slog.d(TAG, "Binder died, cancelling vibration..."); } // The binder death link only exists while the conductor is set. // TODO: move the death linking to be associated with the conductor directly, this // awkwardness will go away. VibrationStepConductor conductor; synchronized (mLock) { conductor = mRequestedActiveConductor; } if (conductor != null) { conductor.notifyCancelled(/* immediate= */ false); } } /** * Sets/activates the current vibration. Must only be called after receiving * onVibratorsReleased from the previous vibration. Loading Loading @@ -268,7 +251,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { private void runCurrentVibrationWithWakeLockAndDeathLink() { IBinder vibrationBinderToken = mExecutingConductor.getVibration().token; try { vibrationBinderToken.linkToDeath(this, 0); vibrationBinderToken.linkToDeath(mExecutingConductor, 0); } catch (RemoteException e) { Slog.e(TAG, "Error linking vibration to token death", e); clientVibrationCompleteIfNotAlready(Vibration.Status.IGNORED_ERROR_TOKEN); Loading @@ -280,7 +263,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { playVibration(); } finally { try { vibrationBinderToken.unlinkToDeath(this, 0); vibrationBinderToken.unlinkToDeath(mExecutingConductor, 0); } catch (NoSuchElementException e) { Slog.wtf(TAG, "Failed to unlink token", e); } Loading services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java +6 −6 Original line number Diff line number Diff line Loading @@ -636,14 +636,14 @@ public class VibrationThreadTest { long vibrationId = 1; VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0); startThreadAndDispatcher(vibrationId, effect); VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect); assertTrue(waitUntil(() -> fakeVibrator.getAmplitudes().size() > 2, TEST_TIMEOUT_MILLIS)); // Vibration still running after 2 cycles. assertTrue(mThread.isRunningVibrationId(vibrationId)); assertTrue(mControllers.get(VIBRATOR_ID).isVibrating()); mThread.binderDied(); conductor.binderDied(); waitForCompletion(); assertFalse(mControllers.get(VIBRATOR_ID).isVibrating()); Loading Loading @@ -1128,17 +1128,17 @@ public class VibrationThreadTest { public void vibrate_binderDied_cancelsVibration() throws Exception { long vibrationId = 1; VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0); startThreadAndDispatcher(vibrationId, effect); VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect); assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(), TEST_TIMEOUT_MILLIS)); assertTrue(mThread.isRunningVibrationId(vibrationId)); mThread.binderDied(); conductor.binderDied(); waitForCompletion(); verify(mVibrationToken).linkToDeath(same(mThread), eq(0)); verify(mVibrationToken).unlinkToDeath(same(mThread), eq(0)); verify(mVibrationToken).linkToDeath(same(conductor), eq(0)); verify(mVibrationToken).unlinkToDeath(same(conductor), eq(0)); verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED); assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).isEmpty()); assertFalse(mControllers.get(VIBRATOR_ID).isVibrating()); Loading Loading
services/core/java/com/android/server/vibrator/VibrationStepConductor.java +15 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Build; import android.os.CombinedVibration; import android.os.IBinder; import android.os.VibrationEffect; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; Loading @@ -46,7 +47,7 @@ import java.util.Queue; * VibrationThread. The only thread-safe methods for calling from other threads are the "notify" * methods (which should never be used from the VibrationThread thread). */ final class VibrationStepConductor { final class VibrationStepConductor implements IBinder.DeathRecipient { private static final boolean DEBUG = VibrationThread.DEBUG; private static final String TAG = VibrationThread.TAG; Loading Loading @@ -289,6 +290,19 @@ final class VibrationStepConductor { } } /** * Binder death notification. VibrationThread registers this when it's running a conductor. * Note that cancellation could theoretically happen immediately, before the conductor has * started, but in this case it will be processed in the first signals loop. */ @Override public void binderDied() { if (DEBUG) { Slog.d(TAG, "Binder died, cancelling vibration..."); } notifyCancelled(/* immediate= */ false); } /** * Notify the execution that cancellation is requested. This will be acted upon * asynchronously in the VibrationThread. Loading
services/core/java/com/android/server/vibrator/VibrationThread.java +3 −20 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ import java.util.NoSuchElementException; import java.util.Objects; /** Plays a {@link Vibration} in dedicated thread. */ final class VibrationThread extends Thread implements IBinder.DeathRecipient { final class VibrationThread extends Thread { static final String TAG = "VibrationThread"; static final boolean DEBUG = false; Loading Loading @@ -118,23 +118,6 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { mVibratorManagerHooks = vibratorManagerHooks; } @Override public void binderDied() { if (DEBUG) { Slog.d(TAG, "Binder died, cancelling vibration..."); } // The binder death link only exists while the conductor is set. // TODO: move the death linking to be associated with the conductor directly, this // awkwardness will go away. VibrationStepConductor conductor; synchronized (mLock) { conductor = mRequestedActiveConductor; } if (conductor != null) { conductor.notifyCancelled(/* immediate= */ false); } } /** * Sets/activates the current vibration. Must only be called after receiving * onVibratorsReleased from the previous vibration. Loading Loading @@ -268,7 +251,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { private void runCurrentVibrationWithWakeLockAndDeathLink() { IBinder vibrationBinderToken = mExecutingConductor.getVibration().token; try { vibrationBinderToken.linkToDeath(this, 0); vibrationBinderToken.linkToDeath(mExecutingConductor, 0); } catch (RemoteException e) { Slog.e(TAG, "Error linking vibration to token death", e); clientVibrationCompleteIfNotAlready(Vibration.Status.IGNORED_ERROR_TOKEN); Loading @@ -280,7 +263,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { playVibration(); } finally { try { vibrationBinderToken.unlinkToDeath(this, 0); vibrationBinderToken.unlinkToDeath(mExecutingConductor, 0); } catch (NoSuchElementException e) { Slog.wtf(TAG, "Failed to unlink token", e); } Loading
services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java +6 −6 Original line number Diff line number Diff line Loading @@ -636,14 +636,14 @@ public class VibrationThreadTest { long vibrationId = 1; VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0); startThreadAndDispatcher(vibrationId, effect); VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect); assertTrue(waitUntil(() -> fakeVibrator.getAmplitudes().size() > 2, TEST_TIMEOUT_MILLIS)); // Vibration still running after 2 cycles. assertTrue(mThread.isRunningVibrationId(vibrationId)); assertTrue(mControllers.get(VIBRATOR_ID).isVibrating()); mThread.binderDied(); conductor.binderDied(); waitForCompletion(); assertFalse(mControllers.get(VIBRATOR_ID).isVibrating()); Loading Loading @@ -1128,17 +1128,17 @@ public class VibrationThreadTest { public void vibrate_binderDied_cancelsVibration() throws Exception { long vibrationId = 1; VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0); startThreadAndDispatcher(vibrationId, effect); VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect); assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(), TEST_TIMEOUT_MILLIS)); assertTrue(mThread.isRunningVibrationId(vibrationId)); mThread.binderDied(); conductor.binderDied(); waitForCompletion(); verify(mVibrationToken).linkToDeath(same(mThread), eq(0)); verify(mVibrationToken).unlinkToDeath(same(mThread), eq(0)); verify(mVibrationToken).linkToDeath(same(conductor), eq(0)); verify(mVibrationToken).unlinkToDeath(same(conductor), eq(0)); verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED); assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).isEmpty()); assertFalse(mControllers.get(VIBRATOR_ID).isVibrating()); Loading