Merge "Add CallerInfo to Vibration class."
diff --git a/core/java/android/os/ExternalVibration.java b/core/java/android/os/ExternalVibration.java
index db5bc70..fb115b3 100644
--- a/core/java/android/os/ExternalVibration.java
+++ b/core/java/android/os/ExternalVibration.java
@@ -104,6 +104,10 @@
         return mAttrs;
     }
 
+    public IBinder getToken() {
+        return mToken;
+    }
+
     public VibrationAttributes getVibrationAttributes() {
         return new VibrationAttributes.Builder(mAttrs).build();
     }
diff --git a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
index be90530..90b6f95 100644
--- a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
@@ -126,7 +126,7 @@
                     "Turning off vibrator " + getVibratorId());
         }
         controller.off();
-        getVibration().stats().reportVibratorOff();
+        getVibration().stats.reportVibratorOff();
         mPendingVibratorOffDeadline = 0;
     }
 
@@ -136,7 +136,7 @@
                     "Amplitude changed on vibrator " + getVibratorId() + " to " + amplitude);
         }
         controller.setAmplitude(amplitude);
-        getVibration().stats().reportSetAmplitude();
+        getVibration().stats.reportSetAmplitude();
     }
 
     /**
@@ -170,7 +170,7 @@
             // Count the loops that were played.
             int loopSize = effectSize - repeatIndex;
             int loopSegmentsPlayed = nextSegmentIndex - repeatIndex;
-            getVibration().stats().reportRepetition(loopSegmentsPlayed / loopSize);
+            getVibration().stats.reportRepetition(loopSegmentsPlayed / loopSize);
             nextSegmentIndex = repeatIndex + ((nextSegmentIndex - effectSize) % loopSize);
         }
         Step nextStep = conductor.nextVibrateStep(nextStartTime, controller, effect,
diff --git a/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java b/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java
index 545ec5b..940bd08 100644
--- a/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java
@@ -73,7 +73,7 @@
                     primitives.toArray(new PrimitiveSegment[primitives.size()]);
             long vibratorOnResult = controller.on(primitivesArray, getVibration().id);
             handleVibratorOnResult(vibratorOnResult);
-            getVibration().stats().reportComposePrimitives(vibratorOnResult, primitivesArray);
+            getVibration().stats.reportComposePrimitives(vibratorOnResult, primitivesArray);
 
             // The next start and off times will be calculated from mVibratorOnResult.
             return nextSteps(/* segmentsPlayed= */ primitives.size());
diff --git a/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java b/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java
index 8bfa2c3..7100ffd 100644
--- a/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java
@@ -72,7 +72,7 @@
             RampSegment[] pwlesArray = pwles.toArray(new RampSegment[pwles.size()]);
             long vibratorOnResult = controller.on(pwlesArray, getVibration().id);
             handleVibratorOnResult(vibratorOnResult);
-            getVibration().stats().reportComposePwle(vibratorOnResult, pwlesArray);
+            getVibration().stats.reportComposePwle(vibratorOnResult, pwlesArray);
 
             // The next start and off times will be calculated from mVibratorOnResult.
             return nextSteps(/* segmentsPlayed= */ pwles.size());
diff --git a/services/core/java/com/android/server/vibrator/FinishSequentialEffectStep.java b/services/core/java/com/android/server/vibrator/FinishSequentialEffectStep.java
index bbbca02..c9683d9 100644
--- a/services/core/java/com/android/server/vibrator/FinishSequentialEffectStep.java
+++ b/services/core/java/com/android/server/vibrator/FinishSequentialEffectStep.java
@@ -51,7 +51,8 @@
                 Slog.d(VibrationThread.TAG,
                         "FinishSequentialEffectStep for effect #" + startedStep.currentIndex);
             }
-            conductor.vibratorManagerHooks.noteVibratorOff(conductor.getVibration().uid);
+            conductor.vibratorManagerHooks.noteVibratorOff(
+                    conductor.getVibration().callerInfo.uid);
             Step nextStep = startedStep.nextStep();
             return nextStep == null ? VibrationStepConductor.EMPTY_STEP_LIST
                     : Arrays.asList(nextStep);
@@ -68,6 +69,7 @@
 
     @Override
     public void cancelImmediately() {
-        conductor.vibratorManagerHooks.noteVibratorOff(conductor.getVibration().uid);
+        conductor.vibratorManagerHooks.noteVibratorOff(
+                conductor.getVibration().callerInfo.uid);
     }
 }
diff --git a/services/core/java/com/android/server/vibrator/HalVibration.java b/services/core/java/com/android/server/vibrator/HalVibration.java
index 53f04d7..87f189a 100644
--- a/services/core/java/com/android/server/vibrator/HalVibration.java
+++ b/services/core/java/com/android/server/vibrator/HalVibration.java
@@ -16,6 +16,7 @@
 
 package com.android.server.vibrator;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.CombinedVibration;
 import android.os.IBinder;
@@ -35,13 +36,6 @@
  */
 final class HalVibration extends Vibration {
 
-    public final VibrationAttributes attrs;
-    public final long id;
-    public final int uid;
-    public final int displayId;
-    public final String opPkg;
-    public final String reason;
-    public final IBinder token;
     public final SparseArray<VibrationEffect> mFallbacks = new SparseArray<>();
 
     /** The actual effect to be played. */
@@ -58,29 +52,15 @@
     /** Vibration status. */
     private Vibration.Status mStatus;
 
-    /** Vibration runtime stats. */
-    private final VibrationStats mStats = new VibrationStats();
-
     /** A {@link CountDownLatch} to enable waiting for completion. */
     private final CountDownLatch mCompletionLatch = new CountDownLatch(1);
 
-    HalVibration(IBinder token, int id, CombinedVibration effect,
-            VibrationAttributes attrs, int uid, int displayId, String opPkg, String reason) {
-        this.token = token;
+    HalVibration(@NonNull IBinder token, CombinedVibration effect, @NonNull CallerInfo callerInfo) {
+        super(token, callerInfo);
         this.mEffect = effect;
-        this.id = id;
-        this.attrs = attrs;
-        this.uid = uid;
-        this.displayId = displayId;
-        this.opPkg = opPkg;
-        this.reason = reason;
         mStatus = Vibration.Status.RUNNING;
     }
 
-    VibrationStats stats() {
-        return mStats;
-    }
-
     /**
      * Set the {@link Status} of this vibration and reports the current system time as this
      * vibration end time, for debugging purposes.
@@ -94,7 +74,7 @@
             return;
         }
         mStatus = info.status;
-        mStats.reportEnded(info.endedByUid, info.endedByUsage);
+        stats.reportEnded(info.endedBy);
         mCompletionLatch.countDown();
     }
 
@@ -190,8 +170,8 @@
      * Return {@link Vibration.DebugInfo} with read-only debug information about this vibration.
      */
     public Vibration.DebugInfo getDebugInfo() {
-        return new Vibration.DebugInfo(mStatus, mStats, mEffect, mOriginalEffect, /* scale= */ 0,
-                attrs, uid, displayId, opPkg, reason);
+        return new Vibration.DebugInfo(mStatus, stats, mEffect, mOriginalEffect, /* scale= */ 0,
+                callerInfo);
     }
 
     /** Return {@link VibrationStats.StatsInfo} with read-only metrics about this vibration. */
@@ -200,7 +180,8 @@
                 ? FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__REPEATED
                 : FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__SINGLE;
         return new VibrationStats.StatsInfo(
-                uid, vibrationType, attrs.getUsage(), mStatus, mStats, completionUptimeMillis);
+                callerInfo.uid, vibrationType, callerInfo.attrs.getUsage(), mStatus,
+                stats, completionUptimeMillis);
     }
 
     /**
@@ -212,8 +193,9 @@
      * pipeline very short vibrations together, regardless of the flag.
      */
     public boolean canPipelineWith(HalVibration vib) {
-        return uid == vib.uid && attrs.isFlagSet(VibrationAttributes.FLAG_PIPELINED_EFFECT)
-                && vib.attrs.isFlagSet(VibrationAttributes.FLAG_PIPELINED_EFFECT)
+        return callerInfo.uid == vib.callerInfo.uid && callerInfo.attrs.isFlagSet(
+                VibrationAttributes.FLAG_PIPELINED_EFFECT)
+                && vib.callerInfo.attrs.isFlagSet(VibrationAttributes.FLAG_PIPELINED_EFFECT)
                 && !isRepeating();
     }
 }
diff --git a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
index 21ba874..4e58b9a 100644
--- a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
+++ b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
@@ -21,7 +21,6 @@
 import android.hardware.input.InputManager;
 import android.os.CombinedVibration;
 import android.os.Handler;
-import android.os.VibrationAttributes;
 import android.os.VibratorManager;
 import android.util.SparseArray;
 import android.view.InputDevice;
