Loading services/core/java/com/android/server/vibrator/HalNativeHandler.java 0 → 100644 +51 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.hardware.vibrator.IVibrationSession; import android.hardware.vibrator.IVibratorManager; /** Handles interactions with vibrator HAL services through native. */ interface HalNativeHandler { /** Initializes the callback instance for future interactions. */ void init(@NonNull HalVibratorManager.Callbacks managerCallback, @NonNull HalVibrator.Callbacks vibratorCallback); /** * Call {@link IVibratorManager#triggerSynced} using given vibration id for callbacks from HAL. * * <p>This should only be called if HAL has {@link IVibratorManager#CAP_TRIGGER_CALLBACK}. The * HAL might fail the request otherwise. * * @return true if successful, false otherwise. */ boolean triggerSyncedWithCallback(long vibrationId); /** * Call {@link IVibratorManager#startSession} using given session id for callbacks from HAL. * * <p>This should only be called if HAL has {@link IVibratorManager#CAP_START_SESSIONS}. The * HAL might fail the request otherwise. * * @return the session binder token if successful, null otherwise. */ @Nullable IVibrationSession startSessionWithCallback(long sessionId, int[] vibratorIds); } services/core/java/com/android/server/vibrator/HalVibrator.java +6 −0 Original line number Diff line number Diff line Loading @@ -27,10 +27,16 @@ import android.os.vibrator.PwlePoint; import android.os.vibrator.RampSegment; import android.util.IndentingPrintWriter; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.UsedByNative; /** Handles interactions with a single vibrator HAL. */ interface HalVibrator { /** Callbacks from the vibrator HAL. */ @UsedByNative( description = "Called from JNI in jni/VibratorManagerService.cpp", kind = KeepItemKind.CLASS_AND_MEMBERS) interface Callbacks { /** Callback triggered when a vibration step is complete. */ void onVibrationStepComplete(int vibratorId, long vibrationId, long stepId); Loading services/core/java/com/android/server/vibrator/HalVibratorManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -20,10 +20,16 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.util.IndentingPrintWriter; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.UsedByNative; /** Handles interactions with a vibrator manager HAL. */ interface HalVibratorManager { /** Callbacks from the vibrator manager HAL. */ @UsedByNative( description = "Called from JNI in jni/VibratorManagerService.cpp", kind = KeepItemKind.CLASS_AND_MEMBERS) interface Callbacks { /** Callback triggered when synced vibration is complete. */ void onSyncedVibrationComplete(long vibrationId); Loading services/core/java/com/android/server/vibrator/VibratorManagerService.java +68 −4 Original line number Diff line number Diff line Loading @@ -88,6 +88,8 @@ import com.android.server.pm.UserManagerInternal; import com.android.server.vibrator.VibrationSession.CallerInfo; import com.android.server.vibrator.VibrationSession.DebugInfo; import com.android.server.vibrator.VibrationSession.Status; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.UsedByNative; import libcore.util.NativeAllocationRegistry; Loading @@ -108,6 +110,9 @@ import java.util.function.Function; import java.util.function.Predicate; /** System implementation of {@link IVibratorManagerService}. */ @UsedByNative( description = "Called from JNI in jni/VibratorManagerService.cpp", kind = KeepItemKind.CLASS_AND_MEMBERS) public class VibratorManagerService extends IVibratorManagerService.Stub { private static final String TAG = "VibratorManagerService"; private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service"; Loading Loading @@ -233,10 +238,22 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } }; // TODO(b/409002423): remove the native methods once remove_hidl_support flag removed static native long nativeInit(HalVibratorManager.Callbacks callback); /** Create native objects and keep weak references to global callbacks. */ private static native long nativeNewInit(HalVibratorManager.Callbacks managerCallbacks, HalVibrator.Callbacks vibratorCallbacks); /** Return pointer to function to destroy native objects created by {@link #nativeInit}. */ private static native long nativeGetFinalizer(); /** Calls {@link IVibratorManager#triggerSynced} with callback. */ private static native boolean nativeTriggerSyncedWithCallback(long nativePtr, long vibrationId); /** Calls {@link IVibratorManager#startSession} with callback. */ private static native IBinder nativeStartSessionWithCallback(long nativePtr, long sessionId, int[] vibratorIds); static native long nativeGetFinalizer(); // TODO(b/409002423): remove native methods below once remove_hidl_support flag removed static native long nativeInit(HalVibratorManager.Callbacks callback); static native long nativeGetCapabilities(long nativeServicePtr); Loading Loading @@ -1741,7 +1758,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } HalVibratorManager createHalVibratorManager() { return VintfHalVibratorManager.createHalVibratorManager(); return VintfHalVibratorManager.createHalVibratorManager(new NativeHandler()); } HalVibratorManager createNativeHalVibratorManager() { Loading Loading @@ -2309,6 +2326,53 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } } /** {@link HalNativeHandler} based on {@link VibratorManagerService} native methods. */ private static class NativeHandler implements HalNativeHandler { @SuppressWarnings("unused") // Used from native as a weak global reference private HalVibratorManager.Callbacks mManagerCallbacks; @SuppressWarnings("unused") // Used from native as a weak global reference private HalVibrator.Callbacks mVibratorCallbacks; /** * Keep pointer to native resources allocated by {@link #nativeInit}, to be used on each * native method call and cleared when this instance is garbage collected. */ private long mNativePtr; @Override public void init(@NonNull HalVibratorManager.Callbacks managerCallback, @NonNull HalVibrator.Callbacks vibratorCallbacks) { mManagerCallbacks = managerCallback; // Used from native as a weak global reference mVibratorCallbacks = vibratorCallbacks; // Used from native as a weak global reference mNativePtr = nativeNewInit(managerCallback, vibratorCallbacks); long finalizerPtr = nativeGetFinalizer(); if (finalizerPtr != 0) { NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced( VibratorManagerService.class.getClassLoader(), finalizerPtr); registry.registerNativeAllocation(this, mNativePtr); } } @Override public boolean triggerSyncedWithCallback(long vibrationId) { return nativeTriggerSyncedWithCallback(mNativePtr, vibrationId); } @Nullable @Override public android.hardware.vibrator.IVibrationSession startSessionWithCallback( long sessionId, int[] vibratorIds) { IBinder token = nativeStartSessionWithCallback(mNativePtr, sessionId, vibratorIds); if (token == null) { return null; } return android.hardware.vibrator.IVibrationSession.Stub.asInterface(token); } } /** Keep records of vibrations played and provide debug information for this service. */ private static final class VibratorManagerRecords { private final VibrationRecords mAggregatedVibrationHistory; Loading services/core/java/com/android/server/vibrator/VintfHalVibratorManager.java +77 −92 Original line number Diff line number Diff line Loading @@ -20,9 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.vibrator.IVibrationSession; import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.IVibratorCallback; import android.hardware.vibrator.IVibratorManager; import android.hardware.vibrator.VibrationSessionConfig; import android.os.Binder; import android.os.DeadObjectException; import android.os.IBinder; Loading @@ -37,7 +35,6 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.server.vibrator.VintfUtils.VintfSupplier; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.List; Loading @@ -50,14 +47,14 @@ class VintfHalVibratorManager { private static final int DEFAULT_VIBRATOR_ID = 0; /** Create {@link HalVibratorManager} based on declared services on device. */ static HalVibratorManager createHalVibratorManager() { static HalVibratorManager createHalVibratorManager(HalNativeHandler nativeHandler) { // TODO(b/422944962): Replace this with Vintf HalVibrator IntFunction<HalVibrator> vibratorFactory = VibratorController::new; if (ServiceManager.isDeclared(IVibratorManager.DESCRIPTOR + "/default")) { Slog.v(TAG, "Loading default IVibratorManager service."); return new DefaultHalVibratorManager( new DefaultVibratorManagerSupplier(), vibratorFactory); return new DefaultHalVibratorManager(new DefaultVibratorManagerSupplier(), nativeHandler, vibratorFactory); } if (ServiceManager.isDeclared(IVibrator.DESCRIPTOR + "/default")) { Slog.v(TAG, "Loading default IVibrator service."); Loading Loading @@ -88,10 +85,34 @@ class VintfHalVibratorManager { static final class DefaultHalVibratorManager implements HalVibratorManager { private static final String TAG = "DefaultHalVibratorManager"; /** Wrapper for native callbacks to keep track of ongoing vibration sessions. */ private final class CallbacksWrapper implements Callbacks { private final Callbacks mDelegate; CallbacksWrapper(Callbacks delegate) { mDelegate = delegate; } @Override public void onSyncedVibrationComplete(long vibrationId) { mDelegate.onSyncedVibrationComplete(vibrationId); } @Override public void onVibrationSessionComplete(long sessionId) { removeSession(sessionId); mDelegate.onVibrationSessionComplete(sessionId); } } private final Object mLock = new Object(); @GuardedBy("mLock") private final LongSparseArray<IVibrationSession> mOngoingSessions = new LongSparseArray<>(); @GuardedBy("mLock") private final LongSparseArray<IBinder.DeathRecipient> mSessionDeathRecipients = new LongSparseArray<>(); private final VintfSupplier<IVibratorManager> mHalSupplier; private final HalNativeHandler mNativeHandler; private final IntFunction<HalVibrator> mVibratorFactory; private final SparseArray<HalVibrator> mVibrators = new SparseArray<>(); Loading @@ -101,14 +122,16 @@ class VintfHalVibratorManager { private volatile int[] mVibratorIds = new int[0]; DefaultHalVibratorManager(VintfSupplier<IVibratorManager> supplier, IntFunction<HalVibrator> vibratorFactory) { HalNativeHandler nativeHandler, IntFunction<HalVibrator> vibratorFactory) { mHalSupplier = supplier; mNativeHandler = nativeHandler; mVibratorFactory = vibratorFactory; } @Override public void init(@NonNull Callbacks cb, @NonNull HalVibrator.Callbacks vibratorCb) { mCallbacks = cb; mCallbacks = new CallbacksWrapper(cb); mNativeHandler.init(mCallbacks, vibratorCb); // Load vibrator hardware info. The vibrator ids and manager capabilities are loaded // once and assumed unchanged for the lifecycle of this service. Each vibrator can still Loading Loading @@ -177,12 +200,14 @@ class VintfHalVibratorManager { Slog.w(TAG, "No capability to synchronize vibrations, ignoring trigger request."); return false; } final IVibratorCallback callback = hasCapability(IVibratorManager.CAP_TRIGGER_CALLBACK) ? new SyncedVibrationCallback(this, vibrationId) : null; if (hasCapability(IVibratorManager.CAP_TRIGGER_CALLBACK)) { // Delegate trigger with callback to native, to avoid creating a new callback // instance for each call, overloading the GC. return mNativeHandler.triggerSyncedWithCallback(vibrationId); } // Trigger callback not supported, avoid unnecessary JNI round trip. return VintfUtils.runNoThrow(mHalSupplier, hal -> hal.triggerSynced(callback), hal -> hal.triggerSynced(null), e -> Slog.e(TAG, "Error triggering synced vibration " + vibrationId, e)); } Loading @@ -203,19 +228,33 @@ class VintfHalVibratorManager { Slog.w(TAG, "No capability to start sessions, ignoring start session request."); return false; } final IVibratorCallback callback = new SessionCallback(this, sessionId); VibrationSessionConfig config = new VibrationSessionConfig(); Optional<IVibrationSession> session = VintfUtils.getNoThrow(mHalSupplier, hal -> hal.startSession(vibratorIds, config, callback), e -> Slog.e(TAG, "Error starting vibration session " + sessionId + " on vibrators " + Arrays.toString(vibratorIds), e)); if (session.isPresent()) { // Delegate start session with callback to native, to avoid creating a new callback // instance for each call, overloading the GC. IVibrationSession session = mNativeHandler.startSessionWithCallback( sessionId, vibratorIds); if (session == null) { Slog.e(TAG, "Error starting session " + sessionId + " for vibrators " + Arrays.toString(vibratorIds)); return false; } // Use same callback from death recipient to remove session and notify client. IBinder.DeathRecipient deathRecipient = () -> mCallbacks.onVibrationSessionComplete(sessionId); try { IBinder sessionToken = session.asBinder(); Binder.allowBlocking(sessionToken); // Required to trigger close/abort methods. sessionToken.linkToDeath(deathRecipient, 0); } catch (RemoteException e) { Slog.e(TAG, "Unable to register DeathRecipient for session " + sessionId, e); deathRecipient = null; } synchronized (mLock) { mOngoingSessions.put(sessionId, session.get()); mOngoingSessions.put(sessionId, session); if (deathRecipient != null) { mSessionDeathRecipients.put(sessionId, deathRecipient); } return true; } return false; return true; } @Override Loading @@ -229,7 +268,8 @@ class VintfHalVibratorManager { session = mOngoingSessions.get(sessionId); } if (session == null) { Slog.w(TAG, "No session with id " + sessionId + " to end, ignoring request."); Slog.w(TAG, "Error ending session " + sessionId + " with abort=" + shouldAbort + ", session not found"); return false; } try { Loading Loading @@ -289,8 +329,20 @@ class VintfHalVibratorManager { } private void removeSession(long sessionId) { IVibrationSession session; IBinder.DeathRecipient deathRecipient; synchronized (mLock) { session = mOngoingSessions.get(sessionId); mOngoingSessions.remove(sessionId); deathRecipient = mSessionDeathRecipients.get(sessionId); mSessionDeathRecipients.remove(sessionId); } if (session != null && deathRecipient != null) { try { session.asBinder().unlinkToDeath(deathRecipient, 0); } catch (Exception e) { Slog.e(TAG, "Unable to remove DeathRecipient for session " + sessionId, e); } } } Loading Loading @@ -325,73 +377,6 @@ class VintfHalVibratorManager { } return names.toArray(new String[names.size()]); } /** Provides {@link IVibratorCallback} without references to local instances. */ private static final class SyncedVibrationCallback extends IVibratorCallback.Stub { private final WeakReference<DefaultHalVibratorManager> mManagerRef; private final long mVibrationId; SyncedVibrationCallback(DefaultHalVibratorManager manager, long vibrationId) { mManagerRef = new WeakReference<>(manager); mVibrationId = vibrationId; } @Override public void onComplete() { DefaultHalVibratorManager manager = mManagerRef.get(); if (manager == null) { return; } Callbacks callbacks = manager.mCallbacks; if (callbacks != null) { callbacks.onSyncedVibrationComplete(mVibrationId); } } @Override public int getInterfaceVersion() { return IVibratorCallback.VERSION; } @Override public String getInterfaceHash() { return IVibratorCallback.HASH; } } /** Provides {@link IVibratorCallback} without references to local instances. */ private static final class SessionCallback extends IVibratorCallback.Stub { private final WeakReference<DefaultHalVibratorManager> mManagerRef; private final long mSessionId; SessionCallback(DefaultHalVibratorManager manager, long sessionId) { mManagerRef = new WeakReference<>(manager); mSessionId = sessionId; } @Override public void onComplete() { DefaultHalVibratorManager manager = mManagerRef.get(); if (manager == null) { return; } manager.removeSession(mSessionId); Callbacks callbacks = manager.mCallbacks; if (callbacks != null) { callbacks.onVibrationSessionComplete(mSessionId); } } @Override public int getInterfaceVersion() { return IVibratorCallback.VERSION; } @Override public String getInterfaceHash() { return IVibratorCallback.HASH; } } } /** Legacy implementation for devices without a declared {@link IVibratorManager} service. */ Loading Loading
services/core/java/com/android/server/vibrator/HalNativeHandler.java 0 → 100644 +51 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.hardware.vibrator.IVibrationSession; import android.hardware.vibrator.IVibratorManager; /** Handles interactions with vibrator HAL services through native. */ interface HalNativeHandler { /** Initializes the callback instance for future interactions. */ void init(@NonNull HalVibratorManager.Callbacks managerCallback, @NonNull HalVibrator.Callbacks vibratorCallback); /** * Call {@link IVibratorManager#triggerSynced} using given vibration id for callbacks from HAL. * * <p>This should only be called if HAL has {@link IVibratorManager#CAP_TRIGGER_CALLBACK}. The * HAL might fail the request otherwise. * * @return true if successful, false otherwise. */ boolean triggerSyncedWithCallback(long vibrationId); /** * Call {@link IVibratorManager#startSession} using given session id for callbacks from HAL. * * <p>This should only be called if HAL has {@link IVibratorManager#CAP_START_SESSIONS}. The * HAL might fail the request otherwise. * * @return the session binder token if successful, null otherwise. */ @Nullable IVibrationSession startSessionWithCallback(long sessionId, int[] vibratorIds); }
services/core/java/com/android/server/vibrator/HalVibrator.java +6 −0 Original line number Diff line number Diff line Loading @@ -27,10 +27,16 @@ import android.os.vibrator.PwlePoint; import android.os.vibrator.RampSegment; import android.util.IndentingPrintWriter; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.UsedByNative; /** Handles interactions with a single vibrator HAL. */ interface HalVibrator { /** Callbacks from the vibrator HAL. */ @UsedByNative( description = "Called from JNI in jni/VibratorManagerService.cpp", kind = KeepItemKind.CLASS_AND_MEMBERS) interface Callbacks { /** Callback triggered when a vibration step is complete. */ void onVibrationStepComplete(int vibratorId, long vibrationId, long stepId); Loading
services/core/java/com/android/server/vibrator/HalVibratorManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -20,10 +20,16 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.util.IndentingPrintWriter; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.UsedByNative; /** Handles interactions with a vibrator manager HAL. */ interface HalVibratorManager { /** Callbacks from the vibrator manager HAL. */ @UsedByNative( description = "Called from JNI in jni/VibratorManagerService.cpp", kind = KeepItemKind.CLASS_AND_MEMBERS) interface Callbacks { /** Callback triggered when synced vibration is complete. */ void onSyncedVibrationComplete(long vibrationId); Loading
services/core/java/com/android/server/vibrator/VibratorManagerService.java +68 −4 Original line number Diff line number Diff line Loading @@ -88,6 +88,8 @@ import com.android.server.pm.UserManagerInternal; import com.android.server.vibrator.VibrationSession.CallerInfo; import com.android.server.vibrator.VibrationSession.DebugInfo; import com.android.server.vibrator.VibrationSession.Status; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.UsedByNative; import libcore.util.NativeAllocationRegistry; Loading @@ -108,6 +110,9 @@ import java.util.function.Function; import java.util.function.Predicate; /** System implementation of {@link IVibratorManagerService}. */ @UsedByNative( description = "Called from JNI in jni/VibratorManagerService.cpp", kind = KeepItemKind.CLASS_AND_MEMBERS) public class VibratorManagerService extends IVibratorManagerService.Stub { private static final String TAG = "VibratorManagerService"; private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service"; Loading Loading @@ -233,10 +238,22 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } }; // TODO(b/409002423): remove the native methods once remove_hidl_support flag removed static native long nativeInit(HalVibratorManager.Callbacks callback); /** Create native objects and keep weak references to global callbacks. */ private static native long nativeNewInit(HalVibratorManager.Callbacks managerCallbacks, HalVibrator.Callbacks vibratorCallbacks); /** Return pointer to function to destroy native objects created by {@link #nativeInit}. */ private static native long nativeGetFinalizer(); /** Calls {@link IVibratorManager#triggerSynced} with callback. */ private static native boolean nativeTriggerSyncedWithCallback(long nativePtr, long vibrationId); /** Calls {@link IVibratorManager#startSession} with callback. */ private static native IBinder nativeStartSessionWithCallback(long nativePtr, long sessionId, int[] vibratorIds); static native long nativeGetFinalizer(); // TODO(b/409002423): remove native methods below once remove_hidl_support flag removed static native long nativeInit(HalVibratorManager.Callbacks callback); static native long nativeGetCapabilities(long nativeServicePtr); Loading Loading @@ -1741,7 +1758,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } HalVibratorManager createHalVibratorManager() { return VintfHalVibratorManager.createHalVibratorManager(); return VintfHalVibratorManager.createHalVibratorManager(new NativeHandler()); } HalVibratorManager createNativeHalVibratorManager() { Loading Loading @@ -2309,6 +2326,53 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } } /** {@link HalNativeHandler} based on {@link VibratorManagerService} native methods. */ private static class NativeHandler implements HalNativeHandler { @SuppressWarnings("unused") // Used from native as a weak global reference private HalVibratorManager.Callbacks mManagerCallbacks; @SuppressWarnings("unused") // Used from native as a weak global reference private HalVibrator.Callbacks mVibratorCallbacks; /** * Keep pointer to native resources allocated by {@link #nativeInit}, to be used on each * native method call and cleared when this instance is garbage collected. */ private long mNativePtr; @Override public void init(@NonNull HalVibratorManager.Callbacks managerCallback, @NonNull HalVibrator.Callbacks vibratorCallbacks) { mManagerCallbacks = managerCallback; // Used from native as a weak global reference mVibratorCallbacks = vibratorCallbacks; // Used from native as a weak global reference mNativePtr = nativeNewInit(managerCallback, vibratorCallbacks); long finalizerPtr = nativeGetFinalizer(); if (finalizerPtr != 0) { NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced( VibratorManagerService.class.getClassLoader(), finalizerPtr); registry.registerNativeAllocation(this, mNativePtr); } } @Override public boolean triggerSyncedWithCallback(long vibrationId) { return nativeTriggerSyncedWithCallback(mNativePtr, vibrationId); } @Nullable @Override public android.hardware.vibrator.IVibrationSession startSessionWithCallback( long sessionId, int[] vibratorIds) { IBinder token = nativeStartSessionWithCallback(mNativePtr, sessionId, vibratorIds); if (token == null) { return null; } return android.hardware.vibrator.IVibrationSession.Stub.asInterface(token); } } /** Keep records of vibrations played and provide debug information for this service. */ private static final class VibratorManagerRecords { private final VibrationRecords mAggregatedVibrationHistory; Loading
services/core/java/com/android/server/vibrator/VintfHalVibratorManager.java +77 −92 Original line number Diff line number Diff line Loading @@ -20,9 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.vibrator.IVibrationSession; import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.IVibratorCallback; import android.hardware.vibrator.IVibratorManager; import android.hardware.vibrator.VibrationSessionConfig; import android.os.Binder; import android.os.DeadObjectException; import android.os.IBinder; Loading @@ -37,7 +35,6 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.server.vibrator.VintfUtils.VintfSupplier; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.List; Loading @@ -50,14 +47,14 @@ class VintfHalVibratorManager { private static final int DEFAULT_VIBRATOR_ID = 0; /** Create {@link HalVibratorManager} based on declared services on device. */ static HalVibratorManager createHalVibratorManager() { static HalVibratorManager createHalVibratorManager(HalNativeHandler nativeHandler) { // TODO(b/422944962): Replace this with Vintf HalVibrator IntFunction<HalVibrator> vibratorFactory = VibratorController::new; if (ServiceManager.isDeclared(IVibratorManager.DESCRIPTOR + "/default")) { Slog.v(TAG, "Loading default IVibratorManager service."); return new DefaultHalVibratorManager( new DefaultVibratorManagerSupplier(), vibratorFactory); return new DefaultHalVibratorManager(new DefaultVibratorManagerSupplier(), nativeHandler, vibratorFactory); } if (ServiceManager.isDeclared(IVibrator.DESCRIPTOR + "/default")) { Slog.v(TAG, "Loading default IVibrator service."); Loading Loading @@ -88,10 +85,34 @@ class VintfHalVibratorManager { static final class DefaultHalVibratorManager implements HalVibratorManager { private static final String TAG = "DefaultHalVibratorManager"; /** Wrapper for native callbacks to keep track of ongoing vibration sessions. */ private final class CallbacksWrapper implements Callbacks { private final Callbacks mDelegate; CallbacksWrapper(Callbacks delegate) { mDelegate = delegate; } @Override public void onSyncedVibrationComplete(long vibrationId) { mDelegate.onSyncedVibrationComplete(vibrationId); } @Override public void onVibrationSessionComplete(long sessionId) { removeSession(sessionId); mDelegate.onVibrationSessionComplete(sessionId); } } private final Object mLock = new Object(); @GuardedBy("mLock") private final LongSparseArray<IVibrationSession> mOngoingSessions = new LongSparseArray<>(); @GuardedBy("mLock") private final LongSparseArray<IBinder.DeathRecipient> mSessionDeathRecipients = new LongSparseArray<>(); private final VintfSupplier<IVibratorManager> mHalSupplier; private final HalNativeHandler mNativeHandler; private final IntFunction<HalVibrator> mVibratorFactory; private final SparseArray<HalVibrator> mVibrators = new SparseArray<>(); Loading @@ -101,14 +122,16 @@ class VintfHalVibratorManager { private volatile int[] mVibratorIds = new int[0]; DefaultHalVibratorManager(VintfSupplier<IVibratorManager> supplier, IntFunction<HalVibrator> vibratorFactory) { HalNativeHandler nativeHandler, IntFunction<HalVibrator> vibratorFactory) { mHalSupplier = supplier; mNativeHandler = nativeHandler; mVibratorFactory = vibratorFactory; } @Override public void init(@NonNull Callbacks cb, @NonNull HalVibrator.Callbacks vibratorCb) { mCallbacks = cb; mCallbacks = new CallbacksWrapper(cb); mNativeHandler.init(mCallbacks, vibratorCb); // Load vibrator hardware info. The vibrator ids and manager capabilities are loaded // once and assumed unchanged for the lifecycle of this service. Each vibrator can still Loading Loading @@ -177,12 +200,14 @@ class VintfHalVibratorManager { Slog.w(TAG, "No capability to synchronize vibrations, ignoring trigger request."); return false; } final IVibratorCallback callback = hasCapability(IVibratorManager.CAP_TRIGGER_CALLBACK) ? new SyncedVibrationCallback(this, vibrationId) : null; if (hasCapability(IVibratorManager.CAP_TRIGGER_CALLBACK)) { // Delegate trigger with callback to native, to avoid creating a new callback // instance for each call, overloading the GC. return mNativeHandler.triggerSyncedWithCallback(vibrationId); } // Trigger callback not supported, avoid unnecessary JNI round trip. return VintfUtils.runNoThrow(mHalSupplier, hal -> hal.triggerSynced(callback), hal -> hal.triggerSynced(null), e -> Slog.e(TAG, "Error triggering synced vibration " + vibrationId, e)); } Loading @@ -203,19 +228,33 @@ class VintfHalVibratorManager { Slog.w(TAG, "No capability to start sessions, ignoring start session request."); return false; } final IVibratorCallback callback = new SessionCallback(this, sessionId); VibrationSessionConfig config = new VibrationSessionConfig(); Optional<IVibrationSession> session = VintfUtils.getNoThrow(mHalSupplier, hal -> hal.startSession(vibratorIds, config, callback), e -> Slog.e(TAG, "Error starting vibration session " + sessionId + " on vibrators " + Arrays.toString(vibratorIds), e)); if (session.isPresent()) { // Delegate start session with callback to native, to avoid creating a new callback // instance for each call, overloading the GC. IVibrationSession session = mNativeHandler.startSessionWithCallback( sessionId, vibratorIds); if (session == null) { Slog.e(TAG, "Error starting session " + sessionId + " for vibrators " + Arrays.toString(vibratorIds)); return false; } // Use same callback from death recipient to remove session and notify client. IBinder.DeathRecipient deathRecipient = () -> mCallbacks.onVibrationSessionComplete(sessionId); try { IBinder sessionToken = session.asBinder(); Binder.allowBlocking(sessionToken); // Required to trigger close/abort methods. sessionToken.linkToDeath(deathRecipient, 0); } catch (RemoteException e) { Slog.e(TAG, "Unable to register DeathRecipient for session " + sessionId, e); deathRecipient = null; } synchronized (mLock) { mOngoingSessions.put(sessionId, session.get()); mOngoingSessions.put(sessionId, session); if (deathRecipient != null) { mSessionDeathRecipients.put(sessionId, deathRecipient); } return true; } return false; return true; } @Override Loading @@ -229,7 +268,8 @@ class VintfHalVibratorManager { session = mOngoingSessions.get(sessionId); } if (session == null) { Slog.w(TAG, "No session with id " + sessionId + " to end, ignoring request."); Slog.w(TAG, "Error ending session " + sessionId + " with abort=" + shouldAbort + ", session not found"); return false; } try { Loading Loading @@ -289,8 +329,20 @@ class VintfHalVibratorManager { } private void removeSession(long sessionId) { IVibrationSession session; IBinder.DeathRecipient deathRecipient; synchronized (mLock) { session = mOngoingSessions.get(sessionId); mOngoingSessions.remove(sessionId); deathRecipient = mSessionDeathRecipients.get(sessionId); mSessionDeathRecipients.remove(sessionId); } if (session != null && deathRecipient != null) { try { session.asBinder().unlinkToDeath(deathRecipient, 0); } catch (Exception e) { Slog.e(TAG, "Unable to remove DeathRecipient for session " + sessionId, e); } } } Loading Loading @@ -325,73 +377,6 @@ class VintfHalVibratorManager { } return names.toArray(new String[names.size()]); } /** Provides {@link IVibratorCallback} without references to local instances. */ private static final class SyncedVibrationCallback extends IVibratorCallback.Stub { private final WeakReference<DefaultHalVibratorManager> mManagerRef; private final long mVibrationId; SyncedVibrationCallback(DefaultHalVibratorManager manager, long vibrationId) { mManagerRef = new WeakReference<>(manager); mVibrationId = vibrationId; } @Override public void onComplete() { DefaultHalVibratorManager manager = mManagerRef.get(); if (manager == null) { return; } Callbacks callbacks = manager.mCallbacks; if (callbacks != null) { callbacks.onSyncedVibrationComplete(mVibrationId); } } @Override public int getInterfaceVersion() { return IVibratorCallback.VERSION; } @Override public String getInterfaceHash() { return IVibratorCallback.HASH; } } /** Provides {@link IVibratorCallback} without references to local instances. */ private static final class SessionCallback extends IVibratorCallback.Stub { private final WeakReference<DefaultHalVibratorManager> mManagerRef; private final long mSessionId; SessionCallback(DefaultHalVibratorManager manager, long sessionId) { mManagerRef = new WeakReference<>(manager); mSessionId = sessionId; } @Override public void onComplete() { DefaultHalVibratorManager manager = mManagerRef.get(); if (manager == null) { return; } manager.removeSession(mSessionId); Callbacks callbacks = manager.mCallbacks; if (callbacks != null) { callbacks.onVibrationSessionComplete(mSessionId); } } @Override public int getInterfaceVersion() { return IVibratorCallback.VERSION; } @Override public String getInterfaceHash() { return IVibratorCallback.HASH; } } } /** Legacy implementation for devices without a declared {@link IVibratorManager} service. */ Loading