From 0694afac2ba2b13bec4df12a32c0af2264f3cf31 Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Fri, 13 Nov 2020 17:41:00 +0000 Subject: [PATCH] Extract Vibration class to vibrator package. This class currently holds a VibrationEffect, but will be changed to hold a CombinedVibrationEffect and used to represent a vibration call to VibratorManagerService. Bug: 167946816 Bug: 131311651 Test: atest FrameworksServiceTests:VibratorServiceTest Change-Id: I65985b6a079458b610a9a2728c3df157f9cee953 --- .../server/VibratorManagerService.java | 2 +- .../com/android/server/VibratorService.java | 488 +++++------------- .../android/server/vibrator/Vibration.java | 287 ++++++++++ .../server/vibrator/VibrationScaler.java | 1 - 4 files changed, 425 insertions(+), 353 deletions(-) create mode 100644 services/core/java/com/android/server/vibrator/Vibration.java diff --git a/services/core/java/com/android/server/VibratorManagerService.java b/services/core/java/com/android/server/VibratorManagerService.java index 356cd0cd937b9..f1f2815be8fa7 100644 --- a/services/core/java/com/android/server/VibratorManagerService.java +++ b/services/core/java/com/android/server/VibratorManagerService.java @@ -159,7 +159,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { pw.println(" Prints this help text."); pw.println(""); pw.println(" list"); - pw.println(" Prints the id of device vibrators. This do not include any "); + pw.println(" Prints the id of device vibrators. This does not include any "); pw.println(" connected input device."); pw.println(""); } diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 6d16f4c25e83e..db2b4e4edd2bc 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -16,8 +16,6 @@ package com.android.server; -import static android.os.VibrationEffect.Composition.PrimitiveEffect; - import android.annotation.Nullable; import android.app.ActivityManager; import android.app.AppOpsManager; @@ -64,6 +62,7 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.vibrator.InputDeviceDelegate; +import com.android.server.vibrator.Vibration; import com.android.server.vibrator.VibrationScaler; import com.android.server.vibrator.VibrationSettings; import com.android.server.vibrator.VibratorController; @@ -72,9 +71,7 @@ import com.android.server.vibrator.VibratorController.OnVibrationCompleteListene import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -82,8 +79,6 @@ import java.util.concurrent.atomic.AtomicInteger; /** System implementation of {@link IVibratorService}. */ public class VibratorService extends IVibratorService.Stub { private static final String TAG = "VibratorService"; - private static final SimpleDateFormat DEBUG_DATE_FORMAT = - new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); private static final boolean DEBUG = false; private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service"; @@ -94,11 +89,11 @@ public class VibratorService extends IVibratorService.Stub { // Used to generate globally unique vibration ids. private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback - private final LinkedList mPreviousRingVibrations; - private final LinkedList mPreviousNotificationVibrations; - private final LinkedList mPreviousAlarmVibrations; - private final LinkedList mPreviousExternalVibrations; - private final LinkedList mPreviousVibrations; + private final LinkedList mPreviousRingVibrations; + private final LinkedList mPreviousNotificationVibrations; + private final LinkedList mPreviousAlarmVibrations; + private final LinkedList mPreviousExternalVibrations; + private final LinkedList mPreviousVibrations; private final int mPreviousVibrationsLimit; private final SparseArray mProcStatesCache = new SparseArray<>(); private final WorkSource mTmpWorkSource = new WorkSource(); @@ -120,6 +115,8 @@ public class VibratorService extends IVibratorService.Stub { @GuardedBy("mLock") private Vibration mCurrentVibration; + @GuardedBy("mLock") + private VibrationDeathRecipient mCurrentVibrationDeathRecipient; private int mCurVibUid = -1; private ExternalVibrationHolder mCurrentExternalVibration; private boolean mLowPowerMode; @@ -167,101 +164,33 @@ public class VibratorService extends IVibratorService.Stub { } } - /** Holder for a {@link VibrationEffect}. */ - private final class Vibration implements IBinder.DeathRecipient { + /** Death recipient to bind {@link Vibration}. */ + private final class VibrationDeathRecipient implements IBinder.DeathRecipient { - public final IBinder token; - // Start time in CLOCK_BOOTTIME base. - public final long startTime; - public final VibrationAttributes attrs; - public final long id; - public final int uid; - public final String opPkg; - public final String reason; + private final Vibration mVibration; - // The actual effect to be played. - public VibrationEffect effect; - // The original effect that was requested. Typically these two things differ because - // the effect was scaled based on the users vibration intensity settings. - public VibrationEffect originalEffect; - // The scale applied to the original effect. - public float scale; - - // Start/end times in unix epoch time. Only to be used for debugging purposes and to - // correlate with other system events, any duration calculations should be done use - // startTime so as not to be affected by discontinuities created by RTC adjustments. - private final long mStartTimeDebug; - private long mEndTimeDebug; - private VibrationInfo.Status mStatus; - - private Vibration(IBinder token, VibrationEffect effect, - VibrationAttributes attrs, int uid, String opPkg, String reason) { - this.token = token; - this.effect = effect; - this.id = mNextVibrationId.getAndIncrement(); - this.startTime = SystemClock.elapsedRealtime(); - this.attrs = attrs; - this.uid = uid; - this.opPkg = opPkg; - this.reason = reason; - mStartTimeDebug = System.currentTimeMillis(); - mStatus = VibrationInfo.Status.RUNNING; + private VibrationDeathRecipient(Vibration vibration) { + mVibration = vibration; } @Override public void binderDied() { synchronized (mLock) { - if (this == mCurrentVibration) { + if (mVibration == mCurrentVibration) { if (DEBUG) { Slog.d(TAG, "Vibration finished because binder died, cleaning up"); } - doCancelVibrateLocked(VibrationInfo.Status.CANCELLED); + doCancelVibrateLocked(Vibration.Status.CANCELLED); } } } - public void end(VibrationInfo.Status status) { - if (hasEnded()) { - // Vibration already ended, keep first ending status set and ignore this one. - return; - } - mStatus = status; - mEndTimeDebug = System.currentTimeMillis(); + private void linkToDeath() throws RemoteException { + mVibration.token.linkToDeath(this, 0); } - public boolean hasEnded() { - return mStatus != VibrationInfo.Status.RUNNING; - } - - public boolean hasTimeoutLongerThan(long millis) { - final long duration = effect.getDuration(); - return duration >= 0 && duration > millis; - } - - public boolean isHapticFeedback() { - return VibratorService.this.isHapticFeedback(attrs.getUsage()); - } - - public boolean isNotification() { - return VibratorService.this.isNotification(attrs.getUsage()); - } - - public boolean isRingtone() { - return VibratorService.this.isRingtone(attrs.getUsage()); - } - - public boolean isAlarm() { - return VibratorService.this.isAlarm(attrs.getUsage()); - } - - public boolean isFromSystem() { - return uid == Process.SYSTEM_UID || uid == 0 || mSystemUiPackage.equals(opPkg); - } - - public VibrationInfo toInfo() { - return new VibrationInfo( - mStartTimeDebug, mEndTimeDebug, effect, originalEffect, scale, attrs, - uid, opPkg, reason, mStatus); + private void unlinkToDeath() { + mVibration.token.unlinkToDeath(this, 0); } } @@ -273,17 +202,17 @@ public class VibratorService extends IVibratorService.Stub { private final long mStartTimeDebug; private long mEndTimeDebug; - private VibrationInfo.Status mStatus; + private Vibration.Status mStatus; private ExternalVibrationHolder(ExternalVibration externalVibration) { this.externalVibration = externalVibration; this.scale = IExternalVibratorService.SCALE_NONE; mStartTimeDebug = System.currentTimeMillis(); - mStatus = VibrationInfo.Status.RUNNING; + mStatus = Vibration.Status.RUNNING; } - public void end(VibrationInfo.Status status) { - if (mStatus != VibrationInfo.Status.RUNNING) { + public void end(Vibration.Status status) { + if (mStatus != Vibration.Status.RUNNING) { // Vibration already ended, keep first ending status set and ignore this one. return; } @@ -291,8 +220,8 @@ public class VibratorService extends IVibratorService.Stub { mEndTimeDebug = System.currentTimeMillis(); } - public VibrationInfo toInfo() { - return new VibrationInfo( + public Vibration.DebugInfo getDebugInfo() { + return new Vibration.DebugInfo( mStartTimeDebug, mEndTimeDebug, /* effect= */ null, /* originalEffect= */ null, scale, externalVibration.getVibrationAttributes(), externalVibration.getUid(), externalVibration.getPackage(), @@ -300,159 +229,6 @@ public class VibratorService extends IVibratorService.Stub { } } - /** Debug information about vibrations. */ - private static class VibrationInfo { - - public enum Status { - RUNNING, - FINISHED, - FORWARDED_TO_INPUT_DEVICES, - CANCELLED, - ERROR_APP_OPS, - IGNORED, - IGNORED_APP_OPS, - IGNORED_BACKGROUND, - IGNORED_RINGTONE, - IGNORED_UNKNOWN_VIBRATION, - IGNORED_UNSUPPORTED, - IGNORED_FOR_ALARM, - IGNORED_FOR_EXTERNAL, - IGNORED_FOR_ONGOING, - IGNORED_FOR_POWER, - IGNORED_FOR_SETTINGS, - } - - private final long mStartTimeDebug; - private final long mEndTimeDebug; - private final VibrationEffect mEffect; - private final VibrationEffect mOriginalEffect; - private final float mScale; - private final VibrationAttributes mAttrs; - private final int mUid; - private final String mOpPkg; - private final String mReason; - private final VibrationInfo.Status mStatus; - - VibrationInfo(long startTimeDebug, long endTimeDebug, VibrationEffect effect, - VibrationEffect originalEffect, float scale, VibrationAttributes attrs, - int uid, String opPkg, String reason, VibrationInfo.Status status) { - mStartTimeDebug = startTimeDebug; - mEndTimeDebug = endTimeDebug; - mEffect = effect; - mOriginalEffect = originalEffect; - mScale = scale; - mAttrs = attrs; - mUid = uid; - mOpPkg = opPkg; - mReason = reason; - mStatus = status; - } - - @Override - public String toString() { - return new StringBuilder() - .append("startTime: ") - .append(DEBUG_DATE_FORMAT.format(new Date(mStartTimeDebug))) - .append(", endTime: ") - .append(mEndTimeDebug == 0 ? null - : DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug))) - .append(", status: ") - .append(mStatus.name().toLowerCase()) - .append(", effect: ") - .append(mEffect) - .append(", originalEffect: ") - .append(mOriginalEffect) - .append(", scale: ") - .append(String.format("%.2f", mScale)) - .append(", attrs: ") - .append(mAttrs) - .append(", uid: ") - .append(mUid) - .append(", opPkg: ") - .append(mOpPkg) - .append(", reason: ") - .append(mReason) - .toString(); - } - - void dumpProto(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); - proto.write(VibrationProto.START_TIME, mStartTimeDebug); - proto.write(VibrationProto.END_TIME, mEndTimeDebug); - 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()); - proto.end(attrsToken); - - if (mEffect != null) { - dumpEffect(proto, VibrationProto.EFFECT, mEffect); - } - if (mOriginalEffect != null) { - dumpEffect(proto, VibrationProto.ORIGINAL_EFFECT, mOriginalEffect); - } - - proto.end(token); - } - - private void dumpEffect(ProtoOutputStream proto, long fieldId, VibrationEffect effect) { - final long token = proto.start(fieldId); - if (effect instanceof VibrationEffect.OneShot) { - dumpEffect(proto, VibrationEffectProto.ONESHOT, (VibrationEffect.OneShot) effect); - } else if (effect instanceof VibrationEffect.Waveform) { - dumpEffect(proto, VibrationEffectProto.WAVEFORM, (VibrationEffect.Waveform) effect); - } else if (effect instanceof VibrationEffect.Prebaked) { - dumpEffect(proto, VibrationEffectProto.PREBAKED, (VibrationEffect.Prebaked) effect); - } else if (effect instanceof VibrationEffect.Composed) { - dumpEffect(proto, VibrationEffectProto.COMPOSED, (VibrationEffect.Composed) effect); - } - proto.end(token); - } - - private void dumpEffect(ProtoOutputStream proto, long fieldId, - VibrationEffect.OneShot effect) { - final long token = proto.start(fieldId); - proto.write(OneShotProto.DURATION, (int) effect.getDuration()); - proto.write(OneShotProto.AMPLITUDE, effect.getAmplitude()); - proto.end(token); - } - - private void dumpEffect(ProtoOutputStream proto, long fieldId, - VibrationEffect.Waveform effect) { - final long token = proto.start(fieldId); - for (long timing : effect.getTimings()) { - proto.write(WaveformProto.TIMINGS, (int) timing); - } - for (int amplitude : effect.getAmplitudes()) { - proto.write(WaveformProto.AMPLITUDES, amplitude); - } - proto.write(WaveformProto.REPEAT, effect.getRepeatIndex() >= 0); - proto.end(token); - } - - private void dumpEffect(ProtoOutputStream proto, long fieldId, - VibrationEffect.Prebaked effect) { - final long token = proto.start(fieldId); - proto.write(PrebakedProto.EFFECT_ID, effect.getId()); - proto.write(PrebakedProto.EFFECT_STRENGTH, effect.getEffectStrength()); - proto.write(PrebakedProto.FALLBACK, effect.shouldFallback()); - proto.end(token); - } - - private void dumpEffect(ProtoOutputStream proto, long fieldId, - VibrationEffect.Composed effect) { - final long token = proto.start(fieldId); - for (PrimitiveEffect primitive : effect.getPrimitiveEffects()) { - proto.write(ComposedProto.EFFECT_IDS, primitive.id); - proto.write(ComposedProto.EFFECT_SCALES, primitive.scale); - proto.write(ComposedProto.DELAYS, primitive.delay); - } - proto.end(token); - } - } - VibratorService(Context context) { this(context, new Injector()); } @@ -546,7 +322,7 @@ public class VibratorService extends IVibratorService.Stub { if (DEBUG) { Slog.d(TAG, "Vibration finished by callback, cleaning up"); } - doCancelVibrateLocked(VibrationInfo.Status.FINISHED); + doCancelVibrateLocked(Vibration.Status.FINISHED); } } } @@ -639,7 +415,8 @@ public class VibratorService extends IVibratorService.Stub { } attrs = fixupVibrationAttributes(attrs); synchronized (mLock) { - Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null); + Vibration vib = new Vibration(null, mNextVibrationId.getAndIncrement(), effect, + attrs, uid, opPkg, null); mAlwaysOnEffects.put(alwaysOnId, vib); updateAlwaysOnLocked(alwaysOnId, vib); } @@ -717,24 +494,26 @@ public class VibratorService extends IVibratorService.Stub { } attrs = fixupVibrationAttributes(attrs); - Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason); + Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs, + uid, opPkg, reason); // If our current vibration is longer than the new vibration and is the same amplitude, // then just let the current one finish. synchronized (mLock) { + VibrationEffect currentEffect = + mCurrentVibration == null ? null : mCurrentVibration.getEffect(); if (effect instanceof VibrationEffect.OneShot - && mCurrentVibration != null - && mCurrentVibration.effect instanceof VibrationEffect.OneShot) { + && currentEffect instanceof VibrationEffect.OneShot) { VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect; VibrationEffect.OneShot currentOneShot = - (VibrationEffect.OneShot) mCurrentVibration.effect; - if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration()) + (VibrationEffect.OneShot) currentEffect; + if (currentOneShot.getDuration() > newOneShot.getDuration() && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) { if (DEBUG) { Slog.d(TAG, "Ignoring incoming vibration in favor of current vibration"); } - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_ONGOING); + endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_ONGOING); return; } } @@ -746,7 +525,7 @@ public class VibratorService extends IVibratorService.Stub { if (DEBUG) { Slog.d(TAG, "Ignoring incoming vibration for current external vibration"); } - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_EXTERNAL); + endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_EXTERNAL); return; } @@ -756,32 +535,32 @@ public class VibratorService extends IVibratorService.Stub { // alarms, in favor of one-shot vibrations that are likely quite short. if (!isRepeatingVibration(effect) && mCurrentVibration != null - && isRepeatingVibration(mCurrentVibration.effect)) { + && isRepeatingVibration(currentEffect)) { if (DEBUG) { Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration"); } - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_ALARM); + endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_ALARM); return; } if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND - && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) { + && !isNotification(vib) && !isRingtone(vib) && !isAlarm(vib)) { Slog.e(TAG, "Ignoring incoming vibration as process with" + " uid= " + uid + " is background," + " attrs= " + vib.attrs); - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_BACKGROUND); + endVibrationLocked(vib, Vibration.Status.IGNORED_BACKGROUND); return; } - linkVibration(vib); + linkVibrationLocked(vib); final long ident = Binder.clearCallingIdentity(); try { - doCancelVibrateLocked(VibrationInfo.Status.CANCELLED); + doCancelVibrateLocked(Vibration.Status.CANCELLED); startVibrationLocked(vib); if (!vib.hasEnded() && mCurrentVibration.id != vib.id) { // Vibration was unexpectedly ignored: add to list for debugging - endVibrationLocked(vib, VibrationInfo.Status.IGNORED); + endVibrationLocked(vib, Vibration.Status.IGNORED); } } finally { Binder.restoreCallingIdentity(ident); @@ -801,13 +580,13 @@ public class VibratorService extends IVibratorService.Stub { return effect.getDuration() == Long.MAX_VALUE; } - private void endVibrationLocked(Vibration vib, VibrationInfo.Status status) { - final LinkedList previousVibrations; - if (vib.isRingtone()) { + private void endVibrationLocked(Vibration vib, Vibration.Status status) { + final LinkedList previousVibrations; + if (isRingtone(vib)) { previousVibrations = mPreviousRingVibrations; - } else if (vib.isNotification()) { + } else if (isNotification(vib)) { previousVibrations = mPreviousNotificationVibrations; - } else if (vib.isAlarm()) { + } else if (isAlarm(vib)) { previousVibrations = mPreviousAlarmVibrations; } else { previousVibrations = mPreviousVibrations; @@ -817,15 +596,15 @@ public class VibratorService extends IVibratorService.Stub { previousVibrations.removeFirst(); } vib.end(status); - previousVibrations.addLast(vib.toInfo()); + previousVibrations.addLast(vib.getDebugInfo()); } - private void endVibrationLocked(ExternalVibrationHolder vib, VibrationInfo.Status status) { + private void endVibrationLocked(ExternalVibrationHolder vib, Vibration.Status status) { if (mPreviousExternalVibrations.size() > mPreviousVibrationsLimit) { mPreviousExternalVibrations.removeFirst(); } vib.end(status); - mPreviousExternalVibrations.addLast(vib.toInfo()); + mPreviousExternalVibrations.addLast(vib.getDebugInfo()); } @Override // Binder call @@ -841,7 +620,7 @@ public class VibratorService extends IVibratorService.Stub { } final long ident = Binder.clearCallingIdentity(); try { - doCancelVibrateLocked(VibrationInfo.Status.CANCELLED); + doCancelVibrateLocked(Vibration.Status.CANCELLED); } finally { Binder.restoreCallingIdentity(ident); } @@ -850,7 +629,7 @@ public class VibratorService extends IVibratorService.Stub { } @GuardedBy("mLock") - private void doCancelVibrateLocked(VibrationInfo.Status status) { + private void doCancelVibrateLocked(Vibration.Status status) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked"); try { @@ -879,7 +658,7 @@ public class VibratorService extends IVibratorService.Stub { synchronized (mLock) { // Make sure the vibration is really done. This also reports that the vibration is // finished. - doCancelVibrateLocked(VibrationInfo.Status.FINISHED); + doCancelVibrateLocked(Vibration.Status.FINISHED); } } @@ -903,21 +682,22 @@ public class VibratorService extends IVibratorService.Stub { try { // Set current vibration before starting it, so callback will work. mCurrentVibration = vib; - if (vib.effect instanceof VibrationEffect.OneShot) { + VibrationEffect effect = vib.getEffect(); + if (effect instanceof VibrationEffect.OneShot) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); doVibratorOn(vib); - } else if (vib.effect instanceof VibrationEffect.Waveform) { + } else if (effect instanceof VibrationEffect.Waveform) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); doVibratorWaveformEffectLocked(vib); - } else if (vib.effect instanceof VibrationEffect.Prebaked) { + } else if (effect instanceof VibrationEffect.Prebaked) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); doVibratorPrebakedEffectLocked(vib); - } else if (vib.effect instanceof VibrationEffect.Composed) { + } else if (effect instanceof VibrationEffect.Composed) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); doVibratorComposedEffectLocked(vib); } else { Slog.e(TAG, "Unknown vibration type, ignoring"); - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNKNOWN_VIBRATION); + endVibrationLocked(vib, Vibration.Status.IGNORED_UNKNOWN_VIBRATION); // The set current vibration is not actually playing, so drop it. mCurrentVibration = null; } @@ -939,11 +719,7 @@ public class VibratorService extends IVibratorService.Stub { /** Scale the vibration effect by the intensity as appropriate based its intent. */ private void applyVibrationIntensityScalingLocked(Vibration vib) { - VibrationEffect scaled = mVibrationScaler.scale(vib.effect, vib.attrs.getUsage()); - if (!scaled.equals(vib.effect)) { - vib.originalEffect = vib.effect; - vib.effect = scaled; - } + vib.updateEffect(mVibrationScaler.scale(vib.getEffect(), vib.attrs.getUsage())); } private static boolean shouldBypassDnd(VibrationAttributes attrs) { @@ -969,21 +745,21 @@ public class VibratorService extends IVibratorService.Stub { private boolean shouldVibrate(Vibration vib) { if (!shouldVibrateForPowerModeLocked(vib)) { - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_POWER); + endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_POWER); return false; } int intensity = mVibrationSettings.getCurrentIntensity(vib.attrs.getUsage()); if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_SETTINGS); + endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_SETTINGS); return false; } - if (vib.isRingtone() && !mVibrationSettings.shouldVibrateForRingtone()) { + if (isRingtone(vib) && !mVibrationSettings.shouldVibrateForRingtone()) { if (DEBUG) { Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); } - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_RINGTONE); + endVibrationLocked(vib, Vibration.Status.IGNORED_RINGTONE); return false; } @@ -993,9 +769,9 @@ public class VibratorService extends IVibratorService.Stub { // We might be getting calls from within system_server, so we don't actually // want to throw a SecurityException here. Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); - endVibrationLocked(vib, VibrationInfo.Status.ERROR_APP_OPS); + endVibrationLocked(vib, Vibration.Status.ERROR_APP_OPS); } else { - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_APP_OPS); + endVibrationLocked(vib, Vibration.Status.IGNORED_APP_OPS); } return false; } @@ -1004,14 +780,14 @@ public class VibratorService extends IVibratorService.Stub { } @GuardedBy("mLock") - private void reportFinishVibrationLocked(VibrationInfo.Status status) { + private void reportFinishVibrationLocked(Vibration.Status status) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked"); try { if (mCurrentVibration != null) { endVibrationLocked(mCurrentVibration, status); mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid, mCurrentVibration.opPkg); - unlinkVibration(mCurrentVibration); + unlinkVibrationLocked(); mCurrentVibration = null; } } finally { @@ -1019,21 +795,27 @@ public class VibratorService extends IVibratorService.Stub { } } - private void linkVibration(Vibration vib) { + @GuardedBy("mLock") + private void linkVibrationLocked(Vibration vib) { + // Unlink previously linked vibration, if any. + unlinkVibrationLocked(); // Only link against waveforms since they potentially don't have a finish if // they're repeating. Let other effects just play out until they're done. - if (vib.effect instanceof VibrationEffect.Waveform) { + if (vib.getEffect() instanceof VibrationEffect.Waveform) { try { - vib.token.linkToDeath(vib, 0); + mCurrentVibrationDeathRecipient = new VibrationDeathRecipient(vib); + mCurrentVibrationDeathRecipient.linkToDeath(); } catch (RemoteException e) { return; } } } - private void unlinkVibration(Vibration vib) { - if (vib.effect instanceof VibrationEffect.Waveform) { - vib.token.unlinkToDeath(vib, 0); + @GuardedBy("mLock") + private void unlinkVibrationLocked() { + if (mCurrentVibrationDeathRecipient != null) { + mCurrentVibrationDeathRecipient.unlinkToDeath(); + mCurrentVibrationDeathRecipient = null; } } @@ -1045,7 +827,7 @@ public class VibratorService extends IVibratorService.Stub { if (devicesUpdated || lowPowerModeUpdated) { // If the state changes out from under us then just reset. - doCancelVibrateLocked(VibrationInfo.Status.CANCELLED); + doCancelVibrateLocked(Vibration.Status.CANCELLED); } updateAlwaysOnLocked(); @@ -1067,7 +849,7 @@ public class VibratorService extends IVibratorService.Stub { if (!shouldVibrate(vib)) { effect = null; } else { - effect = mVibrationScaler.scale(vib.effect, vib.attrs.getUsage()); + effect = mVibrationScaler.scale(vib.getEffect(), vib.attrs.getUsage()); } mVibratorController.updateAlwaysOn(id, effect); } @@ -1083,7 +865,7 @@ public class VibratorService extends IVibratorService.Stub { private void doVibratorOn(Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn"); try { - final VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect; + final VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.getEffect(); if (DEBUG) { Slog.d(TAG, "Turning vibrator on for " + oneShot.getDuration() + " ms" + " with amplitude " + oneShot.getAmplitude() + "."); @@ -1093,7 +875,7 @@ public class VibratorService extends IVibratorService.Stub { if (inputDevicesAvailable) { // The set current vibration is no longer being played by this service, so drop it. mCurrentVibration = null; - endVibrationLocked(vib, VibrationInfo.Status.FORWARDED_TO_INPUT_DEVICES); + endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES); } else { noteVibratorOnLocked(vib.uid, oneShot.getDuration()); // Note: ordering is important here! Many haptic drivers will reset their @@ -1128,11 +910,11 @@ public class VibratorService extends IVibratorService.Stub { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorWaveformEffectLocked"); try { boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable( - vib.uid, vib.opPkg, vib.effect, vib.reason, vib.attrs); + vib.uid, vib.opPkg, vib.getEffect(), vib.reason, vib.attrs); if (inputDevicesAvailable) { // The set current vibration is no longer being played by this service, so drop it. mCurrentVibration = null; - endVibrationLocked(vib, VibrationInfo.Status.FORWARDED_TO_INPUT_DEVICES); + endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES); } else { // mThread better be null here. doCancelVibrate should always be // called before startNextVibrationLocked or startVibrationLocked. @@ -1148,7 +930,7 @@ public class VibratorService extends IVibratorService.Stub { private void doVibratorPrebakedEffectLocked(Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked"); try { - final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; + final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.getEffect(); // Input devices don't support prebaked effect, so skip trying it with them and allow // fallback to be attempted. if (!mInputDeviceDelegate.isAvailable()) { @@ -1158,7 +940,7 @@ public class VibratorService extends IVibratorService.Stub { return; } } - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNSUPPORTED); + endVibrationLocked(vib, Vibration.Status.IGNORED_UNSUPPORTED); // The set current vibration is not actually playing, so drop it. mCurrentVibration = null; @@ -1170,11 +952,11 @@ public class VibratorService extends IVibratorService.Stub { Slog.w(TAG, "Failed to play prebaked effect, no fallback"); return; } - Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid, - vib.opPkg, vib.reason + " (fallback)"); + Vibration fallbackVib = new Vibration(vib.token, mNextVibrationId.getAndIncrement(), + effect, vib.attrs, vib.uid, vib.opPkg, vib.reason + " (fallback)"); // Set current vibration before starting it, so callback will work. mCurrentVibration = fallbackVib; - linkVibration(fallbackVib); + linkVibrationLocked(fallbackVib); applyVibrationIntensityScalingLocked(fallbackVib); startVibrationInnerLocked(fallbackVib); } finally { @@ -1187,18 +969,18 @@ public class VibratorService extends IVibratorService.Stub { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorComposedEffectLocked"); try { - final VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.effect; + final VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.getEffect(); boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable( vib.uid, vib.opPkg, composed, vib.reason, vib.attrs); if (inputDevicesAvailable) { // The set current vibration is no longer being played by this service, so drop it. mCurrentVibration = null; - endVibrationLocked(vib, VibrationInfo.Status.FORWARDED_TO_INPUT_DEVICES); + endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES); return; } else if (!mVibratorController.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) { // The set current vibration is not actually playing, so drop it. mCurrentVibration = null; - endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNSUPPORTED); + endVibrationLocked(vib, Vibration.Status.IGNORED_UNSUPPORTED); return; } @@ -1212,20 +994,24 @@ public class VibratorService extends IVibratorService.Stub { } - private static boolean isNotification(int usageHint) { - return usageHint == VibrationAttributes.USAGE_NOTIFICATION; + private static boolean isNotification(Vibration vib) { + return vib.attrs.getUsage() == VibrationAttributes.USAGE_NOTIFICATION; } - private static boolean isRingtone(int usageHint) { - return usageHint == VibrationAttributes.USAGE_RINGTONE; + private static boolean isRingtone(Vibration vib) { + return vib.attrs.getUsage() == VibrationAttributes.USAGE_RINGTONE; } - private static boolean isHapticFeedback(int usageHint) { - return usageHint == VibrationAttributes.USAGE_TOUCH; + private static boolean isHapticFeedback(Vibration vib) { + return vib.attrs.getUsage() == VibrationAttributes.USAGE_TOUCH; } - private static boolean isAlarm(int usageHint) { - return usageHint == VibrationAttributes.USAGE_ALARM; + private static boolean isAlarm(Vibration vib) { + return vib.attrs.getUsage() == VibrationAttributes.USAGE_ALARM; + } + + private boolean isFromSystem(Vibration vib) { + return vib.uid == Process.SYSTEM_UID || vib.uid == 0 || mSystemUiPackage.equals(vib.opPkg); } private void noteVibratorOnLocked(int uid, long millis) { @@ -1254,13 +1040,13 @@ public class VibratorService extends IVibratorService.Stub { synchronized (mLock) { pw.print(" mCurrentVibration="); if (mCurrentVibration != null) { - pw.println(mCurrentVibration.toInfo().toString()); + pw.println(mCurrentVibration.getDebugInfo().toString()); } else { pw.println("null"); } pw.print(" mCurrentExternalVibration="); if (mCurrentExternalVibration != null) { - pw.println(mCurrentExternalVibration.toInfo().toString()); + pw.println(mCurrentExternalVibration.getDebugInfo().toString()); } else { pw.println("null"); } @@ -1269,28 +1055,28 @@ public class VibratorService extends IVibratorService.Stub { pw.println(" mVibrationSettings=" + mVibrationSettings); pw.println(); pw.println(" Previous ring vibrations:"); - for (VibrationInfo info : mPreviousRingVibrations) { + for (Vibration.DebugInfo info : mPreviousRingVibrations) { pw.print(" "); pw.println(info.toString()); } pw.println(" Previous notification vibrations:"); - for (VibrationInfo info : mPreviousNotificationVibrations) { + for (Vibration.DebugInfo info : mPreviousNotificationVibrations) { pw.println(" " + info); } pw.println(" Previous alarm vibrations:"); - for (VibrationInfo info : mPreviousAlarmVibrations) { + for (Vibration.DebugInfo info : mPreviousAlarmVibrations) { pw.println(" " + info); } pw.println(" Previous vibrations:"); - for (VibrationInfo info : mPreviousVibrations) { + for (Vibration.DebugInfo info : mPreviousVibrations) { pw.println(" " + info); } pw.println(" Previous external vibrations:"); - for (VibrationInfo info : mPreviousExternalVibrations) { + for (Vibration.DebugInfo info : mPreviousExternalVibrations) { pw.println(" " + info); } } @@ -1301,11 +1087,11 @@ public class VibratorService extends IVibratorService.Stub { synchronized (mLock) { if (mCurrentVibration != null) { - mCurrentVibration.toInfo().dumpProto(proto, + mCurrentVibration.getDebugInfo().dumpProto(proto, VibratorServiceDumpProto.CURRENT_VIBRATION); } if (mCurrentExternalVibration != null) { - mCurrentExternalVibration.toInfo().dumpProto(proto, + mCurrentExternalVibration.getDebugInfo().dumpProto(proto, VibratorServiceDumpProto.CURRENT_EXTERNAL_VIBRATION); } proto.write(VibratorServiceDumpProto.IS_VIBRATING, mVibratorController.isVibrating()); @@ -1325,23 +1111,23 @@ public class VibratorService extends IVibratorService.Stub { proto.write(VibratorServiceDumpProto.RING_DEFAULT_INTENSITY, mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE)); - for (VibrationInfo info : mPreviousRingVibrations) { + for (Vibration.DebugInfo info : mPreviousRingVibrations) { info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_RING_VIBRATIONS); } - for (VibrationInfo info : mPreviousNotificationVibrations) { + for (Vibration.DebugInfo info : mPreviousNotificationVibrations) { info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS); } - for (VibrationInfo info : mPreviousAlarmVibrations) { + for (Vibration.DebugInfo info : mPreviousAlarmVibrations) { info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS); } - for (VibrationInfo info : mPreviousVibrations) { + for (Vibration.DebugInfo info : mPreviousVibrations) { info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_VIBRATIONS); } - for (VibrationInfo info : mPreviousExternalVibrations) { + for (Vibration.DebugInfo info : mPreviousExternalVibrations) { info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS); } } @@ -1356,9 +1142,9 @@ public class VibratorService extends IVibratorService.Stub { private boolean mForceStop; VibrateWaveformThread(Vibration vib) { - mWaveform = (VibrationEffect.Waveform) vib.effect; - mVibration = new Vibration(vib.token, /* effect= */ null, vib.attrs, vib.uid, - vib.opPkg, vib.reason); + mWaveform = (VibrationEffect.Waveform) vib.getEffect(); + mVibration = new Vibration(vib.token, /* id= */ 0, /* effect= */ null, vib.attrs, + vib.uid, vib.opPkg, vib.reason); mTmpWorkSource.set(vib.uid); mWakeLock.setWorkSource(mTmpWorkSource); } @@ -1430,8 +1216,8 @@ public class VibratorService extends IVibratorService.Stub { // appropriate intervals. long onDuration = getTotalOnDuration( timings, amplitudes, index - 1, repeat); - mVibration.effect = VibrationEffect.createOneShot( - onDuration, amplitude); + mVibration.updateEffect( + VibrationEffect.createOneShot(onDuration, amplitude)); doVibratorOn(mVibration); nextVibratorStopTime = now + onDuration; } else { @@ -1526,9 +1312,9 @@ public class VibratorService extends IVibratorService.Stub { // haptic feedback as part of the transition. So we don't cancel // system vibrations. if (mCurrentVibration != null - && !(mCurrentVibration.isHapticFeedback() - && mCurrentVibration.isFromSystem())) { - doCancelVibrateLocked(VibrationInfo.Status.CANCELLED); + && !(isHapticFeedback(mCurrentVibration) + && isFromSystem(mCurrentVibration))) { + doCancelVibrateLocked(Vibration.Status.CANCELLED); } } } @@ -1587,9 +1373,9 @@ public class VibratorService extends IVibratorService.Stub { vibHolder.scale = SCALE_MUTE; if (mode == AppOpsManager.MODE_ERRORED) { Slog.w(TAG, "Would be an error: external vibrate from uid " + vib.getUid()); - endVibrationLocked(vibHolder, VibrationInfo.Status.ERROR_APP_OPS); + endVibrationLocked(vibHolder, Vibration.Status.ERROR_APP_OPS); } else { - endVibrationLocked(vibHolder, VibrationInfo.Status.IGNORED_APP_OPS); + endVibrationLocked(vibHolder, Vibration.Status.IGNORED_APP_OPS); } return IExternalVibratorService.SCALE_MUTE; } @@ -1607,10 +1393,10 @@ public class VibratorService extends IVibratorService.Stub { if (DEBUG) { Slog.d(TAG, "Vibrator going under external control."); } - doCancelVibrateLocked(VibrationInfo.Status.CANCELLED); + doCancelVibrateLocked(Vibration.Status.CANCELLED); mVibratorController.setExternalControl(true); } else { - endVibrationLocked(mCurrentExternalVibration, VibrationInfo.Status.CANCELLED); + endVibrationLocked(mCurrentExternalVibration, Vibration.Status.CANCELLED); } // At this point we either have an externally controlled vibration playing, or // no vibration playing. Since the interface defines that only one externally @@ -1640,12 +1426,12 @@ public class VibratorService extends IVibratorService.Stub { if (DEBUG) { Slog.e(TAG, "Stopping external vibration" + vib); } - doCancelExternalVibrateLocked(VibrationInfo.Status.FINISHED); + doCancelExternalVibrateLocked(Vibration.Status.FINISHED); } } } - private void doCancelExternalVibrateLocked(VibrationInfo.Status status) { + private void doCancelExternalVibrateLocked(Vibration.Status status) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelExternalVibrateLocked"); try { if (mCurrentExternalVibration == null) { @@ -1669,7 +1455,7 @@ public class VibratorService extends IVibratorService.Stub { if (DEBUG) { Slog.d(TAG, "External vibration finished because binder died"); } - doCancelExternalVibrateLocked(VibrationInfo.Status.CANCELLED); + doCancelExternalVibrateLocked(Vibration.Status.CANCELLED); } } } diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java new file mode 100644 index 0000000000000..e2cdd02deab91 --- /dev/null +++ b/services/core/java/com/android/server/vibrator/Vibration.java @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.vibrator; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.IBinder; +import android.os.SystemClock; +import android.os.VibrationAttributes; +import android.os.VibrationEffect; +import android.util.proto.ProtoOutputStream; + +import com.android.server.ComposedProto; +import com.android.server.OneShotProto; +import com.android.server.PrebakedProto; +import com.android.server.VibrationAttributesProto; +import com.android.server.VibrationEffectProto; +import com.android.server.VibrationProto; +import com.android.server.WaveformProto; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** Represents a vibration request to the vibrator service. */ +// TODO(b/159207608): Make this package-private once vibrator services are moved to this package +public class Vibration { + private static final String TAG = "Vibration"; + private static final SimpleDateFormat DEBUG_DATE_FORMAT = + new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); + + public enum Status { + RUNNING, + FINISHED, + FORWARDED_TO_INPUT_DEVICES, + CANCELLED, + ERROR_APP_OPS, + IGNORED, + IGNORED_APP_OPS, + IGNORED_BACKGROUND, + IGNORED_RINGTONE, + IGNORED_UNKNOWN_VIBRATION, + IGNORED_UNSUPPORTED, + IGNORED_FOR_ALARM, + IGNORED_FOR_EXTERNAL, + IGNORED_FOR_ONGOING, + IGNORED_FOR_POWER, + IGNORED_FOR_SETTINGS, + } + + /** Start time in CLOCK_BOOTTIME base. */ + public final long startTime; + public final VibrationAttributes attrs; + public final long id; + public final int uid; + public final String opPkg; + public final String reason; + public final IBinder token; + + /** The actual effect to be played. */ + @Nullable + private VibrationEffect mEffect; + + /** + * The original effect that was requested. Typically these two things differ because the effect + * was scaled based on the users vibration intensity settings. + */ + @Nullable + private VibrationEffect mOriginalEffect; + + /** + * Start/end times in unix epoch time. Only to be used for debugging purposes and to correlate + * with other system events, any duration calculations should be done use {@link #startTime} so + * as not to be affected by discontinuities created by RTC adjustments. + */ + private final long mStartTimeDebug; + private long mEndTimeDebug; + private Status mStatus; + + public Vibration(IBinder token, int id, VibrationEffect effect, + VibrationAttributes attrs, int uid, String opPkg, String reason) { + this.token = token; + this.mEffect = effect; + this.id = id; + this.startTime = SystemClock.elapsedRealtime(); + this.attrs = attrs; + this.uid = uid; + this.opPkg = opPkg; + this.reason = reason; + mStartTimeDebug = System.currentTimeMillis(); + mStatus = Status.RUNNING; + } + + /** + * Set the {@link Status} of this vibration and the current system time as this + * vibration end time, for debugging purposes. + * + *

This method will only accept given value if the current status is {@link + * Status#RUNNING}. + */ + public void end(Status status) { + if (hasEnded()) { + // Vibration already ended, keep first ending status set and ignore this one. + return; + } + mStatus = status; + mEndTimeDebug = System.currentTimeMillis(); + } + + /** + * Replace this vibration effect if given {@code scaledEffect} is different, preserving the + * original one for debug purposes. + */ + public void updateEffect(@NonNull VibrationEffect newEffect) { + if (newEffect.equals(mEffect)) { + return; + } + mOriginalEffect = mEffect; + mEffect = newEffect; + } + + /** Return true is current status is different from {@link Status#RUNNING}. */ + public boolean hasEnded() { + return mStatus != Status.RUNNING; + } + + /** Return the effect that should be played by this vibration. */ + @Nullable + public VibrationEffect getEffect() { + return mEffect; + } + + /** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */ + public Vibration.DebugInfo getDebugInfo() { + return new Vibration.DebugInfo( + mStartTimeDebug, mEndTimeDebug, mEffect, mOriginalEffect, /* scale= */ 0, attrs, + uid, opPkg, reason, mStatus); + } + + /** Debug information about vibrations. */ + public static final class DebugInfo { + private final long mStartTimeDebug; + private final long mEndTimeDebug; + private final VibrationEffect mEffect; + private final VibrationEffect mOriginalEffect; + private final float mScale; + private final VibrationAttributes mAttrs; + private final int mUid; + private final String mOpPkg; + private final String mReason; + private final Status mStatus; + + public DebugInfo(long startTimeDebug, long endTimeDebug, VibrationEffect effect, + VibrationEffect originalEffect, float scale, VibrationAttributes attrs, + int uid, String opPkg, String reason, Status status) { + mStartTimeDebug = startTimeDebug; + mEndTimeDebug = endTimeDebug; + mEffect = effect; + mOriginalEffect = originalEffect; + mScale = scale; + mAttrs = attrs; + mUid = uid; + mOpPkg = opPkg; + mReason = reason; + mStatus = status; + } + + @Override + public String toString() { + return new StringBuilder() + .append("startTime: ") + .append(DEBUG_DATE_FORMAT.format(new Date(mStartTimeDebug))) + .append(", endTime: ") + .append(mEndTimeDebug == 0 ? null + : DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug))) + .append(", status: ") + .append(mStatus.name().toLowerCase()) + .append(", effect: ") + .append(mEffect) + .append(", originalEffect: ") + .append(mOriginalEffect) + .append(", scale: ") + .append(String.format("%.2f", mScale)) + .append(", attrs: ") + .append(mAttrs) + .append(", uid: ") + .append(mUid) + .append(", opPkg: ") + .append(mOpPkg) + .append(", reason: ") + .append(mReason) + .toString(); + } + + /** Write this info into given {@code fieldId} on {@link ProtoOutputStream}. */ + public void dumpProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(VibrationProto.START_TIME, mStartTimeDebug); + proto.write(VibrationProto.END_TIME, mEndTimeDebug); + 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()); + proto.end(attrsToken); + + if (mEffect != null) { + dumpEffect(proto, VibrationProto.EFFECT, mEffect); + } + if (mOriginalEffect != null) { + dumpEffect(proto, VibrationProto.ORIGINAL_EFFECT, mOriginalEffect); + } + + proto.end(token); + } + + private void dumpEffect(ProtoOutputStream proto, long fieldId, VibrationEffect effect) { + final long token = proto.start(fieldId); + if (effect instanceof VibrationEffect.OneShot) { + dumpEffect(proto, VibrationEffectProto.ONESHOT, (VibrationEffect.OneShot) effect); + } else if (effect instanceof VibrationEffect.Waveform) { + dumpEffect(proto, VibrationEffectProto.WAVEFORM, (VibrationEffect.Waveform) effect); + } else if (effect instanceof VibrationEffect.Prebaked) { + dumpEffect(proto, VibrationEffectProto.PREBAKED, (VibrationEffect.Prebaked) effect); + } else if (effect instanceof VibrationEffect.Composed) { + dumpEffect(proto, VibrationEffectProto.COMPOSED, (VibrationEffect.Composed) effect); + } + proto.end(token); + } + + private void dumpEffect(ProtoOutputStream proto, long fieldId, + VibrationEffect.OneShot effect) { + final long token = proto.start(fieldId); + proto.write(OneShotProto.DURATION, (int) effect.getDuration()); + proto.write(OneShotProto.AMPLITUDE, effect.getAmplitude()); + proto.end(token); + } + + private void dumpEffect(ProtoOutputStream proto, long fieldId, + VibrationEffect.Waveform effect) { + final long token = proto.start(fieldId); + for (long timing : effect.getTimings()) { + proto.write(WaveformProto.TIMINGS, (int) timing); + } + for (int amplitude : effect.getAmplitudes()) { + proto.write(WaveformProto.AMPLITUDES, amplitude); + } + proto.write(WaveformProto.REPEAT, effect.getRepeatIndex() >= 0); + proto.end(token); + } + + private void dumpEffect(ProtoOutputStream proto, long fieldId, + VibrationEffect.Prebaked effect) { + final long token = proto.start(fieldId); + proto.write(PrebakedProto.EFFECT_ID, effect.getId()); + proto.write(PrebakedProto.EFFECT_STRENGTH, effect.getEffectStrength()); + proto.write(PrebakedProto.FALLBACK, effect.shouldFallback()); + proto.end(token); + } + + private void dumpEffect(ProtoOutputStream proto, long fieldId, + VibrationEffect.Composed effect) { + final long token = proto.start(fieldId); + for (VibrationEffect.Composition.PrimitiveEffect primitive : + effect.getPrimitiveEffects()) { + proto.write(ComposedProto.EFFECT_IDS, primitive.id); + proto.write(ComposedProto.EFFECT_SCALES, primitive.scale); + proto.write(ComposedProto.DELAYS, primitive.delay); + } + proto.end(token); + } + } +} diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java index 42a0a706a1c7f..5f7e47d6ca29d 100644 --- a/services/core/java/com/android/server/vibrator/VibrationScaler.java +++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java @@ -31,7 +31,6 @@ public final class VibrationScaler { // Scale levels. Each level, except MUTE, is defined as the delta between the current setting // and the default intensity for that type of vibration (i.e. current - default). - private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100 private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2 private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1 private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0