@@ -94,11 +93,11 @@
      *
      * @return {@link #isAvailable()}
      */
-    public boolean vibrateIfAvailable(int uid, String opPkg, CombinedVibration effect,
-            String reason, VibrationAttributes attrs) {
+    public boolean vibrateIfAvailable(Vibration.CallerInfo callerInfo, CombinedVibration effect) {
         synchronized (mLock) {
             for (int i = 0; i < mInputDeviceVibrators.size(); i++) {
-                mInputDeviceVibrators.valueAt(i).vibrate(uid, opPkg, effect, reason, attrs);
+                mInputDeviceVibrators.valueAt(i).vibrate(callerInfo.uid, callerInfo.opPkg, effect,
+                        callerInfo.reason, callerInfo.attrs);
             }
             return mInputDeviceVibrators.size() > 0;
         }
diff --git a/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java b/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java
index d91bafa..8094e7c5 100644
--- a/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java
@@ -64,7 +64,7 @@
             VibrationEffect fallback = getVibration().getFallback(prebaked.getEffectId());
             long vibratorOnResult = controller.on(prebaked, getVibration().id);
             handleVibratorOnResult(vibratorOnResult);
-            getVibration().stats().reportPerformEffect(vibratorOnResult, prebaked);
+            getVibration().stats.reportPerformEffect(vibratorOnResult, prebaked);
 
             if (vibratorOnResult == 0 && prebaked.shouldFallback()
                     && (fallback instanceof VibrationEffect.Composed)) {
diff --git a/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java b/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java
index 1672470..cce1ef4 100644
--- a/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java
@@ -161,7 +161,7 @@
         }
         long vibratorOnResult = controller.on(duration, getVibration().id);
         handleVibratorOnResult(vibratorOnResult);
-        getVibration().stats().reportVibratorOn(vibratorOnResult);
+        getVibration().stats.reportVibratorOn(vibratorOnResult);
         return vibratorOnResult;
     }
 
diff --git a/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java b/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
index fd1a3ac..15c60a3 100644
--- a/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
+++ b/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
@@ -93,8 +93,8 @@
             }
 
             mVibratorsOnMaxDuration = startVibrating(effectMapping, nextSteps);
-            conductor.vibratorManagerHooks.noteVibratorOn(conductor.getVibration().uid,
-                    mVibratorsOnMaxDuration);
+            conductor.vibratorManagerHooks.noteVibratorOn(
+                    conductor.getVibration().callerInfo.uid, mVibratorsOnMaxDuration);
         } finally {
             if (mVibratorsOnMaxDuration >= 0) {
                 // It least one vibrator was started then add a finish step to wait for all
@@ -211,7 +211,8 @@
         // Check if sync was prepared and if any step was accepted by a vibrator,
         // otherwise there is nothing to trigger here.
         if (hasPrepared && !hasFailed && maxDuration > 0) {
-            hasTriggered = conductor.vibratorManagerHooks.triggerSyncedVibration(getVibration().id);
+            hasTriggered = conductor.vibratorManagerHooks.triggerSyncedVibration(
+                    getVibration().id);
             hasFailed &= hasTriggered;
         }
 
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index 5667c72..1cc0a4f 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.CombinedVibration;
+import android.os.IBinder;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.vibrator.PrebakedSegment;
@@ -31,6 +32,7 @@
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * The base class for all vibrations.
@@ -38,6 +40,13 @@
 class Vibration {
     private static final SimpleDateFormat DEBUG_DATE_FORMAT =
             new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+    // Used to generate globally unique vibration ids.
+    private static final AtomicInteger sNextVibrationId = new AtomicInteger(1); // 0 = no callback
+
+    public final long id;
+    public final CallerInfo callerInfo;
+    public final VibrationStats stats = new VibrationStats();
+    public final IBinder callerToken;
 
     /** Vibration status with reference to values from vibratormanagerservice.proto for logging. */
     enum Status {
@@ -80,24 +89,82 @@
         }
     }
 
+    Vibration(@NonNull IBinder token, @NonNull CallerInfo callerInfo) {
+        Objects.requireNonNull(token);
+        Objects.requireNonNull(callerInfo);
+        this.id = sNextVibrationId.getAndIncrement();
+        this.callerToken = token;
+        this.callerInfo = callerInfo;
+    }
+
+    /**
+     * Holds lightweight immutable info on the process that triggered the vibration. This data
+     * could potentially be kept in memory for a long time for bugreport dumpsys operations.
+     *
+     * Since CallerInfo can be kept in memory for a long time, it shouldn't hold any references to
+     * potentially expensive or resource-linked objects, such as {@link IBinder}.
+     */
+    static final class CallerInfo {
+        public final VibrationAttributes attrs;
+        public final int uid;
+        public final int displayId;
+        public final String opPkg;
+        public final String reason;
+
+        CallerInfo(@NonNull VibrationAttributes attrs, int uid, int displayId,
+                String opPkg, String reason) {
+            Objects.requireNonNull(attrs);
+            this.attrs = attrs;
+            this.uid = uid;
+            this.displayId = displayId;
+            this.opPkg = opPkg;
+            this.reason = reason;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof CallerInfo)) return false;
+            CallerInfo that = (CallerInfo) o;
+            return Objects.equals(attrs, that.attrs)
+                    && uid == that.uid
+                    && displayId == that.displayId
+                    && Objects.equals(opPkg, that.opPkg)
+                    && Objects.equals(reason, that.reason);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(attrs, uid, displayId, opPkg, reason);
+        }
+
+        @Override
+        public String toString() {
+            return "CallerInfo{"
+                    + " attrs=" + attrs
+                    + ", uid=" + uid
+                    + ", displayId=" + displayId
+                    + ", opPkg=" + opPkg
+                    + ", reason=" + reason
+                    + '}';
+        }
+    }
+
     /** Immutable info passed as a signal to end a vibration. */
     static final class EndInfo {
         /** The {@link Status} to be set to the vibration when it ends with this info. */
         @NonNull
         public final Status status;
-        /** The UID that triggered the vibration that ended this, or -1 if undefined. */
-        public final int endedByUid;
-        /** The VibrationAttributes.USAGE_* of the vibration that ended this, or -1 if undefined. */
-        public final int endedByUsage;
+        /** Info about the process that ended the vibration. */
+        public final CallerInfo endedBy;
 
         EndInfo(@NonNull Vibration.Status status) {
-            this(status, /* endedByUid= */ -1, /* endedByUsage= */ -1);
+            this(status, null);
         }
 
-        EndInfo(@NonNull Vibration.Status status, int endedByUid, int endedByUsage) {
+        EndInfo(@NonNull Vibration.Status status, @Nullable CallerInfo endedBy) {
             this.status = status;
-            this.endedByUid = endedByUid;
-            this.endedByUsage = endedByUsage;
+            this.endedBy = endedBy;
         }
 
         @Override
@@ -105,27 +172,31 @@
             if (this == o) return true;
             if (!(o instanceof EndInfo)) return false;
             EndInfo that = (EndInfo) o;
-            return endedByUid == that.endedByUid
-                    && endedByUsage == that.endedByUsage
+            return Objects.equals(endedBy, that.endedBy)
                     && status == that.status;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(status, endedByUid, endedByUsage);
+            return Objects.hash(status, endedBy);
         }
 
         @Override
         public String toString() {
             return "EndInfo{"
                     + "status=" + status
-                    + ", endedByUid=" + endedByUid
-                    + ", endedByUsage=" + endedByUsage
+                    + ", endedBy=" + endedBy
                     + '}';
         }
     }
 
-    /** Debug information about vibrations. */
+    /**
+     * Holds lightweight debug information about the vibration that could potentially be kept in
+     * memory for a long time for bugreport dumpsys operations.
+     *
+     * Since DebugInfo can be kept in memory for a long time, it shouldn't hold any references to
+     * potentially expensive or resource-linked objects, such as {@link IBinder}.
+     */
     static final class DebugInfo {
         private final long mCreateTime;
         private final long mStartTime;
@@ -134,16 +205,13 @@
         private final CombinedVibration mEffect;
         private final CombinedVibration mOriginalEffect;
         private final float mScale;
-        private final VibrationAttributes mAttrs;
-        private final int mUid;
-        private final int mDisplayId;
-        private final String mOpPkg;
-        private final String mReason;
+        private final CallerInfo mCallerInfo;
         private final Status mStatus;
 
         DebugInfo(Status status, VibrationStats stats, @Nullable CombinedVibration effect,
-                @Nullable CombinedVibration originalEffect, float scale, VibrationAttributes attrs,
-                int uid, int displayId, String opPkg, String reason) {
+                @Nullable CombinedVibration originalEffect, float scale,
+                @NonNull CallerInfo callerInfo) {
+            Objects.requireNonNull(callerInfo);
             mCreateTime = stats.getCreateTimeDebug();
             mStartTime = stats.getStartTimeDebug();
             mEndTime = stats.getEndTimeDebug();
@@ -151,11 +219,7 @@
             mEffect = effect;
             mOriginalEffect = originalEffect;
             mScale = scale;
-            mAttrs = attrs;
-            mUid = uid;
-            mDisplayId = displayId;
-            mOpPkg = opPkg;
-            mReason = reason;
+            mCallerInfo = callerInfo;
             mStatus = status;
         }
 
@@ -179,16 +243,8 @@
                     .append(mOriginalEffect)
                     .append(", scale: ")
                     .append(String.format("%.2f", mScale))
-                    .append(", attrs: ")
-                    .append(mAttrs)
-                    .append(", uid: ")
-                    .append(mUid)
-                    .append(", displayId: ")
-                    .append(mDisplayId)
-                    .append(", opPkg: ")
-                    .append(mOpPkg)
-                    .append(", reason: ")
-                    .append(mReason)
+                    .append(", callerInfo: ")
+                    .append(mCallerInfo)
                     .toString();
         }
 
@@ -201,9 +257,10 @@
             proto.write(VibrationProto.STATUS, mStatus.ordinal());
 
             final long attrsToken = proto.start(VibrationProto.ATTRIBUTES);
