Loading services/core/java/com/android/server/vibrator/ExternalVibrationSession.java +13 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.vibrator; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.ExternalVibration; Loading @@ -24,6 +25,7 @@ import android.os.IBinder; import android.os.VibrationAttributes; import android.os.vibrator.Flags; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.FrameworkStatsLog; /** Loading @@ -32,14 +34,16 @@ import com.android.internal.util.FrameworkStatsLog; final class ExternalVibrationSession extends Vibration implements VibrationSession, IBinder.DeathRecipient { private final Object mLock = new Object(); private final ExternalVibration mExternalVibration; private final ExternalVibrationScale mScale = new ExternalVibrationScale(); @GuardedBy("mLock") @Nullable private Runnable mBinderDeathCallback; ExternalVibrationSession(ExternalVibration externalVibration) { super(externalVibration.getToken(), new CallerInfo( super(new CallerInfo( externalVibration.getVibrationAttributes(), externalVibration.getUid(), // TODO(b/249785241): Find a way to link ExternalVibration to a VirtualDevice // instead of using DEVICE_ID_INVALID here and relying on the UID checks. Loading Loading @@ -82,24 +86,25 @@ final class ExternalVibrationSession extends Vibration } @Override public void linkToDeath(Runnable callback) { synchronized (this) { public boolean linkToDeath(Runnable callback) { synchronized (mLock) { mBinderDeathCallback = callback; } mExternalVibration.linkToDeath(this); return true; } @Override public void unlinkToDeath() { mExternalVibration.unlinkToDeath(this); synchronized (this) { synchronized (mLock) { mBinderDeathCallback = null; } } @Override public void binderDied() { synchronized (this) { synchronized (mLock) { if (mBinderDeathCallback != null) { mBinderDeathCallback.run(); } Loading @@ -119,9 +124,11 @@ final class ExternalVibrationSession extends Vibration } @Override public void notifyEnded() { public void requestEnd(@NonNull Status status, @Nullable CallerInfo endedBy, boolean immediate) { // Notify external client that this vibration should stop sending data to the vibrator. mExternalVibration.mute(); end(new EndInfo(status, endedBy)); } boolean isHoldingSameVibration(ExternalVibration vib) { Loading services/core/java/com/android/server/vibrator/HalVibration.java +4 −2 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import java.util.concurrent.CountDownLatch; final class HalVibration extends Vibration { public final SparseArray<VibrationEffect> mFallbacks = new SparseArray<>(); public final IBinder callerToken; /** A {@link CountDownLatch} to enable waiting for completion. */ private final CountDownLatch mCompletionLatch = new CountDownLatch(1); Loading @@ -55,9 +56,10 @@ final class HalVibration extends Vibration { private int mScaleLevel; private float mAdaptiveScale; HalVibration(@NonNull IBinder token, @NonNull CombinedVibration effect, HalVibration(@NonNull IBinder callerToken, @NonNull CombinedVibration effect, @NonNull VibrationSession.CallerInfo callerInfo) { super(token, callerInfo); super(callerInfo); this.callerToken = callerToken; mOriginalEffect = effect; mEffectToPlay = effect; mScaleLevel = VibrationScaler.SCALE_NONE; Loading services/core/java/com/android/server/vibrator/Vibration.java +1 −4 Original line number Diff line number Diff line Loading @@ -53,16 +53,13 @@ abstract class Vibration { public final long id; public final VibrationSession.CallerInfo callerInfo; public final VibrationStats stats = new VibrationStats(); public final IBinder callerToken; private VibrationSession.Status mStatus; Vibration(@NonNull IBinder token, @NonNull VibrationSession.CallerInfo callerInfo) { Objects.requireNonNull(token); Vibration(@NonNull VibrationSession.CallerInfo callerInfo) { Objects.requireNonNull(callerInfo); mStatus = VibrationSession.Status.RUNNING; this.id = sNextVibrationId.getAndIncrement(); this.callerToken = token; this.callerInfo = callerInfo; } Loading services/core/java/com/android/server/vibrator/VibrationSession.java +16 −4 Original line number Diff line number Diff line Loading @@ -49,14 +49,26 @@ interface VibrationSession { * Links this session to the app process death with given callback to handle it. * * <p>This can be used by the service to end the vibration session when the app process dies. * * @param callback The service callback to be triggered when the binder dies * @return true if the link was successful, false otherwise */ void linkToDeath(Runnable callback); boolean linkToDeath(@Nullable Runnable callback); /** Removes link to the app process death. */ void unlinkToDeath(); /** Notify the session end was requested, which might be acted upon asynchronously. */ void notifyEnded(); /** * Notify the session end was requested, which might be acted upon asynchronously. * * <p>Only the first end signal will be used to end a session, but subsequent calls with * {@code immediate} flag set to true can still force it to take effect urgently. * * @param status the end status. * @param endedBy the {@link CallerInfo} of the session that requested this session to end. * @param immediate indicates whether cancellation should abort urgently and skip cleanup steps. */ void requestEnd(@NonNull Status status, @Nullable CallerInfo endedBy, boolean immediate); /** * Session status with reference to values from vibratormanagerservice.proto for logging. Loading Loading @@ -119,7 +131,7 @@ interface VibrationSession { public final String reason; CallerInfo(@NonNull VibrationAttributes attrs, int uid, int deviceId, String opPkg, String reason) { @Nullable String reason) { Objects.requireNonNull(attrs); this.attrs = attrs; this.uid = uid; Loading services/core/java/com/android/server/vibrator/VibrationStepConductor.java +41 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.os.Build; import android.os.CombinedVibration; import android.os.IBinder; import android.os.RemoteException; import android.os.VibrationEffect; import android.os.vibrator.Flags; import android.os.vibrator.PrebakedSegment; Loading @@ -38,6 +39,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import java.util.PriorityQueue; import java.util.Queue; import java.util.concurrent.CancellationException; Loading Loading @@ -357,6 +359,28 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { /* immediate= */ false); } /** * Returns true if successfully linked this conductor to the death of the binder that requested * the vibration. */ public boolean linkToDeath() { try { mVibration.callerToken.linkToDeath(this, 0); } catch (RemoteException e) { Slog.e(TAG, "Error linking vibration to token death", e); return false; } return true; } public void unlinkToDeath() { try { mVibration.callerToken.unlinkToDeath(this, 0); } catch (NoSuchElementException e) { Slog.wtf(TAG, "Failed to unlink vibration to token death", e); } } /** * Notify the execution that cancellation is requested. This will be acted upon * asynchronously in the VibrationThread. Loading Loading @@ -452,6 +476,23 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { } } /** * Notify that the VibrationThread has completed the vibration effect playback. * * <p>This is a lightweight method intended to be called by the vibration thread directly. The * VibrationThread may still be continuing with cleanup tasks, and should not be given new work * until it notifies the manager that it has been released. */ public void notifyVibrationComplete(@NonNull Vibration.EndInfo endInfo) { if (Build.IS_DEBUGGABLE) { expectIsVibrationThread(true); } if (DEBUG) { Slog.d(TAG, "Vibration " + mVibration.id + " finished with " + endInfo); } mVibration.end(endInfo); } /** Returns true if a cancellation signal was sent via {@link #notifyCancelled}. */ public boolean wasNotifiedToCancel() { if (Build.IS_DEBUGGABLE) { Loading Loading
services/core/java/com/android/server/vibrator/ExternalVibrationSession.java +13 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.vibrator; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.ExternalVibration; Loading @@ -24,6 +25,7 @@ import android.os.IBinder; import android.os.VibrationAttributes; import android.os.vibrator.Flags; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.FrameworkStatsLog; /** Loading @@ -32,14 +34,16 @@ import com.android.internal.util.FrameworkStatsLog; final class ExternalVibrationSession extends Vibration implements VibrationSession, IBinder.DeathRecipient { private final Object mLock = new Object(); private final ExternalVibration mExternalVibration; private final ExternalVibrationScale mScale = new ExternalVibrationScale(); @GuardedBy("mLock") @Nullable private Runnable mBinderDeathCallback; ExternalVibrationSession(ExternalVibration externalVibration) { super(externalVibration.getToken(), new CallerInfo( super(new CallerInfo( externalVibration.getVibrationAttributes(), externalVibration.getUid(), // TODO(b/249785241): Find a way to link ExternalVibration to a VirtualDevice // instead of using DEVICE_ID_INVALID here and relying on the UID checks. Loading Loading @@ -82,24 +86,25 @@ final class ExternalVibrationSession extends Vibration } @Override public void linkToDeath(Runnable callback) { synchronized (this) { public boolean linkToDeath(Runnable callback) { synchronized (mLock) { mBinderDeathCallback = callback; } mExternalVibration.linkToDeath(this); return true; } @Override public void unlinkToDeath() { mExternalVibration.unlinkToDeath(this); synchronized (this) { synchronized (mLock) { mBinderDeathCallback = null; } } @Override public void binderDied() { synchronized (this) { synchronized (mLock) { if (mBinderDeathCallback != null) { mBinderDeathCallback.run(); } Loading @@ -119,9 +124,11 @@ final class ExternalVibrationSession extends Vibration } @Override public void notifyEnded() { public void requestEnd(@NonNull Status status, @Nullable CallerInfo endedBy, boolean immediate) { // Notify external client that this vibration should stop sending data to the vibrator. mExternalVibration.mute(); end(new EndInfo(status, endedBy)); } boolean isHoldingSameVibration(ExternalVibration vib) { Loading
services/core/java/com/android/server/vibrator/HalVibration.java +4 −2 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import java.util.concurrent.CountDownLatch; final class HalVibration extends Vibration { public final SparseArray<VibrationEffect> mFallbacks = new SparseArray<>(); public final IBinder callerToken; /** A {@link CountDownLatch} to enable waiting for completion. */ private final CountDownLatch mCompletionLatch = new CountDownLatch(1); Loading @@ -55,9 +56,10 @@ final class HalVibration extends Vibration { private int mScaleLevel; private float mAdaptiveScale; HalVibration(@NonNull IBinder token, @NonNull CombinedVibration effect, HalVibration(@NonNull IBinder callerToken, @NonNull CombinedVibration effect, @NonNull VibrationSession.CallerInfo callerInfo) { super(token, callerInfo); super(callerInfo); this.callerToken = callerToken; mOriginalEffect = effect; mEffectToPlay = effect; mScaleLevel = VibrationScaler.SCALE_NONE; Loading
services/core/java/com/android/server/vibrator/Vibration.java +1 −4 Original line number Diff line number Diff line Loading @@ -53,16 +53,13 @@ abstract class Vibration { public final long id; public final VibrationSession.CallerInfo callerInfo; public final VibrationStats stats = new VibrationStats(); public final IBinder callerToken; private VibrationSession.Status mStatus; Vibration(@NonNull IBinder token, @NonNull VibrationSession.CallerInfo callerInfo) { Objects.requireNonNull(token); Vibration(@NonNull VibrationSession.CallerInfo callerInfo) { Objects.requireNonNull(callerInfo); mStatus = VibrationSession.Status.RUNNING; this.id = sNextVibrationId.getAndIncrement(); this.callerToken = token; this.callerInfo = callerInfo; } Loading
services/core/java/com/android/server/vibrator/VibrationSession.java +16 −4 Original line number Diff line number Diff line Loading @@ -49,14 +49,26 @@ interface VibrationSession { * Links this session to the app process death with given callback to handle it. * * <p>This can be used by the service to end the vibration session when the app process dies. * * @param callback The service callback to be triggered when the binder dies * @return true if the link was successful, false otherwise */ void linkToDeath(Runnable callback); boolean linkToDeath(@Nullable Runnable callback); /** Removes link to the app process death. */ void unlinkToDeath(); /** Notify the session end was requested, which might be acted upon asynchronously. */ void notifyEnded(); /** * Notify the session end was requested, which might be acted upon asynchronously. * * <p>Only the first end signal will be used to end a session, but subsequent calls with * {@code immediate} flag set to true can still force it to take effect urgently. * * @param status the end status. * @param endedBy the {@link CallerInfo} of the session that requested this session to end. * @param immediate indicates whether cancellation should abort urgently and skip cleanup steps. */ void requestEnd(@NonNull Status status, @Nullable CallerInfo endedBy, boolean immediate); /** * Session status with reference to values from vibratormanagerservice.proto for logging. Loading Loading @@ -119,7 +131,7 @@ interface VibrationSession { public final String reason; CallerInfo(@NonNull VibrationAttributes attrs, int uid, int deviceId, String opPkg, String reason) { @Nullable String reason) { Objects.requireNonNull(attrs); this.attrs = attrs; this.uid = uid; Loading
services/core/java/com/android/server/vibrator/VibrationStepConductor.java +41 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.os.Build; import android.os.CombinedVibration; import android.os.IBinder; import android.os.RemoteException; import android.os.VibrationEffect; import android.os.vibrator.Flags; import android.os.vibrator.PrebakedSegment; Loading @@ -38,6 +39,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import java.util.PriorityQueue; import java.util.Queue; import java.util.concurrent.CancellationException; Loading Loading @@ -357,6 +359,28 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { /* immediate= */ false); } /** * Returns true if successfully linked this conductor to the death of the binder that requested * the vibration. */ public boolean linkToDeath() { try { mVibration.callerToken.linkToDeath(this, 0); } catch (RemoteException e) { Slog.e(TAG, "Error linking vibration to token death", e); return false; } return true; } public void unlinkToDeath() { try { mVibration.callerToken.unlinkToDeath(this, 0); } catch (NoSuchElementException e) { Slog.wtf(TAG, "Failed to unlink vibration to token death", e); } } /** * Notify the execution that cancellation is requested. This will be acted upon * asynchronously in the VibrationThread. Loading Loading @@ -452,6 +476,23 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { } } /** * Notify that the VibrationThread has completed the vibration effect playback. * * <p>This is a lightweight method intended to be called by the vibration thread directly. The * VibrationThread may still be continuing with cleanup tasks, and should not be given new work * until it notifies the manager that it has been released. */ public void notifyVibrationComplete(@NonNull Vibration.EndInfo endInfo) { if (Build.IS_DEBUGGABLE) { expectIsVibrationThread(true); } if (DEBUG) { Slog.d(TAG, "Vibration " + mVibration.id + " finished with " + endInfo); } mVibration.end(endInfo); } /** Returns true if a cancellation signal was sent via {@link #notifyCancelled}. */ public boolean wasNotifiedToCancel() { if (Build.IS_DEBUGGABLE) { Loading