diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java index 58407cf7fd461..e12426b2b02c6 100644 --- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java +++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java @@ -60,8 +60,6 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { static final float RAMP_OFF_AMPLITUDE_MIN = 1e-3f; static final List EMPTY_STEP_LIST = new ArrayList<>(); - private final Object mLock = new Object(); - // Used within steps. public final VibrationSettings vibrationSettings; public final DeviceVibrationEffectAdapter deviceEffectAdapter; @@ -74,6 +72,11 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { private final Queue mPendingOnVibratorCompleteSteps = new LinkedList<>(); // Signalling fields. + // Note that vibrator callback signals may happen inside vibrator HAL calls made by the + // VibrationThread, or on an external executor, so this lock should not be held for anything + // other than updating signalling state - particularly not during HAL calls or when invoking + // other callbacks that may trigger calls into the thread. + private final Object mLock = new Object(); @GuardedBy("mLock") private final IntArray mSignalVibratorsComplete; @GuardedBy("mLock") @@ -334,9 +337,9 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { * The state update is recorded for processing on the main execution thread (VibrationThread). */ public void notifyVibratorComplete(int vibratorId) { - if (Build.IS_DEBUGGABLE) { - expectIsVibrationThread(false); - } + // HAL callbacks may be triggered directly within HAL calls, so these notifications + // could be on the VibrationThread as it calls the HAL, or some other executor later. + // Therefore no thread assertion is made here. if (DEBUG) { Slog.d(TAG, "Vibration complete reported by vibrator " + vibratorId); @@ -356,9 +359,9 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { * (VibrationThread). */ public void notifySyncedVibrationComplete() { - if (Build.IS_DEBUGGABLE) { - expectIsVibrationThread(false); - } + // HAL callbacks may be triggered directly within HAL calls, so these notifications + // could be on the VibrationThread as it calls the HAL, or some other executor later. + // Therefore no thread assertion is made here. if (DEBUG) { Slog.d(TAG, "Synced vibration complete reported by vibrator manager"); @@ -394,7 +397,7 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { int[] vibratorsToProcess = null; boolean doCancel = false; boolean doCancelImmediate = false; - // Swap out the queue of completions to process. + // Collect signals to process, but don't keep the lock while processing them. synchronized (mLock) { if (mSignalCancelImmediate) { if (mCancelledImmediately) { @@ -407,6 +410,7 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { doCancel = true; } if (!doCancelImmediate && mSignalVibratorsComplete.size() > 0) { + // Swap out the queue of completions to process. vibratorsToProcess = mSignalVibratorsComplete.toArray(); // makes a copy mSignalVibratorsComplete.clear(); } diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java index 205ea62496ff3..cecc5c04dedcb 100644 --- a/services/core/java/com/android/server/vibrator/VibrationThread.java +++ b/services/core/java/com/android/server/vibrator/VibrationThread.java @@ -22,6 +22,7 @@ import android.os.IBinder; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; +import android.os.SystemClock; import android.os.Trace; import android.os.WorkSource; import android.util.Slog; @@ -176,7 +177,7 @@ final class VibrationThread extends Thread { * @return true if the vibration completed, or false if waiting timed out. */ public boolean waitForThreadIdle(long maxWaitMillis) { - long now = System.currentTimeMillis(); + long now = SystemClock.elapsedRealtime(); long deadline = now + maxWaitMillis; synchronized (mLock) { while (true) { @@ -191,7 +192,7 @@ final class VibrationThread extends Thread { } catch (InterruptedException e) { Slog.w(TAG, "VibrationThread interrupted waiting to stop, continuing"); } - now = System.currentTimeMillis(); + now = SystemClock.elapsedRealtime(); } } }