-            proto.write(VibrationAttributesProto.USAGE, mAttrs.getUsage());
-            proto.write(VibrationAttributesProto.AUDIO_USAGE, mAttrs.getAudioUsage());
-            proto.write(VibrationAttributesProto.FLAGS, mAttrs.getFlags());
+            final VibrationAttributes attrs = mCallerInfo.attrs;
+            proto.write(VibrationAttributesProto.USAGE, attrs.getUsage());
+            proto.write(VibrationAttributesProto.AUDIO_USAGE, attrs.getAudioUsage());
+            proto.write(VibrationAttributesProto.FLAGS, attrs.getFlags());
             proto.end(attrsToken);
 
             if (mEffect != null) {
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index d944a3b..8a7d607c 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -27,6 +27,7 @@
 import static android.os.VibrationAttributes.USAGE_TOUCH;
 import static android.os.VibrationAttributes.USAGE_UNKNOWN;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.IUidObserver;
@@ -375,15 +376,15 @@
      * null otherwise.
      */
     @Nullable
-    public Vibration.Status shouldIgnoreVibration(int uid, int displayId,
-            VibrationAttributes attrs) {
-        final int usage = attrs.getUsage();
+    public Vibration.Status shouldIgnoreVibration(@NonNull Vibration.CallerInfo callerInfo) {
+        final int usage = callerInfo.attrs.getUsage();
         synchronized (mLock) {
-            if (!mUidObserver.isUidForeground(uid)
+            if (!mUidObserver.isUidForeground(callerInfo.uid)
                     && !BACKGROUND_PROCESS_USAGE_ALLOWLIST.contains(usage)) {
                 return Vibration.Status.IGNORED_BACKGROUND;
             }
-            if (mVirtualDeviceListener.isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
+            if (mVirtualDeviceListener.isAppOrDisplayOnAnyVirtualDevice(callerInfo.uid,
+                    callerInfo.displayId)) {
                 return Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE;
             }
 
@@ -391,7 +392,8 @@
                 return Vibration.Status.IGNORED_FOR_POWER;
             }
 
-            if (!attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)) {
+            if (!callerInfo.attrs.isFlagSet(
+                    VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)) {
                 if (!mVibrateOn && (VIBRATE_ON_DISABLED_USAGE_ALLOWED != usage)) {
                     return Vibration.Status.IGNORED_FOR_SETTINGS;
                 }
@@ -401,7 +403,7 @@
                 }
             }
 
-            if (!attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)) {
+            if (!callerInfo.attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)) {
                 if (!shouldVibrateForRingerModeLocked(usage)) {
                     return Vibration.Status.IGNORED_FOR_RINGER_MODE;
                 }
@@ -420,8 +422,8 @@
      *
      * @return true if the vibration should be cancelled when the screen goes off, false otherwise.
      */
-    public boolean shouldCancelVibrationOnScreenOff(int uid, String opPkg,
-            @VibrationAttributes.Usage int usage, long vibrationStartUptimeMillis) {
+    public boolean shouldCancelVibrationOnScreenOff(@NonNull Vibration.CallerInfo callerInfo,
+            long vibrationStartUptimeMillis) {
         PowerManagerInternal pm;
         synchronized (mLock) {
             pm = mPowerManagerInternal;
@@ -442,12 +444,13 @@
                 return false;
             }
         }
-        if (!SYSTEM_VIBRATION_SCREEN_OFF_USAGE_ALLOWLIST.contains(usage)) {
+        if (!SYSTEM_VIBRATION_SCREEN_OFF_USAGE_ALLOWLIST.contains(callerInfo.attrs.getUsage())) {
             // Usages not allowed even for system vibrations should always be cancelled.
             return true;
         }
         // Only allow vibrations from System packages to continue vibrating when the screen goes off
-        return uid != Process.SYSTEM_UID && uid != 0 && !mSystemUiPackage.equals(opPkg);
+        return callerInfo.uid != Process.SYSTEM_UID && callerInfo.uid != 0
+                && !mSystemUiPackage.equals(callerInfo.opPkg);
     }
 
     /**
diff --git a/services/core/java/com/android/server/vibrator/VibrationStats.java b/services/core/java/com/android/server/vibrator/VibrationStats.java
index 931be1d..2d00351 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStats.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStats.java
@@ -16,6 +16,8 @@
 
 package com.android.server.vibrator;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.SystemClock;
 import android.os.vibrator.PrebakedSegment;
 import android.os.vibrator.PrimitiveSegment;
@@ -159,15 +161,18 @@
      * @return true if the status was accepted. This method will only accept given values if
      * the end timestamp was never set.
      */
-    boolean reportEnded(int endedByUid, int endedByUsage) {
+    boolean reportEnded(@Nullable Vibration.CallerInfo endedBy) {
         if (hasEnded()) {
             // Vibration already ended, keep first ending stats set and ignore this one.
             return false;
         }
-        mEndedByUid = endedByUid;
-        mEndedByUsage = endedByUsage;
+        if (endedBy != null) {
+            mEndedByUid = endedBy.uid;
+            mEndedByUsage = endedBy.attrs.getUsage();
+        }
         mEndUptimeMillis = SystemClock.uptimeMillis();
         mEndTimeDebug = System.currentTimeMillis();
+
         return true;
     }
 
@@ -177,9 +182,9 @@
      * <p>This method will only accept the first value as the one that was interrupted by this
      * vibration, and will ignore all successive calls.
      */
-    void reportInterruptedAnotherVibration(int interruptedUsage) {
+    void reportInterruptedAnotherVibration(@NonNull Vibration.CallerInfo callerInfo) {
         if (mInterruptedUsage < 0) {
-            mInterruptedUsage = interruptedUsage;
+            mInterruptedUsage = callerInfo.attrs.getUsage();
         }
     }
 
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index 11cab4b..4202afb 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -157,7 +157,7 @@
         mNextSteps.offer(new StartSequentialEffectStep(this, sequentialEffect));
         // Vibration will start playing in the Vibrator, following the effect timings and delays.
         // Report current time as the vibration start time, for debugging.
-        mVibration.stats().reportStarted();
+        mVibration.stats.reportStarted();
     }
 
     public HalVibration getVibration() {
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index d2dc43c..cfb4c74 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -161,7 +161,8 @@
             // for this thread.
             // No point doing this in finally, as if there's an exception, this thread will die
             // and be unusable anyway.
-            mVibratorManagerHooks.onVibrationThreadReleased(mExecutingConductor.getVibration().id);
+            mVibratorManagerHooks.onVibrationThreadReleased(
+                    mExecutingConductor.getVibration().id);
             synchronized (mLock) {
                 mLock.notifyAll();
             }
@@ -230,7 +231,8 @@
 
     /** Runs the VibrationThread ensuring that the wake lock is acquired and released. */
     private void runCurrentVibrationWithWakeLock() {
-        WorkSource workSource = new WorkSource(mExecutingConductor.getVibration().uid);
+        WorkSource workSource = new WorkSource(
+                mExecutingConductor.getVibration().callerInfo.uid);
         mWakeLock.setWorkSource(workSource);
         mWakeLock.acquire();
         try {
@@ -251,7 +253,7 @@
      * Called from within runWithWakeLock.
      */
     private void runCurrentVibrationWithWakeLockAndDeathLink() {
-        IBinder vibrationBinderToken = mExecutingConductor.getVibration().token;
+        IBinder vibrationBinderToken = mExecutingConductor.getVibration().callerToken;
         try {
             vibrationBinderToken.linkToDeath(mExecutingConductor, 0);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index c87332d..5756414 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -77,7 +77,6 @@
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
@@ -123,9 +122,6 @@
         }
     }
 
-    // Used to generate globally unique vibration ids.
-    private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback
-
     private final Object mLock = new Object();
     private final Context mContext;
     private final PowerManager.WakeLock mWakeLock;
@@ -367,8 +363,9 @@
                     // missing on individual vibrators.
                     return false;
                 }
-                AlwaysOnVibration alwaysOnVibration = new AlwaysOnVibration(
-                        alwaysOnId, uid, opPkg, attrs, effects);
+                AlwaysOnVibration alwaysOnVibration = new AlwaysOnVibration(alwaysOnId,
+                        new Vibration.CallerInfo(attrs, uid, Display.DEFAULT_DISPLAY, opPkg,
+                                null), effects);
                 mAlwaysOnEffects.put(alwaysOnId, alwaysOnVibration);
                 updateAlwaysOnLocked(alwaysOnVibration);
             }
@@ -408,8 +405,8 @@
             }
             attrs = fixupVibrationAttributes(attrs, effect);
             // Create Vibration.Stats as close to the received request as possible, for tracking.
-            HalVibration vib = new HalVibration(token, mNextVibrationId.getAndIncrement(), effect,
-                    attrs, uid, displayId, opPkg, reason);
+            HalVibration vib = new HalVibration(token, effect,
+                    new Vibration.CallerInfo(attrs, uid, displayId, opPkg, reason));
             fillVibrationFallbacks(vib, effect);
 
             if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
@@ -422,27 +419,23 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Starting vibrate for vibration " + vib.id);
                 }
-                int ignoredByUid = -1;
-                int ignoredByUsage = -1;
-                Vibration.Status status = null;
+                Vibration.CallerInfo ignoredByCallerInfo = null;
+                Vibration.Status status;
 
                 // Check if user settings or DnD is set to ignore this vibration.
-                status = shouldIgnoreVibrationLocked(vib.uid, vib.displayId, vib.opPkg, vib.attrs);
+                status = shouldIgnoreVibrationLocked(vib.callerInfo);
 
                 // Check if something has external control, assume it's more important.
                 if ((status == null) && (mCurrentExternalVibration != null)) {
                     status = Vibration.Status.IGNORED_FOR_EXTERNAL;
-                    ignoredByUid = mCurrentExternalVibration.externalVibration.getUid();
-                    ignoredByUsage = mCurrentExternalVibration.externalVibration
-                            .getVibrationAttributes().getUsage();
+                    ignoredByCallerInfo = mCurrentExternalVibration.callerInfo;
                 }
 
                 // Check if ongoing vibration is more important than this vibration.
                 if (status == null) {
                     status = shouldIgnoreVibrationForOngoingLocked(vib);
                     if (status != null) {
-                        ignoredByUid = mCurrentVibration.getVibration().uid;
-                        ignoredByUsage = mCurrentVibration.getVibration().attrs.getUsage();
+                        ignoredByCallerInfo = mCurrentVibration.getVibration().callerInfo;
                     }
                 }
 
@@ -460,12 +453,11 @@
                                     Slog.d(TAG, "Pipelining vibration " + vib.id);
                                 }
                             } else {
-                                vib.stats().reportInterruptedAnotherVibration(
-                                        mCurrentVibration.getVibration().attrs.getUsage());
+                                vib.stats.reportInterruptedAnotherVibration(
+                                        mCurrentVibration.getVibration().callerInfo);
                                 mCurrentVibration.notifyCancelled(
-                                        new Vibration.EndInfo(
-                                                Vibration.Status.CANCELLED_SUPERSEDED, vib.uid,
-                                                vib.attrs.getUsage()),
+                                        new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
+                                                vib.callerInfo),
                                         /* immediate= */ false);
                             }
                         }
@@ -478,7 +470,7 @@
                 // Ignored or failed to start the vibration, end it and report metrics right away.
                 if (status != Vibration.Status.RUNNING) {
                     endVibrationLocked(vib,
-                            new Vibration.EndInfo(status, ignoredByUid, ignoredByUsage),
+                            new Vibration.EndInfo(status, ignoredByCallerInfo),
                             /* shouldWriteStats= */ true);
                 }
                 return vib;
@@ -641,8 +633,7 @@
             }
 
             HalVibration vib = mCurrentVibration.getVibration();
