Merge "Handle binder death with the conductor rather than VibrationThread." into tm-dev am: 180fe3085a
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17046343 Change-Id: Ifaba07bb3cdaaa358cf40b2e6cd3ff2c58023818
This commit is contained in:
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
|
|||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.CombinedVibration;
|
import android.os.CombinedVibration;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.os.VibrationEffect;
|
import android.os.VibrationEffect;
|
||||||
import android.os.vibrator.PrebakedSegment;
|
import android.os.vibrator.PrebakedSegment;
|
||||||
import android.os.vibrator.PrimitiveSegment;
|
import android.os.vibrator.PrimitiveSegment;
|
||||||
@@ -46,7 +47,7 @@ import java.util.Queue;
|
|||||||
* VibrationThread. The only thread-safe methods for calling from other threads are the "notify"
|
* VibrationThread. The only thread-safe methods for calling from other threads are the "notify"
|
||||||
* methods (which should never be used from the VibrationThread thread).
|
* 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 boolean DEBUG = VibrationThread.DEBUG;
|
||||||
private static final String TAG = VibrationThread.TAG;
|
private static final String TAG = VibrationThread.TAG;
|
||||||
|
|
||||||
@@ -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
|
* Notify the execution that cancellation is requested. This will be acted upon
|
||||||
* asynchronously in the VibrationThread.
|
* asynchronously in the VibrationThread.
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import java.util.NoSuchElementException;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/** Plays a {@link Vibration} in dedicated thread. */
|
/** 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 String TAG = "VibrationThread";
|
||||||
static final boolean DEBUG = false;
|
static final boolean DEBUG = false;
|
||||||
|
|
||||||
@@ -118,23 +118,6 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
|
|||||||
mVibratorManagerHooks = vibratorManagerHooks;
|
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
|
* Sets/activates the current vibration. Must only be called after receiving
|
||||||
* onVibratorsReleased from the previous vibration.
|
* onVibratorsReleased from the previous vibration.
|
||||||
@@ -268,7 +251,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
|
|||||||
private void runCurrentVibrationWithWakeLockAndDeathLink() {
|
private void runCurrentVibrationWithWakeLockAndDeathLink() {
|
||||||
IBinder vibrationBinderToken = mExecutingConductor.getVibration().token;
|
IBinder vibrationBinderToken = mExecutingConductor.getVibration().token;
|
||||||
try {
|
try {
|
||||||
vibrationBinderToken.linkToDeath(this, 0);
|
vibrationBinderToken.linkToDeath(mExecutingConductor, 0);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.e(TAG, "Error linking vibration to token death", e);
|
Slog.e(TAG, "Error linking vibration to token death", e);
|
||||||
clientVibrationCompleteIfNotAlready(Vibration.Status.IGNORED_ERROR_TOKEN);
|
clientVibrationCompleteIfNotAlready(Vibration.Status.IGNORED_ERROR_TOKEN);
|
||||||
@@ -280,7 +263,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
|
|||||||
playVibration();
|
playVibration();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
vibrationBinderToken.unlinkToDeath(this, 0);
|
vibrationBinderToken.unlinkToDeath(mExecutingConductor, 0);
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
Slog.wtf(TAG, "Failed to unlink token", e);
|
Slog.wtf(TAG, "Failed to unlink token", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -636,14 +636,14 @@ public class VibrationThreadTest {
|
|||||||
|
|
||||||
long vibrationId = 1;
|
long vibrationId = 1;
|
||||||
VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0);
|
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));
|
assertTrue(waitUntil(() -> fakeVibrator.getAmplitudes().size() > 2, TEST_TIMEOUT_MILLIS));
|
||||||
// Vibration still running after 2 cycles.
|
// Vibration still running after 2 cycles.
|
||||||
assertTrue(mThread.isRunningVibrationId(vibrationId));
|
assertTrue(mThread.isRunningVibrationId(vibrationId));
|
||||||
assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());
|
assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());
|
||||||
|
|
||||||
mThread.binderDied();
|
conductor.binderDied();
|
||||||
waitForCompletion();
|
waitForCompletion();
|
||||||
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
|
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
|
||||||
|
|
||||||
@@ -1128,17 +1128,17 @@ public class VibrationThreadTest {
|
|||||||
public void vibrate_binderDied_cancelsVibration() throws Exception {
|
public void vibrate_binderDied_cancelsVibration() throws Exception {
|
||||||
long vibrationId = 1;
|
long vibrationId = 1;
|
||||||
VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0);
|
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(),
|
assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(),
|
||||||
TEST_TIMEOUT_MILLIS));
|
TEST_TIMEOUT_MILLIS));
|
||||||
assertTrue(mThread.isRunningVibrationId(vibrationId));
|
assertTrue(mThread.isRunningVibrationId(vibrationId));
|
||||||
|
|
||||||
mThread.binderDied();
|
conductor.binderDied();
|
||||||
waitForCompletion();
|
waitForCompletion();
|
||||||
|
|
||||||
verify(mVibrationToken).linkToDeath(same(mThread), eq(0));
|
verify(mVibrationToken).linkToDeath(same(conductor), eq(0));
|
||||||
verify(mVibrationToken).unlinkToDeath(same(mThread), eq(0));
|
verify(mVibrationToken).unlinkToDeath(same(conductor), eq(0));
|
||||||
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
|
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
|
||||||
assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).isEmpty());
|
assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).isEmpty());
|
||||||
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
|
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
|
||||||
|
|||||||
Reference in New Issue
Block a user