Loading services/core/java/com/android/server/vibrator/Vibration.java +5 −1 Original line number Diff line number Diff line Loading @@ -208,6 +208,7 @@ abstract class Vibration { * potentially expensive or resource-linked objects, such as {@link IBinder}. */ static final class DebugInfo { final Status mStatus; final long mCreateTime; final CallerInfo mCallerInfo; @Nullable Loading @@ -220,7 +221,6 @@ abstract class Vibration { private final CombinedVibration mOriginalEffect; private final int mScaleLevel; private final float mAdaptiveScale; private final Status mStatus; DebugInfo(Status status, VibrationStats stats, @Nullable CombinedVibration playedEffect, @Nullable CombinedVibration originalEffect, int scaleLevel, Loading Loading @@ -253,6 +253,10 @@ abstract class Vibration { + ", callerInfo: " + mCallerInfo; } void logMetrics(VibratorFrameworkStatsLogger statsLogger) { statsLogger.logVibrationAdaptiveHapticScale(mCallerInfo.uid, mAdaptiveScale); } /** * Write this info in a compact way into given {@link PrintWriter}. * Loading services/core/java/com/android/server/vibrator/VibrationStepConductor.java +18 −4 Original line number Diff line number Diff line Loading @@ -40,8 +40,10 @@ import java.util.LinkedList; import java.util.List; import java.util.PriorityQueue; import java.util.Queue; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * Creates and manages a queue of steps for performing a VibrationEffect, as well as coordinating Loading Loading @@ -70,6 +72,7 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { private final DeviceAdapter mDeviceAdapter; private final VibrationScaler mVibrationScaler; private final VibratorFrameworkStatsLogger mStatsLogger; // Not guarded by lock because it's mostly used to read immutable fields by this conductor. // This is only modified here at the prepareToStart method which always runs at the vibration Loading Loading @@ -103,14 +106,15 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { private int mSuccessfulVibratorOnSteps; VibrationStepConductor(HalVibration vib, VibrationSettings vibrationSettings, DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler, DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler, VibratorFrameworkStatsLogger statsLogger, CompletableFuture<Void> requestVibrationParamsFuture, VibrationThread.VibratorManagerHooks vibratorManagerHooks) { this.mVibration = vib; this.vibrationSettings = vibrationSettings; this.mDeviceAdapter = deviceAdapter; mVibrationScaler = vibrationScaler; mStatsLogger = statsLogger; mRequestVibrationParamsFuture = requestVibrationParamsFuture; this.vibratorManagerHooks = vibratorManagerHooks; this.mSignalVibratorsComplete = Loading Loading @@ -461,9 +465,19 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { } try { mRequestVibrationParamsFuture.orTimeout( mRequestVibrationParamsFuture.get( vibrationSettings.getRequestVibrationParamsTimeoutMs(), TimeUnit.MILLISECONDS).get(); TimeUnit.MILLISECONDS); } catch (TimeoutException e) { if (DEBUG) { Slog.d(TAG, "Request for vibration params timed out", e); } mStatsLogger.logVibrationParamRequestTimeout(mVibration.callerInfo.uid); } catch (CancellationException e) { if (DEBUG) { Slog.d(TAG, "Request for vibration params cancelled, maybe superseded or" + " vibrator controller unregistered. Skipping params...", e); } } catch (Throwable e) { Slog.w(TAG, "Failed to retrieve vibration params.", e); } Loading services/core/java/com/android/server/vibrator/VibratorControlService.java +46 −25 Original line number Diff line number Diff line Loading @@ -72,19 +72,21 @@ final class VibratorControlService extends IVibratorControlService.Stub { private final VibrationParamsRecords mVibrationParamsRecords; private final VibratorControllerHolder mVibratorControllerHolder; private final VibrationScaler mVibrationScaler; private final VibratorFrameworkStatsLogger mStatsLogger; private final Object mLock; private final int[] mRequestVibrationParamsForUsages; @GuardedBy("mLock") private CompletableFuture<Void> mRequestVibrationParamsFuture = null; @GuardedBy("mLock") private IBinder mRequestVibrationParamsToken; @Nullable private VibrationParamRequest mVibrationParamRequest = null; VibratorControlService(Context context, VibratorControllerHolder vibratorControllerHolder, VibrationScaler vibrationScaler, VibrationSettings vibrationSettings, Object lock) { VibrationSettings vibrationSettings, VibratorFrameworkStatsLogger statsLogger, Object lock) { mVibratorControllerHolder = vibratorControllerHolder; mVibrationScaler = vibrationScaler; mStatsLogger = statsLogger; mLock = lock; mRequestVibrationParamsForUsages = vibrationSettings.getRequestVibrationParamsForUsages(); Loading Loading @@ -180,20 +182,25 @@ final class VibratorControlService extends IVibratorControlService.Stub { Objects.requireNonNull(requestToken); synchronized (mLock) { if (mRequestVibrationParamsToken == null) { if (mVibrationParamRequest == null) { Slog.wtf(TAG, "New vibration params received but no token was cached in the service. " + "New vibration params ignored."); mStatsLogger.logVibrationParamResponseIgnored(); return; } if (!Objects.equals(requestToken, mRequestVibrationParamsToken)) { if (!Objects.equals(requestToken, mVibrationParamRequest.token)) { Slog.w(TAG, "New vibration params received but the provided token does not match the " + "cached one. New vibration params ignored."); mStatsLogger.logVibrationParamResponseIgnored(); return; } long latencyMs = SystemClock.uptimeMillis() - mVibrationParamRequest.uptimeMs; mStatsLogger.logVibrationParamRequestLatency(mVibrationParamRequest.uid, latencyMs); updateAdaptiveHapticsScales(result); endOngoingRequestVibrationParamsLocked(/* wasCancelled= */ false); recordUpdateVibrationParams(result, /* fromRequest= */ true); Loading Loading @@ -222,7 +229,7 @@ final class VibratorControlService extends IVibratorControlService.Stub { */ @Nullable public CompletableFuture<Void> triggerVibrationParamsRequest( @VibrationAttributes.Usage int usage, int timeoutInMillis) { int uid, @VibrationAttributes.Usage int usage, int timeoutInMillis) { synchronized (mLock) { IVibratorController vibratorController = mVibratorControllerHolder.getVibratorController(); Loading @@ -241,16 +248,16 @@ final class VibratorControlService extends IVibratorControlService.Stub { try { endOngoingRequestVibrationParamsLocked(/* wasCancelled= */ true); mRequestVibrationParamsFuture = new CompletableFuture<>(); mRequestVibrationParamsToken = new Binder(); mVibrationParamRequest = new VibrationParamRequest(uid); vibratorController.requestVibrationParams(vibrationType, timeoutInMillis, mRequestVibrationParamsToken); mVibrationParamRequest.token); return mVibrationParamRequest.future; } catch (RemoteException e) { Slog.e(TAG, "Failed to request vibration params.", e); endOngoingRequestVibrationParamsLocked(/* wasCancelled= */ true); } return mRequestVibrationParamsFuture; return null; } } Loading @@ -276,13 +283,13 @@ final class VibratorControlService extends IVibratorControlService.Stub { } /** * Returns the {@link #mRequestVibrationParamsToken} which is used to validate * Returns the binder token which is used to validate * {@link #onRequestVibrationParamsComplete(IBinder, VibrationParam[])} calls. */ @VisibleForTesting public IBinder getRequestVibrationParamsToken() { synchronized (mLock) { return mRequestVibrationParamsToken; return mVibrationParamRequest == null ? null : mVibrationParamRequest.token; } } Loading @@ -293,7 +300,7 @@ final class VibratorControlService extends IVibratorControlService.Stub { synchronized (mLock) { isVibratorControllerRegistered = mVibratorControllerHolder.getVibratorController() != null; hasPendingVibrationParamsRequest = mRequestVibrationParamsFuture != null; hasPendingVibrationParamsRequest = mVibrationParamRequest != null; } pw.println("VibratorControlService:"); Loading Loading @@ -329,18 +336,10 @@ final class VibratorControlService extends IVibratorControlService.Stub { */ @GuardedBy("mLock") private void endOngoingRequestVibrationParamsLocked(boolean wasCancelled) { mRequestVibrationParamsToken = null; if (mRequestVibrationParamsFuture == null) { return; if (mVibrationParamRequest != null) { mVibrationParamRequest.endRequest(wasCancelled); } if (wasCancelled) { mRequestVibrationParamsFuture.cancel(/* mayInterruptIfRunning= */ true); } else { mRequestVibrationParamsFuture.complete(null); } mRequestVibrationParamsFuture = null; mVibrationParamRequest = null; } private static int mapToAdaptiveVibrationType(@VibrationAttributes.Usage int usage) { Loading Loading @@ -423,6 +422,7 @@ final class VibratorControlService extends IVibratorControlService.Stub { * @param scale The scaling factor that should be applied to the vibrations. */ private void updateAdaptiveHapticsScales(int types, float scale) { mStatsLogger.logVibrationParamScale(scale); for (int usage : mapFromAdaptiveVibrationTypeToVibrationUsages(types)) { updateOrRemoveAdaptiveHapticsScale(usage, scale); } Loading Loading @@ -504,6 +504,27 @@ final class VibratorControlService extends IVibratorControlService.Stub { } } /** Represents a request for {@link VibrationParam}. */ private static final class VibrationParamRequest { public final CompletableFuture<Void> future = new CompletableFuture<>(); public final IBinder token = new Binder(); public final int uid; public final long uptimeMs; VibrationParamRequest(int uid) { this.uid = uid; uptimeMs = SystemClock.uptimeMillis(); } public void endRequest(boolean wasCancelled) { if (wasCancelled) { future.cancel(/* mayInterruptIfRunning= */ true); } else { future.complete(null); } } } /** * Record for a single {@link Vibration.DebugInfo}, that can be grouped by usage and aggregated * by UID, {@link VibrationAttributes} and {@link VibrationEffect}. Loading services/core/java/com/android/server/vibrator/VibratorFrameworkStatsLogger.java +45 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.modules.expresslog.Counter; import com.android.modules.expresslog.Histogram; import java.util.ArrayDeque; import java.util.Queue; Loading @@ -40,6 +41,23 @@ public class VibratorFrameworkStatsLogger { // Warning about dropping entries after this amount of atoms were dropped by the throttle. private static final int VIBRATION_REPORTED_WARNING_QUEUE_SIZE = 200; // Latency between 0ms and 99ms, with 100 representing overflow latencies >= 100ms. // Underflow not expected. private static final Histogram sVibrationParamRequestLatencyHistogram = new Histogram( "vibrator.value_vibration_param_request_latency", new Histogram.UniformOptions(20, 0, 100)); // Scales in [0, 2), with 2 representing overflow scales >= 2. // Underflow expected to represent how many times scales were cleared (set to -1). private static final Histogram sVibrationParamScaleHistogram = new Histogram( "vibrator.value_vibration_param_scale", new Histogram.UniformOptions(20, 0, 2)); // Scales in [0, 2), with 2 representing overflow scales >= 2. // Underflow not expected. private static final Histogram sAdaptiveHapticScaleHistogram = new Histogram( "vibrator.value_vibration_adaptive_haptic_scale", new Histogram.UniformOptions(20, 0, 2)); private final Object mLock = new Object(); private final Handler mHandler; private final long mVibrationReportedLogIntervalMillis; Loading Loading @@ -140,6 +158,33 @@ public class VibratorFrameworkStatsLogger { } } /** Logs adaptive haptic scale value applied to a vibration, only if it's not 1.0. */ public void logVibrationAdaptiveHapticScale(int uid, float scale) { if (Float.compare(scale, 1f) != 0) { sAdaptiveHapticScaleHistogram.logSampleWithUid(uid, scale); } } /** Logs a vibration param scale value received by the vibrator control service. */ public void logVibrationParamScale(float scale) { sVibrationParamScaleHistogram.logSample(scale); } /** Logs the latency of a successful vibration params request completed before a vibration. */ public void logVibrationParamRequestLatency(int uid, long latencyMs) { sVibrationParamRequestLatencyHistogram.logSampleWithUid(uid, (float) latencyMs); } /** Logs a vibration params request timed out before a vibration. */ public void logVibrationParamRequestTimeout(int uid) { Counter.logIncrementWithUid("vibrator.value_vibration_param_request_timeout", uid); } /** Logs when a response received for a vibration params request is ignored by the service. */ public void logVibrationParamResponseIgnored() { Counter.logIncrement("vibrator.value_vibration_param_response_ignored"); } /** Logs only if the haptics feedback effect is one of the KEYBOARD_ constants. */ public static void logPerformHapticsFeedbackIfKeyboard(int uid, int hapticsFeedbackEffect) { boolean isKeyboard; Loading services/core/java/com/android/server/vibrator/VibratorManagerService.java +13 −19 Original line number Diff line number Diff line Loading @@ -212,12 +212,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { mContext = context; mInjector = injector; mHandler = injector.createHandler(Looper.myLooper()); mFrameworkStatsLogger = injector.getFrameworkStatsLogger(mHandler); mVibrationSettings = new VibrationSettings(mContext, mHandler); mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings); mVibratorControlService = new VibratorControlService(mContext, injector.createVibratorControllerHolder(), mVibrationScaler, mVibrationSettings, mLock); mFrameworkStatsLogger, mLock); mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler); VibrationCompleteListener listener = new VibrationCompleteListener(this); Loading @@ -235,7 +236,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { recentDumpSizeLimit, dumpSizeLimit, dumpAggregationTimeLimit); mBatteryStatsService = injector.getBatteryStatsService(); mFrameworkStatsLogger = injector.getFrameworkStatsLogger(mHandler); mAppOps = mContext.getSystemService(AppOpsManager.class); Loading Loading @@ -853,9 +853,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private void endVibrationLocked(HalVibration vib, Vibration.EndInfo vibrationEndInfo, boolean shouldWriteStats) { vib.end(vibrationEndInfo); logVibrationStatus(vib.callerInfo.uid, vib.callerInfo.attrs, vibrationEndInfo.status); mVibratorManagerRecords.record(vib); logAndRecordVibration(vib.getDebugInfo()); if (shouldWriteStats) { mFrameworkStatsLogger.writeVibrationReportedAsync( vib.getStatsInfo(/* completionUptimeMillis= */ SystemClock.uptimeMillis())); Loading @@ -866,9 +864,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private void endVibrationAndWriteStatsLocked(ExternalVibrationHolder vib, Vibration.EndInfo vibrationEndInfo) { vib.end(vibrationEndInfo); logVibrationStatus(vib.externalVibration.getUid(), vib.externalVibration.getVibrationAttributes(), vibrationEndInfo.status); mVibratorManagerRecords.record(vib); logAndRecordVibration(vib.getDebugInfo()); mFrameworkStatsLogger.writeVibrationReportedAsync( vib.getStatsInfo(/* completionUptimeMillis= */ SystemClock.uptimeMillis())); } Loading @@ -882,12 +878,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { vib.callerInfo.attrs.getUsage())) { requestVibrationParamsFuture = mVibratorControlService.triggerVibrationParamsRequest( vib.callerInfo.attrs.getUsage(), vib.callerInfo.uid, vib.callerInfo.attrs.getUsage(), mVibrationSettings.getRequestVibrationParamsTimeoutMs()); } return new VibrationStepConductor(vib, mVibrationSettings, mDeviceAdapter, mVibrationScaler, requestVibrationParamsFuture, mVibrationThreadCallbacks); mFrameworkStatsLogger, requestVibrationParamsFuture, mVibrationThreadCallbacks); } private Vibration.EndInfo startVibrationOnInputDevicesLocked(HalVibration vib) { Loading @@ -903,6 +899,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { return new Vibration.EndInfo(Vibration.Status.FORWARDED_TO_INPUT_DEVICES); } private void logAndRecordVibration(Vibration.DebugInfo info) { info.logMetrics(mFrameworkStatsLogger); logVibrationStatus(info.mCallerInfo.uid, info.mCallerInfo.attrs, info.mStatus); mVibratorManagerRecords.record(info); } private void logVibrationStatus(int uid, VibrationAttributes attrs, Vibration.Status status) { switch (status) { Loading Loading @@ -1752,15 +1754,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { new VibrationRecords(recentVibrationSizeLimit, /* aggregationTimeLimit= */ 0); } synchronized void record(HalVibration vib) { record(vib.getDebugInfo()); } synchronized void record(ExternalVibrationHolder vib) { record(vib.getDebugInfo()); } private synchronized void record(Vibration.DebugInfo info) { synchronized void record(Vibration.DebugInfo info) { GroupedAggregatedLogRecords.AggregatedLogRecord<VibrationRecord> droppedRecord = mRecentVibrations.add(new VibrationRecord(info)); if (droppedRecord != null) { Loading Loading
services/core/java/com/android/server/vibrator/Vibration.java +5 −1 Original line number Diff line number Diff line Loading @@ -208,6 +208,7 @@ abstract class Vibration { * potentially expensive or resource-linked objects, such as {@link IBinder}. */ static final class DebugInfo { final Status mStatus; final long mCreateTime; final CallerInfo mCallerInfo; @Nullable Loading @@ -220,7 +221,6 @@ abstract class Vibration { private final CombinedVibration mOriginalEffect; private final int mScaleLevel; private final float mAdaptiveScale; private final Status mStatus; DebugInfo(Status status, VibrationStats stats, @Nullable CombinedVibration playedEffect, @Nullable CombinedVibration originalEffect, int scaleLevel, Loading Loading @@ -253,6 +253,10 @@ abstract class Vibration { + ", callerInfo: " + mCallerInfo; } void logMetrics(VibratorFrameworkStatsLogger statsLogger) { statsLogger.logVibrationAdaptiveHapticScale(mCallerInfo.uid, mAdaptiveScale); } /** * Write this info in a compact way into given {@link PrintWriter}. * Loading
services/core/java/com/android/server/vibrator/VibrationStepConductor.java +18 −4 Original line number Diff line number Diff line Loading @@ -40,8 +40,10 @@ import java.util.LinkedList; import java.util.List; import java.util.PriorityQueue; import java.util.Queue; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * Creates and manages a queue of steps for performing a VibrationEffect, as well as coordinating Loading Loading @@ -70,6 +72,7 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { private final DeviceAdapter mDeviceAdapter; private final VibrationScaler mVibrationScaler; private final VibratorFrameworkStatsLogger mStatsLogger; // Not guarded by lock because it's mostly used to read immutable fields by this conductor. // This is only modified here at the prepareToStart method which always runs at the vibration Loading Loading @@ -103,14 +106,15 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { private int mSuccessfulVibratorOnSteps; VibrationStepConductor(HalVibration vib, VibrationSettings vibrationSettings, DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler, DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler, VibratorFrameworkStatsLogger statsLogger, CompletableFuture<Void> requestVibrationParamsFuture, VibrationThread.VibratorManagerHooks vibratorManagerHooks) { this.mVibration = vib; this.vibrationSettings = vibrationSettings; this.mDeviceAdapter = deviceAdapter; mVibrationScaler = vibrationScaler; mStatsLogger = statsLogger; mRequestVibrationParamsFuture = requestVibrationParamsFuture; this.vibratorManagerHooks = vibratorManagerHooks; this.mSignalVibratorsComplete = Loading Loading @@ -461,9 +465,19 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { } try { mRequestVibrationParamsFuture.orTimeout( mRequestVibrationParamsFuture.get( vibrationSettings.getRequestVibrationParamsTimeoutMs(), TimeUnit.MILLISECONDS).get(); TimeUnit.MILLISECONDS); } catch (TimeoutException e) { if (DEBUG) { Slog.d(TAG, "Request for vibration params timed out", e); } mStatsLogger.logVibrationParamRequestTimeout(mVibration.callerInfo.uid); } catch (CancellationException e) { if (DEBUG) { Slog.d(TAG, "Request for vibration params cancelled, maybe superseded or" + " vibrator controller unregistered. Skipping params...", e); } } catch (Throwable e) { Slog.w(TAG, "Failed to retrieve vibration params.", e); } Loading
services/core/java/com/android/server/vibrator/VibratorControlService.java +46 −25 Original line number Diff line number Diff line Loading @@ -72,19 +72,21 @@ final class VibratorControlService extends IVibratorControlService.Stub { private final VibrationParamsRecords mVibrationParamsRecords; private final VibratorControllerHolder mVibratorControllerHolder; private final VibrationScaler mVibrationScaler; private final VibratorFrameworkStatsLogger mStatsLogger; private final Object mLock; private final int[] mRequestVibrationParamsForUsages; @GuardedBy("mLock") private CompletableFuture<Void> mRequestVibrationParamsFuture = null; @GuardedBy("mLock") private IBinder mRequestVibrationParamsToken; @Nullable private VibrationParamRequest mVibrationParamRequest = null; VibratorControlService(Context context, VibratorControllerHolder vibratorControllerHolder, VibrationScaler vibrationScaler, VibrationSettings vibrationSettings, Object lock) { VibrationSettings vibrationSettings, VibratorFrameworkStatsLogger statsLogger, Object lock) { mVibratorControllerHolder = vibratorControllerHolder; mVibrationScaler = vibrationScaler; mStatsLogger = statsLogger; mLock = lock; mRequestVibrationParamsForUsages = vibrationSettings.getRequestVibrationParamsForUsages(); Loading Loading @@ -180,20 +182,25 @@ final class VibratorControlService extends IVibratorControlService.Stub { Objects.requireNonNull(requestToken); synchronized (mLock) { if (mRequestVibrationParamsToken == null) { if (mVibrationParamRequest == null) { Slog.wtf(TAG, "New vibration params received but no token was cached in the service. " + "New vibration params ignored."); mStatsLogger.logVibrationParamResponseIgnored(); return; } if (!Objects.equals(requestToken, mRequestVibrationParamsToken)) { if (!Objects.equals(requestToken, mVibrationParamRequest.token)) { Slog.w(TAG, "New vibration params received but the provided token does not match the " + "cached one. New vibration params ignored."); mStatsLogger.logVibrationParamResponseIgnored(); return; } long latencyMs = SystemClock.uptimeMillis() - mVibrationParamRequest.uptimeMs; mStatsLogger.logVibrationParamRequestLatency(mVibrationParamRequest.uid, latencyMs); updateAdaptiveHapticsScales(result); endOngoingRequestVibrationParamsLocked(/* wasCancelled= */ false); recordUpdateVibrationParams(result, /* fromRequest= */ true); Loading Loading @@ -222,7 +229,7 @@ final class VibratorControlService extends IVibratorControlService.Stub { */ @Nullable public CompletableFuture<Void> triggerVibrationParamsRequest( @VibrationAttributes.Usage int usage, int timeoutInMillis) { int uid, @VibrationAttributes.Usage int usage, int timeoutInMillis) { synchronized (mLock) { IVibratorController vibratorController = mVibratorControllerHolder.getVibratorController(); Loading @@ -241,16 +248,16 @@ final class VibratorControlService extends IVibratorControlService.Stub { try { endOngoingRequestVibrationParamsLocked(/* wasCancelled= */ true); mRequestVibrationParamsFuture = new CompletableFuture<>(); mRequestVibrationParamsToken = new Binder(); mVibrationParamRequest = new VibrationParamRequest(uid); vibratorController.requestVibrationParams(vibrationType, timeoutInMillis, mRequestVibrationParamsToken); mVibrationParamRequest.token); return mVibrationParamRequest.future; } catch (RemoteException e) { Slog.e(TAG, "Failed to request vibration params.", e); endOngoingRequestVibrationParamsLocked(/* wasCancelled= */ true); } return mRequestVibrationParamsFuture; return null; } } Loading @@ -276,13 +283,13 @@ final class VibratorControlService extends IVibratorControlService.Stub { } /** * Returns the {@link #mRequestVibrationParamsToken} which is used to validate * Returns the binder token which is used to validate * {@link #onRequestVibrationParamsComplete(IBinder, VibrationParam[])} calls. */ @VisibleForTesting public IBinder getRequestVibrationParamsToken() { synchronized (mLock) { return mRequestVibrationParamsToken; return mVibrationParamRequest == null ? null : mVibrationParamRequest.token; } } Loading @@ -293,7 +300,7 @@ final class VibratorControlService extends IVibratorControlService.Stub { synchronized (mLock) { isVibratorControllerRegistered = mVibratorControllerHolder.getVibratorController() != null; hasPendingVibrationParamsRequest = mRequestVibrationParamsFuture != null; hasPendingVibrationParamsRequest = mVibrationParamRequest != null; } pw.println("VibratorControlService:"); Loading Loading @@ -329,18 +336,10 @@ final class VibratorControlService extends IVibratorControlService.Stub { */ @GuardedBy("mLock") private void endOngoingRequestVibrationParamsLocked(boolean wasCancelled) { mRequestVibrationParamsToken = null; if (mRequestVibrationParamsFuture == null) { return; if (mVibrationParamRequest != null) { mVibrationParamRequest.endRequest(wasCancelled); } if (wasCancelled) { mRequestVibrationParamsFuture.cancel(/* mayInterruptIfRunning= */ true); } else { mRequestVibrationParamsFuture.complete(null); } mRequestVibrationParamsFuture = null; mVibrationParamRequest = null; } private static int mapToAdaptiveVibrationType(@VibrationAttributes.Usage int usage) { Loading Loading @@ -423,6 +422,7 @@ final class VibratorControlService extends IVibratorControlService.Stub { * @param scale The scaling factor that should be applied to the vibrations. */ private void updateAdaptiveHapticsScales(int types, float scale) { mStatsLogger.logVibrationParamScale(scale); for (int usage : mapFromAdaptiveVibrationTypeToVibrationUsages(types)) { updateOrRemoveAdaptiveHapticsScale(usage, scale); } Loading Loading @@ -504,6 +504,27 @@ final class VibratorControlService extends IVibratorControlService.Stub { } } /** Represents a request for {@link VibrationParam}. */ private static final class VibrationParamRequest { public final CompletableFuture<Void> future = new CompletableFuture<>(); public final IBinder token = new Binder(); public final int uid; public final long uptimeMs; VibrationParamRequest(int uid) { this.uid = uid; uptimeMs = SystemClock.uptimeMillis(); } public void endRequest(boolean wasCancelled) { if (wasCancelled) { future.cancel(/* mayInterruptIfRunning= */ true); } else { future.complete(null); } } } /** * Record for a single {@link Vibration.DebugInfo}, that can be grouped by usage and aggregated * by UID, {@link VibrationAttributes} and {@link VibrationEffect}. Loading
services/core/java/com/android/server/vibrator/VibratorFrameworkStatsLogger.java +45 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.modules.expresslog.Counter; import com.android.modules.expresslog.Histogram; import java.util.ArrayDeque; import java.util.Queue; Loading @@ -40,6 +41,23 @@ public class VibratorFrameworkStatsLogger { // Warning about dropping entries after this amount of atoms were dropped by the throttle. private static final int VIBRATION_REPORTED_WARNING_QUEUE_SIZE = 200; // Latency between 0ms and 99ms, with 100 representing overflow latencies >= 100ms. // Underflow not expected. private static final Histogram sVibrationParamRequestLatencyHistogram = new Histogram( "vibrator.value_vibration_param_request_latency", new Histogram.UniformOptions(20, 0, 100)); // Scales in [0, 2), with 2 representing overflow scales >= 2. // Underflow expected to represent how many times scales were cleared (set to -1). private static final Histogram sVibrationParamScaleHistogram = new Histogram( "vibrator.value_vibration_param_scale", new Histogram.UniformOptions(20, 0, 2)); // Scales in [0, 2), with 2 representing overflow scales >= 2. // Underflow not expected. private static final Histogram sAdaptiveHapticScaleHistogram = new Histogram( "vibrator.value_vibration_adaptive_haptic_scale", new Histogram.UniformOptions(20, 0, 2)); private final Object mLock = new Object(); private final Handler mHandler; private final long mVibrationReportedLogIntervalMillis; Loading Loading @@ -140,6 +158,33 @@ public class VibratorFrameworkStatsLogger { } } /** Logs adaptive haptic scale value applied to a vibration, only if it's not 1.0. */ public void logVibrationAdaptiveHapticScale(int uid, float scale) { if (Float.compare(scale, 1f) != 0) { sAdaptiveHapticScaleHistogram.logSampleWithUid(uid, scale); } } /** Logs a vibration param scale value received by the vibrator control service. */ public void logVibrationParamScale(float scale) { sVibrationParamScaleHistogram.logSample(scale); } /** Logs the latency of a successful vibration params request completed before a vibration. */ public void logVibrationParamRequestLatency(int uid, long latencyMs) { sVibrationParamRequestLatencyHistogram.logSampleWithUid(uid, (float) latencyMs); } /** Logs a vibration params request timed out before a vibration. */ public void logVibrationParamRequestTimeout(int uid) { Counter.logIncrementWithUid("vibrator.value_vibration_param_request_timeout", uid); } /** Logs when a response received for a vibration params request is ignored by the service. */ public void logVibrationParamResponseIgnored() { Counter.logIncrement("vibrator.value_vibration_param_response_ignored"); } /** Logs only if the haptics feedback effect is one of the KEYBOARD_ constants. */ public static void logPerformHapticsFeedbackIfKeyboard(int uid, int hapticsFeedbackEffect) { boolean isKeyboard; Loading
services/core/java/com/android/server/vibrator/VibratorManagerService.java +13 −19 Original line number Diff line number Diff line Loading @@ -212,12 +212,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { mContext = context; mInjector = injector; mHandler = injector.createHandler(Looper.myLooper()); mFrameworkStatsLogger = injector.getFrameworkStatsLogger(mHandler); mVibrationSettings = new VibrationSettings(mContext, mHandler); mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings); mVibratorControlService = new VibratorControlService(mContext, injector.createVibratorControllerHolder(), mVibrationScaler, mVibrationSettings, mLock); mFrameworkStatsLogger, mLock); mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler); VibrationCompleteListener listener = new VibrationCompleteListener(this); Loading @@ -235,7 +236,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { recentDumpSizeLimit, dumpSizeLimit, dumpAggregationTimeLimit); mBatteryStatsService = injector.getBatteryStatsService(); mFrameworkStatsLogger = injector.getFrameworkStatsLogger(mHandler); mAppOps = mContext.getSystemService(AppOpsManager.class); Loading Loading @@ -853,9 +853,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private void endVibrationLocked(HalVibration vib, Vibration.EndInfo vibrationEndInfo, boolean shouldWriteStats) { vib.end(vibrationEndInfo); logVibrationStatus(vib.callerInfo.uid, vib.callerInfo.attrs, vibrationEndInfo.status); mVibratorManagerRecords.record(vib); logAndRecordVibration(vib.getDebugInfo()); if (shouldWriteStats) { mFrameworkStatsLogger.writeVibrationReportedAsync( vib.getStatsInfo(/* completionUptimeMillis= */ SystemClock.uptimeMillis())); Loading @@ -866,9 +864,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private void endVibrationAndWriteStatsLocked(ExternalVibrationHolder vib, Vibration.EndInfo vibrationEndInfo) { vib.end(vibrationEndInfo); logVibrationStatus(vib.externalVibration.getUid(), vib.externalVibration.getVibrationAttributes(), vibrationEndInfo.status); mVibratorManagerRecords.record(vib); logAndRecordVibration(vib.getDebugInfo()); mFrameworkStatsLogger.writeVibrationReportedAsync( vib.getStatsInfo(/* completionUptimeMillis= */ SystemClock.uptimeMillis())); } Loading @@ -882,12 +878,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { vib.callerInfo.attrs.getUsage())) { requestVibrationParamsFuture = mVibratorControlService.triggerVibrationParamsRequest( vib.callerInfo.attrs.getUsage(), vib.callerInfo.uid, vib.callerInfo.attrs.getUsage(), mVibrationSettings.getRequestVibrationParamsTimeoutMs()); } return new VibrationStepConductor(vib, mVibrationSettings, mDeviceAdapter, mVibrationScaler, requestVibrationParamsFuture, mVibrationThreadCallbacks); mFrameworkStatsLogger, requestVibrationParamsFuture, mVibrationThreadCallbacks); } private Vibration.EndInfo startVibrationOnInputDevicesLocked(HalVibration vib) { Loading @@ -903,6 +899,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { return new Vibration.EndInfo(Vibration.Status.FORWARDED_TO_INPUT_DEVICES); } private void logAndRecordVibration(Vibration.DebugInfo info) { info.logMetrics(mFrameworkStatsLogger); logVibrationStatus(info.mCallerInfo.uid, info.mCallerInfo.attrs, info.mStatus); mVibratorManagerRecords.record(info); } private void logVibrationStatus(int uid, VibrationAttributes attrs, Vibration.Status status) { switch (status) { Loading Loading @@ -1752,15 +1754,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { new VibrationRecords(recentVibrationSizeLimit, /* aggregationTimeLimit= */ 0); } synchronized void record(HalVibration vib) { record(vib.getDebugInfo()); } synchronized void record(ExternalVibrationHolder vib) { record(vib.getDebugInfo()); } private synchronized void record(Vibration.DebugInfo info) { synchronized void record(Vibration.DebugInfo info) { GroupedAggregatedLogRecords.AggregatedLogRecord<VibrationRecord> droppedRecord = mRecentVibrations.add(new VibrationRecord(info)); if (droppedRecord != null) { Loading