-            Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
-                    vib.uid, vib.displayId, vib.opPkg, vib.attrs);
+            Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(vib.callerInfo);
 
             if (inputDevicesChanged || (ignoreStatus != null)) {
                 if (DEBUG) {
@@ -671,10 +662,9 @@
             if (vibrator == null) {
                 continue;
             }
-            Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
-                    vib.uid, Display.DEFAULT_DISPLAY, vib.opPkg, vib.attrs);
+            Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(vib.callerInfo);
             if (ignoreStatus == null) {
-                effect = mVibrationScaler.scale(effect, vib.attrs.getUsage());
+                effect = mVibrationScaler.scale(effect, vib.callerInfo.attrs.getUsage());
             } else {
                 // Vibration should not run, use null effect to remove registered effect.
                 effect = null;
@@ -687,9 +677,10 @@
     private Vibration.Status startVibrationLocked(HalVibration vib) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
         try {
-            vib.updateEffects(effect -> mVibrationScaler.scale(effect, vib.attrs.getUsage()));
+            vib.updateEffects(
+                    effect -> mVibrationScaler.scale(effect, vib.callerInfo.attrs.getUsage()));
             boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
-                    vib.uid, vib.opPkg, vib.getEffect(), vib.reason, vib.attrs);
+                    vib.callerInfo, vib.getEffect());
             if (inputDevicesAvailable) {
                 return Vibration.Status.FORWARDED_TO_INPUT_DEVICES;
             }
@@ -704,8 +695,7 @@
             // Note that we don't consider pipelining here, because new pipelined ones should
             // replace pending non-executing pipelined ones anyway.
             clearNextVibrationLocked(
-                    new Vibration.EndInfo(Vibration.Status.IGNORED_SUPERSEDED,
-                            vib.uid, vib.attrs.getUsage()));
+                    new Vibration.EndInfo(Vibration.Status.IGNORED_SUPERSEDED, vib.callerInfo));
             mNextVibration = conductor;
             return Vibration.Status.RUNNING;
         } finally {
@@ -718,7 +708,7 @@
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationThreadLocked");
         try {
             HalVibration vib = conductor.getVibration();
-            int mode = startAppOpModeLocked(vib.uid, vib.opPkg, vib.attrs);
+            int mode = startAppOpModeLocked(vib.callerInfo);
             switch (mode) {
                 case AppOpsManager.MODE_ALLOWED:
                     Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
@@ -731,7 +721,8 @@
                     }
                     return Vibration.Status.RUNNING;
                 case AppOpsManager.MODE_ERRORED:
-                    Slog.w(TAG, "Start AppOpsManager operation errored for uid " + vib.uid);
+                    Slog.w(TAG, "Start AppOpsManager operation errored for uid "
+                            + vib.callerInfo.uid);
                     return Vibration.Status.IGNORED_ERROR_APP_OPS;
                 default:
                     return Vibration.Status.IGNORED_APP_OPS;
@@ -745,7 +736,8 @@
     private void endVibrationLocked(HalVibration vib, Vibration.EndInfo vibrationEndInfo,
             boolean shouldWriteStats) {
         vib.end(vibrationEndInfo);
-        logVibrationStatus(vib.uid, vib.attrs, vibrationEndInfo.status);
+        logVibrationStatus(vib.callerInfo.uid, vib.callerInfo.attrs,
+                vibrationEndInfo.status);
         mVibratorManagerRecords.record(vib);
         if (shouldWriteStats) {
             mFrameworkStatsLogger.writeVibrationReportedAsync(
@@ -817,12 +809,13 @@
         try {
             HalVibration vib = mCurrentVibration.getVibration();
             if (DEBUG) {
-                Slog.d(TAG, "Reporting vibration " + vib.id + " finished with " + vibrationEndInfo);
+                Slog.d(TAG, "Reporting vibration " + vib.id + " finished with "
+                        + vibrationEndInfo);
             }
             // DO NOT write metrics at this point, wait for the VibrationThread to report the
             // vibration was released, after all cleanup. The metrics will be reported then.
             endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ false);
-            finishAppOpModeLocked(vib.uid, vib.opPkg);
+            finishAppOpModeLocked(vib.callerInfo);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
         }
@@ -830,7 +823,8 @@
 
     private void onSyncedVibrationComplete(long vibrationId) {
         synchronized (mLock) {
-            if (mCurrentVibration != null && mCurrentVibration.getVibration().id == vibrationId) {
+            if (mCurrentVibration != null
+                    && mCurrentVibration.getVibration().id == vibrationId) {
                 if (DEBUG) {
                     Slog.d(TAG, "Synced vibration " + vibrationId + " complete, notifying thread");
                 }
@@ -841,7 +835,8 @@
 
     private void onVibrationComplete(int vibratorId, long vibrationId) {
         synchronized (mLock) {
-            if (mCurrentVibration != null && mCurrentVibration.getVibration().id == vibrationId) {
+            if (mCurrentVibration != null
+                    && mCurrentVibration.getVibration().id == vibrationId) {
                 if (DEBUG) {
                     Slog.d(TAG, "Vibration " + vibrationId + " on vibrator " + vibratorId
                             + " complete, notifying thread");
@@ -871,8 +866,8 @@
             return null;
         }
 
-        int currentUsage = currentVibration.attrs.getUsage();
-        int newUsage = vib.attrs.getUsage();
+        int currentUsage = currentVibration.callerInfo.attrs.getUsage();
+        int newUsage = vib.callerInfo.attrs.getUsage();
         if (getVibrationImportance(currentUsage) > getVibrationImportance(newUsage)) {
             // Current vibration has higher importance than this one and should not be cancelled.
             return Vibration.Status.IGNORED_FOR_HIGHER_IMPORTANCE;
@@ -916,15 +911,13 @@
      */
     @GuardedBy("mLock")
     @Nullable
-    private Vibration.Status shouldIgnoreVibrationLocked(int uid, int displayId, String opPkg,
-            VibrationAttributes attrs) {
-        Vibration.Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(uid,
-                displayId, attrs);
+    private Vibration.Status shouldIgnoreVibrationLocked(Vibration.CallerInfo callerInfo) {
+        Vibration.Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(callerInfo);
         if (statusFromSettings != null) {
             return statusFromSettings;
         }
 
-        int mode = checkAppOpModeLocked(uid, opPkg, attrs);
+        int mode = checkAppOpModeLocked(callerInfo);
         if (mode != AppOpsManager.MODE_ALLOWED) {
             if (mode == AppOpsManager.MODE_ERRORED) {
                 // We might be getting calls from within system_server, so we don't actually
@@ -948,7 +941,8 @@
      *                    started with the same token can be cancelled with it.
      */
     private boolean shouldCancelVibration(HalVibration vib, int usageFilter, IBinder token) {
-        return (vib.token == token) && shouldCancelVibration(vib.attrs, usageFilter);
+        return (vib.callerToken == token) && shouldCancelVibration(vib.callerInfo.attrs,
+                usageFilter);
     }
 
     /**
@@ -973,24 +967,25 @@
      * {@code attrs}. This will return one of the AppOpsManager.MODE_*.
      */
     @GuardedBy("mLock")
-    private int checkAppOpModeLocked(int uid, String opPkg, VibrationAttributes attrs) {
+    private int checkAppOpModeLocked(Vibration.CallerInfo callerInfo) {
         int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
-                attrs.getAudioUsage(), uid, opPkg);
-        int fixedMode = fixupAppOpModeLocked(mode, attrs);
+                callerInfo.attrs.getAudioUsage(), callerInfo.uid, callerInfo.opPkg);
+        int fixedMode = fixupAppOpModeLocked(mode, callerInfo.attrs);
         if (mode != fixedMode && fixedMode == AppOpsManager.MODE_ALLOWED) {
             // If we're just ignoring the vibration op then this is set by DND and we should ignore
             // if we're asked to bypass. AppOps won't be able to record this operation, so make
             // sure we at least note it in the logs for debugging.
-            Slog.d(TAG, "Bypassing DND for vibrate from uid " + uid);
+            Slog.d(TAG, "Bypassing DND for vibrate from uid " + callerInfo.uid);
         }
         return fixedMode;
     }
 
     /** Start an operation in {@link AppOpsManager}, if allowed. */
     @GuardedBy("mLock")
-    private int startAppOpModeLocked(int uid, String opPkg, VibrationAttributes attrs) {
+    private int startAppOpModeLocked(Vibration.CallerInfo callerInfo) {
         return fixupAppOpModeLocked(
-                mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, uid, opPkg), attrs);
+                mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, callerInfo.uid, callerInfo.opPkg),
+                callerInfo.attrs);
     }
 
     /**
@@ -998,8 +993,8 @@
      * operation with same uid was previously started.
      */
     @GuardedBy("mLock")
-    private void finishAppOpModeLocked(int uid, String opPkg) {
-        mAppOps.finishOp(AppOpsManager.OP_VIBRATE, uid, opPkg);
+    private void finishAppOpModeLocked(Vibration.CallerInfo callerInfo) {
+        mAppOps.finishOp(AppOpsManager.OP_VIBRATE, callerInfo.uid, callerInfo.opPkg);
     }
 
     /**
@@ -1186,8 +1181,8 @@
             return false;
         }
         HalVibration vib = conductor.getVibration();
-        return mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                vib.uid, vib.opPkg, vib.attrs.getUsage(), vib.stats().getCreateUptimeMillis());
+        return mVibrationSettings.shouldCancelVibrationOnScreenOff(vib.callerInfo,
+                vib.stats.getCreateUptimeMillis());
     }
 
     @GuardedBy("mLock")
@@ -1385,31 +1380,33 @@
      */
     private static final class AlwaysOnVibration {
         public final int alwaysOnId;
-        public final int uid;
-        public final String opPkg;
-        public final VibrationAttributes attrs;
+        public final Vibration.CallerInfo callerInfo;
         public final SparseArray<PrebakedSegment> effects;
 
-        AlwaysOnVibration(int alwaysOnId, int uid, String opPkg, VibrationAttributes attrs,
+        AlwaysOnVibration(int alwaysOnId, Vibration.CallerInfo callerInfo,
                 SparseArray<PrebakedSegment> effects) {
             this.alwaysOnId = alwaysOnId;
-            this.uid = uid;
-            this.opPkg = opPkg;
-            this.attrs = attrs;
+            this.callerInfo = callerInfo;
             this.effects = effects;
         }
     }
 
     /** Holder for a {@link ExternalVibration}. */
-    private final class ExternalVibrationHolder implements IBinder.DeathRecipient {
+    private final class ExternalVibrationHolder extends Vibration implements
+            IBinder.DeathRecipient {
 
         public final ExternalVibration externalVibration;
-        public final VibrationStats stats = new VibrationStats();
         public int scale;
 
         private Vibration.Status mStatus;
 
         private ExternalVibrationHolder(ExternalVibration externalVibration) {
+            super(externalVibration.getToken(), new Vibration.CallerInfo(
+                    externalVibration.getVibrationAttributes(), externalVibration.getUid(),
+                    // TODO(b/243604888): propagating displayID from IExternalVibration instead of
+                    //  using INVALID_DISPLAY for all external vibrations.
+                    Display.INVALID_DISPLAY,
+                    externalVibration.getPackage(), null));
             this.externalVibration = externalVibration;
             this.scale = IExternalVibratorService.SCALE_NONE;
             mStatus = Vibration.Status.RUNNING;
@@ -1437,14 +1434,15 @@
                 return;
             }
             mStatus = info.status;
-            stats.reportEnded(info.endedByUid, info.endedByUsage);
+            stats.reportEnded(info.endedBy);
 
             if (stats.hasStarted()) {
                 // External vibration doesn't have feedback from total time the vibrator was playing
                 // with non-zero amplitude, so we use the duration between start and end times of
                 // the vibration as the time the vibrator was ON, since the haptic channels are
                 // open for this duration and can receive vibration waveform data.
-                stats.reportVibratorOn(stats.getEndUptimeMillis() - stats.getStartUptimeMillis());
+                stats.reportVibratorOn(
+                        stats.getEndUptimeMillis() - stats.getStartUptimeMillis());
             }
         }
 
@@ -1462,13 +1460,8 @@
         }
 
         public Vibration.DebugInfo getDebugInfo() {
-            return new Vibration.DebugInfo(
-                    mStatus, stats, /* effect= */ null, /* originalEffect= */ null, scale,
-                    externalVibration.getVibrationAttributes(), externalVibration.getUid(),
-                    // TODO(b/243604888): propagating displayID from IExternalVibration instead of
-                    // using INVALID_DISPLAY for all external vibrations.
-                    Display.INVALID_DISPLAY,
-                    externalVibration.getPackage(), /* reason= */ null);
+            return new Vibration.DebugInfo(mStatus, stats, /* effect= */ null,
+                    /* originalEffect= */ null, scale, callerInfo);
         }
 
         public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) {
@@ -1538,7 +1531,7 @@
         }
 
         synchronized void record(HalVibration vib) {
-            int usage = vib.attrs.getUsage();
+            int usage = vib.callerInfo.attrs.getUsage();
             if (!mPreviousVibrations.contains(usage)) {
                 mPreviousVibrations.put(usage, new LinkedList<>());
             }
@@ -1679,8 +1672,7 @@
             synchronized (mLock) {
                 // TODO(b/243604888): propagating displayID from IExternalVibration instead of
                 // using INVALID_DISPLAY for all external vibrations.
-                Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
-                        vib.getUid(), Display.INVALID_DISPLAY, vib.getPackage(), attrs);
+                Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(vibHolder.callerInfo);
                 if (ignoreStatus != null) {
                     vibHolder.scale = IExternalVibratorService.SCALE_MUTE;
                     // Failed to start the vibration, end it and report metrics right away.
@@ -1698,13 +1690,13 @@
                     // vibration that may be playing and ready the vibrator for external control.
                     if (mCurrentVibration != null) {
                         vibHolder.stats.reportInterruptedAnotherVibration(
-                                mCurrentVibration.getVibration().attrs.getUsage());
+                                mCurrentVibration.getVibration().callerInfo);
                         clearNextVibrationLocked(
                                 new Vibration.EndInfo(Vibration.Status.IGNORED_FOR_EXTERNAL,
-                                        vib.getUid(), attrs.getUsage()));
+                                        vibHolder.callerInfo));
                         mCurrentVibration.notifyCancelled(
                                 new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
-                                        vib.getUid(), attrs.getUsage()),
+                                        vibHolder.callerInfo),
                                 /* immediate= */ true);
                         waitForCompletion = true;
                     }
@@ -1720,11 +1712,10 @@
                     alreadyUnderExternalControl = true;
                     mCurrentExternalVibration.mute();
                     vibHolder.stats.reportInterruptedAnotherVibration(
-                            mCurrentExternalVibration.externalVibration
-                                    .getVibrationAttributes().getUsage());
+                            mCurrentExternalVibration.callerInfo);
                     endExternalVibrateLocked(
                             new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
-                                    vib.getUid(), attrs.getUsage()),
+                                    vibHolder.callerInfo),
                             /* continueExternalControl= */ true);
                 }
                 mCurrentExternalVibration = vibHolder;
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
index 2ac8b37..6edef75 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -263,7 +263,8 @@
     public void vibrateIfAvailable_withNoInputDevice_returnsFalse() {
         assertFalse(mInputDeviceDelegate.isAvailable());
         assertFalse(mInputDeviceDelegate.vibrateIfAvailable(
-                UID, PACKAGE_NAME, SYNCED_EFFECT, REASON, VIBRATION_ATTRIBUTES));
+                new Vibration.CallerInfo(VIBRATION_ATTRIBUTES, UID, -1, PACKAGE_NAME, REASON),
+                SYNCED_EFFECT));
     }
 
     @Test
@@ -277,7 +278,8 @@
         mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
 
         assertTrue(mInputDeviceDelegate.vibrateIfAvailable(
-                UID, PACKAGE_NAME, SYNCED_EFFECT, REASON, VIBRATION_ATTRIBUTES));
+                new Vibration.CallerInfo(VIBRATION_ATTRIBUTES, UID, -1, PACKAGE_NAME, REASON),
+                SYNCED_EFFECT));
         verify(mIInputManagerMock).vibrateCombined(eq(1), same(SYNCED_EFFECT), any());
         verify(mIInputManagerMock).vibrateCombined(eq(2), same(SYNCED_EFFECT), any());
     }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index 508e7b0f..d50aca9 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -564,17 +564,17 @@
 
         for (int usage : ALL_USAGES) {
             // Non-system vibration
-            assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                    UID, "some.app", usage, vibrateStartTime));
+            assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(createCallerInfo(
+                    UID, "some.app", usage), vibrateStartTime));
             // Vibration with UID zero
             assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                    /* uid= */ 0, "", usage, vibrateStartTime));
+                    createCallerInfo(/* uid= */ 0, "", usage), vibrateStartTime));
             // System vibration
             assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                    Process.SYSTEM_UID, "", usage, vibrateStartTime));
+                    createCallerInfo(Process.SYSTEM_UID, "", usage), vibrateStartTime));
             // SysUI vibration
             assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                    UID, SYSUI_PACKAGE_NAME, usage, vibrateStartTime));
+                    createCallerInfo(UID, SYSUI_PACKAGE_NAME, usage), vibrateStartTime));
         }
     }
 
@@ -592,16 +592,16 @@
             for (int usage : ALL_USAGES) {
                 // Non-system vibration
                 assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        UID, "some.app", usage, vibrateStartTime));
+                        createCallerInfo(UID, "some.app", usage), vibrateStartTime));
                 // Vibration with UID zero
                 assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        /* uid= */ 0, "", usage, vibrateStartTime));
+                        createCallerInfo(/* uid= */ 0, "", usage), vibrateStartTime));
                 // System vibration
                 assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        Process.SYSTEM_UID, "", usage, vibrateStartTime));
+                        createCallerInfo(Process.SYSTEM_UID, "", usage), vibrateStartTime));
                 // SysUI vibration
                 assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        UID, SYSUI_PACKAGE_NAME, usage, vibrateStartTime));
+                        createCallerInfo(UID, SYSUI_PACKAGE_NAME, usage), vibrateStartTime));
             }
         }
     }
@@ -613,7 +613,7 @@
 
         for (int usage : ALL_USAGES) {
             assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                    UID, "some.app", usage, vibrateStartTime));
+                    createCallerInfo(UID, "some.app", usage), vibrateStartTime));
         }
     }
 
@@ -626,10 +626,10 @@
             if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK
                     || usage == USAGE_PHYSICAL_EMULATION) {
                 assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        /* uid= */ 0, "", usage, vibrateStartTime));
+                        createCallerInfo(/* uid= */ 0, "", usage), vibrateStartTime));
             } else {
                 assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        /* uid= */ 0, "", usage, vibrateStartTime));
+                        createCallerInfo(/* uid= */ 0, "", usage), vibrateStartTime));
             }
         }
     }
@@ -643,10 +643,10 @@
             if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK
                     || usage == USAGE_PHYSICAL_EMULATION) {
                 assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        Process.SYSTEM_UID, "", usage, vibrateStartTime));
+                        createCallerInfo(Process.SYSTEM_UID, "", usage), vibrateStartTime));
             } else {
                 assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        Process.SYSTEM_UID, "", usage, vibrateStartTime));
+                        createCallerInfo(Process.SYSTEM_UID, "", usage), vibrateStartTime));
             }
         }
     }
@@ -660,10 +660,10 @@
             if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK
                     || usage == USAGE_PHYSICAL_EMULATION) {
                 assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        UID, SYSUI_PACKAGE_NAME, usage, vibrateStartTime));
+                        createCallerInfo(UID, SYSUI_PACKAGE_NAME, usage), vibrateStartTime));
             } else {
                 assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                        UID, SYSUI_PACKAGE_NAME, usage, vibrateStartTime));
+                        createCallerInfo(UID, SYSUI_PACKAGE_NAME, usage), vibrateStartTime));
             }
         }
     }
@@ -755,10 +755,10 @@
 
     private void assertVibrationIgnoredForUsageAndDisplay(@VibrationAttributes.Usage int usage,
             int displayId, Vibration.Status expectedStatus) {
-        assertEquals(errorMessageForUsage(usage),
-                expectedStatus,
-                mVibrationSettings.shouldIgnoreVibration(UID, displayId,
-                        VibrationAttributes.createForUsage(usage)));
+        Vibration.CallerInfo callerInfo = new Vibration.CallerInfo(
+                VibrationAttributes.createForUsage(usage), UID, displayId, null, null);
+        assertEquals(errorMessageForUsage(usage), expectedStatus,
+                mVibrationSettings.shouldIgnoreVibration(callerInfo));
     }
 
     private void assertVibrationNotIgnoredForUsage(@VibrationAttributes.Usage int usage) {
@@ -767,24 +767,22 @@
 
     private void assertVibrationNotIgnoredForUsageAndFlags(@VibrationAttributes.Usage int usage,
             @VibrationAttributes.Flag int flags) {
-        assertVibrationNotIgnoredForUsageAndFlagsAndDidsplay(usage, Display.DEFAULT_DISPLAY, flags);
+        assertVibrationNotIgnoredForUsageAndFlagsAndDisplay(usage, Display.DEFAULT_DISPLAY, flags);
     }
 
     private void assertVibrationNotIgnoredForUsageAndDisplay(@VibrationAttributes.Usage int usage,
             int displayId) {
-        assertVibrationNotIgnoredForUsageAndFlagsAndDidsplay(usage, displayId, /* flags= */ 0);
+        assertVibrationNotIgnoredForUsageAndFlagsAndDisplay(usage, displayId, /* flags= */ 0);
     }
 
-    private void assertVibrationNotIgnoredForUsageAndFlagsAndDidsplay(
+    private void assertVibrationNotIgnoredForUsageAndFlagsAndDisplay(
             @VibrationAttributes.Usage int usage, int displayId,
             @VibrationAttributes.Flag int flags) {
+        Vibration.CallerInfo callerInfo = new Vibration.CallerInfo(
+                new VibrationAttributes.Builder().setUsage(usage).setFlags(flags).build(), UID,
+                displayId, null, null);
         assertNull(errorMessageForUsage(usage),
-                mVibrationSettings.shouldIgnoreVibration(UID,
-                        displayId,
-                        new VibrationAttributes.Builder()
-                                .setUsage(usage)
-                                .setFlags(flags)
-                                .build()));
+                mVibrationSettings.shouldIgnoreVibration(callerInfo));
     }
 
 
@@ -826,4 +824,10 @@
         when(mPowerManagerInternalMock.getLastGoToSleep()).thenReturn(
                 new PowerManager.SleepData(sleepTime, reason));
     }
+
+    private Vibration.CallerInfo createCallerInfo(int uid, String opPkg,
+            @VibrationAttributes.Usage int usage) {
+        VibrationAttributes attrs = VibrationAttributes.createForUsage(usage);
+        return new Vibration.CallerInfo(attrs, uid, VIRTUAL_DISPLAY_ID, opPkg, null);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index 9facb4b..12810bb 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -154,10 +154,10 @@
     @Test
     public void vibrate_noVibrator_ignoresVibration() {
         mVibratorProviders.clear();
-        long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.createParallel(
                 VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mControllerCallbacks, never()).onComplete(anyInt(), eq(vibrationId));
@@ -166,12 +166,12 @@
 
     @Test
     public void vibrate_missingVibrators_ignoresVibration() {
-        long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.startSequential()
                 .addNext(2, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
                 .addNext(3, VibrationEffect.get(VibrationEffect.EFFECT_TICK))
                 .combine();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mControllerCallbacks, never()).onComplete(anyInt(), eq(vibrationId));
@@ -182,9 +182,9 @@
     public void vibrate_singleVibratorOneShot_runsVibrationAndSetsAmplitude() throws Exception {
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.createOneShot(10, 100);
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
@@ -201,9 +201,9 @@
     @Test
     public void vibrate_oneShotWithoutAmplitudeControl_runsVibrationWithDefaultAmplitude()
             throws Exception {
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.createOneShot(10, 100);
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
@@ -222,10 +222,10 @@
             throws Exception {
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.createWaveform(
                 new long[]{5, 5, 5}, new int[]{1, 2, 3}, -1);
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(15L));
@@ -246,10 +246,10 @@
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         int[] amplitudes = new int[]{1, 2, 3};
         VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5, 5, 5}, amplitudes, 0);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(
                 waitUntil(() -> fakeVibrator.getAmplitudes().size() > 2 * amplitudes.length,
@@ -259,8 +259,9 @@
         assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());
 
         Vibration.EndInfo cancelVibrationInfo = new Vibration.EndInfo(
-                Vibration.Status.CANCELLED_SUPERSEDED, /* endedByUid= */ 1,
-                /* endedByUsage= */ VibrationAttributes.USAGE_ALARM);
+                Vibration.Status.CANCELLED_SUPERSEDED, new Vibration.CallerInfo(
+                VibrationAttributes.createForUsage(VibrationAttributes.USAGE_ALARM), /* uid= */
+                1, /* displayId= */ -1, /* opPkg= */ null, /* reason= */ null));
         conductor.notifyCancelled(
                 cancelVibrationInfo,
                 /* immediate= */ false);
@@ -287,11 +288,11 @@
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         int[] amplitudes = new int[]{1, 2, 3};
         VibrationEffect effect = VibrationEffect.createWaveform(
                 new long[]{1, 10, 100}, amplitudes, 0);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> !fakeVibrator.getAmplitudes().isEmpty(), TEST_TIMEOUT_MILLIS));
         conductor.notifyCancelled(
@@ -315,7 +316,6 @@
         fakeVibrator.setMaxAmplitudes(1, 1, 1);
         fakeVibrator.setPwleSizeMax(10);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startWaveform(targetAmplitude(1))
                 // Very long segment so thread will be cancelled after first PWLE is triggered.
                 .addTransition(Duration.ofMillis(100), targetFrequency(100))
@@ -323,7 +323,8 @@
         VibrationEffect repeatingEffect = VibrationEffect.startComposition()
                 .repeatEffectIndefinitely(effect)
                 .compose();
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, repeatingEffect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(repeatingEffect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> !fakeVibrator.getEffectSegments(vibrationId).isEmpty(),
                 TEST_TIMEOUT_MILLIS));
@@ -346,7 +347,6 @@
         fakeVibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK);
         fakeVibrator.setCompositionSizeMax(10);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startComposition()
                 // Very long delay so thread will be cancelled after first PWLE is triggered.
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
@@ -354,7 +354,8 @@
         VibrationEffect repeatingEffect = VibrationEffect.startComposition()
                 .repeatEffectIndefinitely(effect)
                 .compose();
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, repeatingEffect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(repeatingEffect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> !fakeVibrator.getEffectSegments(vibrationId).isEmpty(),
                 TEST_TIMEOUT_MILLIS));
@@ -375,11 +376,11 @@
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         int[] amplitudes = new int[]{1, 2, 3};
         VibrationEffect effect = VibrationEffect.createWaveform(
                 new long[]{5000, 500, 50}, amplitudes, 0);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> !fakeVibrator.getAmplitudes().isEmpty(), TEST_TIMEOUT_MILLIS));
         conductor.notifyCancelled(
@@ -400,11 +401,11 @@
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         int[] amplitudes = new int[]{1, 2};
         VibrationEffect effect = VibrationEffect.createWaveform(
                 new long[]{4900, 50}, amplitudes, 0);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> fakeVibrator.getEffectSegments(vibrationId).size() > 1,
                 5000 + TEST_TIMEOUT_MILLIS));
@@ -433,13 +434,13 @@
         mVibratorProviders.get(VIBRATOR_ID).setSupportedPrimitives(
                 VibrationEffect.Composition.PRIMITIVE_CLICK);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
                 .compose();
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(),
                 TEST_TIMEOUT_MILLIS));
@@ -466,9 +467,9 @@
             throws Exception {
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.createWaveform(new long[]{100}, new int[]{100}, 0);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(),
                 TEST_TIMEOUT_MILLIS));
@@ -494,9 +495,9 @@
     public void vibrate_singleVibratorPrebaked_runsVibration() throws Exception {
         mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_THUD);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_THUD);
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
@@ -514,12 +515,12 @@
             throws Exception {
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         VibrationEffect fallback = VibrationEffect.createOneShot(10, 100);
-        HalVibration vibration = createVibration(vibrationId, CombinedVibration.createParallel(
+        HalVibration vibration = createVibration(CombinedVibration.createParallel(
                 VibrationEffect.get(VibrationEffect.EFFECT_CLICK)));
         vibration.addFallback(VibrationEffect.EFFECT_CLICK, fallback);
-        startThreadAndDispatcher(vibration);
+        VibrationStepConductor conductor = startThreadAndDispatcher(vibration);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
@@ -536,9 +537,9 @@
     @Test
     public void vibrate_singleVibratorPrebakedAndUnsupportedEffect_ignoresVibration()
             throws Exception {
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(0L));
@@ -555,12 +556,12 @@
         fakeVibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK,
                 VibrationEffect.Composition.PRIMITIVE_TICK);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
                 .compose();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(40L));
@@ -576,11 +577,11 @@
 
     @Test
     public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() {
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
                 .compose();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(0L));
@@ -600,13 +601,13 @@
                 VibrationEffect.Composition.PRIMITIVE_SPIN);
         fakeVibrator.setCompositionSizeMax(2);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.8f)
                 .compose();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
@@ -630,7 +631,6 @@
         fakeVibrator.setMaxAmplitudes(
                 0.5f /* 100Hz*/, 1 /* 150Hz */, 0.6f /* 200Hz */);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addEffect(VibrationEffect.createOneShot(10, 100))
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
@@ -643,7 +643,8 @@
                         .build())
                 .addEffect(VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
                 .compose();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         // Use first duration the vibrator is turned on since we cannot estimate the clicks.
@@ -675,7 +676,6 @@
                 VibrationEffect.Composition.PRIMITIVE_TICK);
         fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
 
-        long vibrationId = 1;
         VibrationEffect fallback = VibrationEffect.createOneShot(10, 100);
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addEffect(VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
@@ -683,9 +683,10 @@
                 .addEffect(VibrationEffect.get(VibrationEffect.EFFECT_TICK))
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
                 .compose();
-        HalVibration vib = createVibration(vibrationId, CombinedVibration.createParallel(effect));
+        HalVibration vib = createVibration(CombinedVibration.createParallel(effect));
         vib.addFallback(VibrationEffect.EFFECT_TICK, fallback);
-        startThreadAndDispatcher(vib);
+        VibrationStepConductor conductor = startThreadAndDispatcher(vib);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         // Use first duration the vibrator is turned on since we cannot estimate the clicks.
@@ -718,7 +719,6 @@
         fakeVibrator.setMaxAmplitudes(
                 0.5f /* 100Hz*/, 1 /* 150Hz */, 0.6f /* 200Hz */);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startWaveform(targetAmplitude(1))
                 .addSustain(Duration.ofMillis(10))
                 .addTransition(Duration.ofMillis(20), targetAmplitude(0))
@@ -726,7 +726,8 @@
                 .addSustain(Duration.ofMillis(30))
                 .addTransition(Duration.ofMillis(40), targetAmplitude(0.6f), targetFrequency(200))
                 .build();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(100L));
@@ -756,7 +757,6 @@
         fakeVibrator.setMaxAmplitudes(1, 1, 1);
         fakeVibrator.setPwleSizeMax(3);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startWaveform(targetAmplitude(1))
                 .addSustain(Duration.ofMillis(10))
                 .addTransition(Duration.ofMillis(20), targetAmplitude(0))
@@ -768,7 +768,8 @@
                 .addTransition(Duration.ofMillis(40), targetAmplitude(0.7f), targetFrequency(200))
                 .addTransition(Duration.ofMillis(40), targetAmplitude(0.6f), targetFrequency(200))
                 .build();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
@@ -784,9 +785,9 @@
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> fakeVibrator.getAmplitudes().size() > 2, TEST_TIMEOUT_MILLIS));
         // Vibration still running after 2 cycles.
@@ -804,9 +805,9 @@
     public void vibrate_singleVibrator_skipsSyncedCallbacks() {
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
-        startThreadAndDispatcher(vibrationId,
+        VibrationStepConductor conductor = startThreadAndDispatcher(
                 VibrationEffect.createOneShot(10, 100));
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
@@ -820,12 +821,12 @@
             throws Exception {
         mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_TICK);
 
-        long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.startParallel()
                 .addVibrator(VIBRATOR_ID, VibrationEffect.get(VibrationEffect.EFFECT_TICK))
                 .addVibrator(2, VibrationEffect.get(VibrationEffect.EFFECT_TICK))
                 .combine();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
@@ -846,10 +847,10 @@
         mVibratorProviders.get(2).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         mVibratorProviders.get(3).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
 
-        long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.createParallel(
                 VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
@@ -881,7 +882,6 @@
         mVibratorProviders.get(4).setSupportedPrimitives(
                 VibrationEffect.Composition.PRIMITIVE_CLICK);
 
-        long vibrationId = 1;
         VibrationEffect composed = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                 .compose();
@@ -892,7 +892,8 @@
                         new long[]{10, 10}, new int[]{1, 2}, -1))
                 .addVibrator(4, composed)
                 .combine();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
@@ -929,7 +930,6 @@
                 VibrationEffect.Composition.PRIMITIVE_CLICK);
         mVibratorProviders.get(3).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
 
-        long vibrationId = 1;
         VibrationEffect composed = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                 .compose();
@@ -938,7 +938,8 @@
                 .addNext(1, VibrationEffect.createOneShot(10, 100), /* delay= */ 50)
                 .addNext(2, composed, /* delay= */ 50)
                 .combine();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         waitForCompletion();
         InOrder controllerVerifier = inOrder(mControllerCallbacks);
@@ -972,7 +973,6 @@
     @Test
     public void vibrate_multipleSyncedCallbackTriggered_finishSteps() throws Exception {
         int[] vibratorIds = new int[]{1, 2};
-        long vibrationId = 1;
         mockVibrators(vibratorIds);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
         mVibratorProviders.get(1).setSupportedPrimitives(
@@ -981,13 +981,15 @@
         mVibratorProviders.get(2).setSupportedPrimitives(
                 VibrationEffect.Composition.PRIMITIVE_CLICK);
         when(mManagerHooks.prepareSyncedVibration(anyLong(), eq(vibratorIds))).thenReturn(true);
-        when(mManagerHooks.triggerSyncedVibration(eq(vibrationId))).thenReturn(true);
 
         VibrationEffect composed = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 100)
                 .compose();
         CombinedVibration effect = CombinedVibration.createParallel(composed);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
+
+        when(mManagerHooks.triggerSyncedVibration(eq(vibrationId))).thenReturn(true);
 
         assertTrue(waitUntil(
                 () -> !mVibratorProviders.get(1).getEffectSegments(vibrationId).isEmpty()
@@ -1021,7 +1023,6 @@
         when(mManagerHooks.prepareSyncedVibration(anyLong(), any())).thenReturn(true);
         when(mManagerHooks.triggerSyncedVibration(anyLong())).thenReturn(true);
 
-        long vibrationId = 1;
         VibrationEffect composed = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                 .compose();
@@ -1031,7 +1032,8 @@
                 .addVibrator(3, VibrationEffect.createWaveform(new long[]{10}, new int[]{100}, -1))
                 .addVibrator(4, composed)
                 .combine();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         long expectedCap = IVibratorManager.CAP_SYNC
@@ -1055,12 +1057,12 @@
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         when(mManagerHooks.prepareSyncedVibration(anyLong(), any())).thenReturn(false);
 
-        long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.startParallel()
                 .addVibrator(1, VibrationEffect.createOneShot(10, 100))
                 .addVibrator(2, VibrationEffect.createWaveform(new long[]{5}, new int[]{200}, -1))
                 .combine();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         long expectedCap = IVibratorManager.CAP_SYNC | IVibratorManager.CAP_PREPARE_ON;
@@ -1084,12 +1086,12 @@
         when(mManagerHooks.prepareSyncedVibration(anyLong(), any())).thenReturn(true);
         when(mManagerHooks.triggerSyncedVibration(anyLong())).thenReturn(false);
 
-        long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.startParallel()
                 .addVibrator(1, VibrationEffect.createOneShot(10, 100))
                 .addVibrator(2, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
                 .combine();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         long expectedCap = IVibratorManager.CAP_SYNC
@@ -1110,7 +1112,6 @@
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         mVibratorProviders.get(3).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.startParallel()
                 .addVibrator(1, VibrationEffect.createWaveform(
                         new long[]{5, 10, 10}, new int[]{1, 2, 3}, -1))
@@ -1119,7 +1120,8 @@
                 .addVibrator(3, VibrationEffect.createWaveform(
                         new long[]{60}, new int[]{6}, -1))
                 .combine();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         // All vibrators are turned on in parallel.
         assertTrue(waitUntil(
@@ -1169,8 +1171,7 @@
         Arrays.fill(amplitudes, VibrationEffect.DEFAULT_AMPLITUDE);
         VibrationEffect effect = VibrationEffect.createWaveform(timings, amplitudes, -1);
 
-        long vibrationId = 1;
-        startThreadAndDispatcher(vibrationId, effect);
+        startThreadAndDispatcher(effect);
         long startTime = SystemClock.elapsedRealtime();
 
         waitForCompletion(totalDuration + TEST_TIMEOUT_MILLIS);
@@ -1192,9 +1193,9 @@
         long latency = 5_000; // 5s
         fakeVibrator.setOnLatency(latency);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> !fakeVibrator.getEffectSegments(vibrationId).isEmpty(),
                 TEST_TIMEOUT_MILLIS));
@@ -1226,7 +1227,6 @@
         mVibratorProviders.get(2).setSupportedPrimitives(
                 VibrationEffect.Composition.PRIMITIVE_CLICK);
 
-        long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.startParallel()
                 .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
                 .addVibrator(2, VibrationEffect.startComposition()
@@ -1235,7 +1235,8 @@
                         .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
                         .compose())
                 .combine();
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> mControllers.get(2).isVibrating(),
                 TEST_TIMEOUT_MILLIS));
@@ -1264,13 +1265,13 @@
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.startParallel()
                 .addVibrator(1, VibrationEffect.createWaveform(
                         new long[]{100, 100}, new int[]{1, 2}, 0))
                 .addVibrator(2, VibrationEffect.createOneShot(100, 100))
                 .combine();
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> mControllers.get(1).isVibrating()
                         && mControllers.get(2).isVibrating(),
@@ -1296,9 +1297,9 @@
 
     @Test
     public void vibrate_binderDied_cancelsVibration() throws Exception {
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(),
                 TEST_TIMEOUT_MILLIS));
@@ -1320,10 +1321,10 @@
         mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings);
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.createWaveform(
                 new long[]{5, 5, 5}, new int[]{60, 120, 240}, -1);
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
@@ -1346,9 +1347,9 @@
         mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings);
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.createOneShot(10, 200);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
 
         // Vibration completed but vibrator not yet released.
         verify(mManagerHooks, timeout(TEST_TIMEOUT_MILLIS)).onVibrationCompleted(eq(vibrationId),
@@ -1381,9 +1382,9 @@
         mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings);
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.createOneShot(10_000, 240);
-        VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(),
                 TEST_TIMEOUT_MILLIS));
         conductor.notifyCancelled(
@@ -1410,9 +1411,9 @@
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         mVibratorProviders.get(VIBRATOR_ID).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
@@ -1432,11 +1433,11 @@
         mVibratorProviders.get(VIBRATOR_ID).setSupportedPrimitives(
                 VibrationEffect.Composition.PRIMITIVE_CLICK);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                 .compose();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
@@ -1461,11 +1462,11 @@
         fakeVibrator.setMaxAmplitudes(1, 1, 1);
         fakeVibrator.setPwleSizeMax(2);
 
-        long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startWaveform()
                 .addTransition(Duration.ofMillis(1), targetAmplitude(1))
                 .build();
-        startThreadAndDispatcher(vibrationId, effect);
+        VibrationStepConductor conductor = startThreadAndDispatcher(effect);
+        long vibrationId = conductor.getVibration().id;
         waitForCompletion();
 
         verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
@@ -1485,12 +1486,6 @@
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL,
                 IVibrator.CAP_COMPOSE_EFFECTS);
 
-        long vibrationId1 = 1;
-        long vibrationId2 = 2;
-        long vibrationId3 = 3;
-        long vibrationId4 = 4;
-        long vibrationId5 = 5;
-
         // A simple effect, followed by a repeating effect that gets cancelled, followed by another
         // simple effect.
         VibrationEffect effect1 = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
@@ -1503,12 +1498,14 @@
         VibrationEffect effect4 = VibrationEffect.createOneShot(8000, 100);
         VibrationEffect effect5 = VibrationEffect.createOneShot(20, 222);
 
-        startThreadAndDispatcher(vibrationId1, effect1);
+        VibrationStepConductor conductor1 = startThreadAndDispatcher(effect1);
+        long vibrationId1 = conductor1.getVibration().id;
         waitForCompletion();
         verify(mControllerCallbacks).onComplete(VIBRATOR_ID, vibrationId1);
         verifyCallbacksTriggered(vibrationId1, Vibration.Status.FINISHED);
 
-        VibrationStepConductor conductor2 = startThreadAndDispatcher(vibrationId2, effect2);
+        VibrationStepConductor conductor2 = startThreadAndDispatcher(effect2);
+        long vibrationId2 = conductor2.getVibration().id;
         // Effect2 won't complete on its own. Cancel it after a couple of repeats.
         Thread.sleep(150);  // More than two TICKs.
         conductor2.notifyCancelled(
@@ -1516,12 +1513,14 @@
                 /* immediate= */ false);
         waitForCompletion();
 
-        startThreadAndDispatcher(vibrationId3, effect3);
+        VibrationStepConductor conductor3 = startThreadAndDispatcher(effect3);
+        long vibrationId3 = conductor3.getVibration().id;
         waitForCompletion();
 
         // Effect4 is a long oneshot, but it gets cancelled as fast as possible.
         long start4 = System.currentTimeMillis();
-        VibrationStepConductor conductor4 = startThreadAndDispatcher(vibrationId4, effect4);
+        VibrationStepConductor conductor4 = startThreadAndDispatcher(effect4);
+        long vibrationId4 = conductor4.getVibration().id;
         conductor4.notifyCancelled(
                 new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
                 /* immediate= */ true);
@@ -1529,7 +1528,8 @@
         long duration4 = System.currentTimeMillis() - start4;
 
         // Effect5 is to show that things keep going after the immediate cancel.
-        startThreadAndDispatcher(vibrationId5, effect5);
+        VibrationStepConductor conductor5 = startThreadAndDispatcher(effect5);
+        long vibrationId5 = conductor5.getVibration().id;
         waitForCompletion();
 
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
@@ -1582,14 +1582,12 @@
         }
     }
 
-    private VibrationStepConductor startThreadAndDispatcher(
-            long vibrationId, VibrationEffect effect) {
-        return startThreadAndDispatcher(vibrationId, CombinedVibration.createParallel(effect));
+    private VibrationStepConductor startThreadAndDispatcher(VibrationEffect effect) {
+        return startThreadAndDispatcher(CombinedVibration.createParallel(effect));
     }
 
-    private VibrationStepConductor startThreadAndDispatcher(long vibrationId,
-            CombinedVibration effect) {
-        return startThreadAndDispatcher(createVibration(vibrationId, effect));
+    private VibrationStepConductor startThreadAndDispatcher(CombinedVibration effect) {
+        return startThreadAndDispatcher(createVibration(effect));
     }
 
     private VibrationStepConductor startThreadAndDispatcher(HalVibration vib) {
@@ -1624,9 +1622,9 @@
         mTestLooper.dispatchAll();  // Flush callbacks
     }
 
-    private HalVibration createVibration(long id, CombinedVibration effect) {
-        return new HalVibration(mVibrationToken, (int) id, effect, ATTRS, UID, DISPLAY_ID,
-                PACKAGE_NAME, "reason");
+    private HalVibration createVibration(CombinedVibration effect) {
+        return new HalVibration(mVibrationToken, effect,
+                new Vibration.CallerInfo(ATTRS, UID, DISPLAY_ID, PACKAGE_NAME, "reason"));
     }
 
     private SparseArray<VibratorController> createVibratorControllers() {