1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.vibrator;
18 
19 import android.annotation.Nullable;
20 import android.hardware.vibrator.IVibrator;
21 import android.os.Binder;
22 import android.os.IVibratorStateListener;
23 import android.os.RemoteCallbackList;
24 import android.os.RemoteException;
25 import android.os.VibratorInfo;
26 import android.os.vibrator.PrebakedSegment;
27 import android.os.vibrator.PrimitiveSegment;
28 import android.os.vibrator.RampSegment;
29 import android.util.Slog;
30 
31 import com.android.internal.annotations.GuardedBy;
32 import com.android.internal.annotations.VisibleForTesting;
33 
34 import libcore.util.NativeAllocationRegistry;
35 
36 /** Controls a single vibrator. */
37 final class VibratorController {
38     private static final String TAG = "VibratorController";
39 
40     private final Object mLock = new Object();
41 
42     @GuardedBy("mLock")
43     private final NativeWrapper mNativeWrapper;
44 
45     // Vibrator state listeners that support concurrent updates and broadcasts, but should lock
46     // while broadcasting to guarantee delivery order.
47     private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
48             new RemoteCallbackList<>();
49 
50     // Vibrator state variables that are updated from synchronized blocks but can be read anytime
51     // for a snippet of the current known vibrator state/info.
52     private volatile VibratorInfo mVibratorInfo;
53     private volatile boolean mVibratorInfoLoadSuccessful;
54     private volatile boolean mIsVibrating;
55     private volatile boolean mIsUnderExternalControl;
56     private volatile float mCurrentAmplitude;
57 
58     /** Listener for vibration completion callbacks from native. */
59     public interface OnVibrationCompleteListener {
60 
61         /** Callback triggered when vibration is complete. */
onComplete(int vibratorId, long vibrationId)62         void onComplete(int vibratorId, long vibrationId);
63     }
64 
VibratorController(int vibratorId, OnVibrationCompleteListener listener)65     VibratorController(int vibratorId, OnVibrationCompleteListener listener) {
66         this(vibratorId, listener, new NativeWrapper());
67     }
68 
69     @VisibleForTesting
VibratorController(int vibratorId, OnVibrationCompleteListener listener, NativeWrapper nativeWrapper)70     VibratorController(int vibratorId, OnVibrationCompleteListener listener,
71             NativeWrapper nativeWrapper) {
72         mNativeWrapper = nativeWrapper;
73         mNativeWrapper.init(vibratorId, listener);
74         VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId);
75         mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder);
76         mVibratorInfo = vibratorInfoBuilder.build();
77 
78         if (!mVibratorInfoLoadSuccessful) {
79             Slog.e(TAG,
80                     "Vibrator controller initialization failed to load some HAL info for vibrator "
81                             + vibratorId);
82         }
83     }
84 
85     /** Register state listener for this vibrator. */
registerVibratorStateListener(IVibratorStateListener listener)86     public boolean registerVibratorStateListener(IVibratorStateListener listener) {
87         final long token = Binder.clearCallingIdentity();
88         try {
89             // Register the listener and send the first state atomically, to avoid potentially
90             // out of order broadcasts in between.
91             synchronized (mLock) {
92                 if (!mVibratorStateListeners.register(listener)) {
93                     return false;
94                 }
95                 // Notify its callback after new client registered.
96                 notifyStateListener(listener, mIsVibrating);
97             }
98             return true;
99         } finally {
100             Binder.restoreCallingIdentity(token);
101         }
102     }
103 
104     /** Remove registered state listener for this vibrator. */
unregisterVibratorStateListener(IVibratorStateListener listener)105     public boolean unregisterVibratorStateListener(IVibratorStateListener listener) {
106         final long token = Binder.clearCallingIdentity();
107         try {
108             return mVibratorStateListeners.unregister(listener);
109         } finally {
110             Binder.restoreCallingIdentity(token);
111         }
112     }
113 
114     /** Reruns the query to the vibrator to load the {@link VibratorInfo}, if not yet successful. */
reloadVibratorInfoIfNeeded()115     public void reloadVibratorInfoIfNeeded() {
116         // Early check outside lock, for quick return.
117         if (mVibratorInfoLoadSuccessful) {
118             return;
119         }
120         synchronized (mLock) {
121             if (mVibratorInfoLoadSuccessful) {
122                 return;
123             }
124             int vibratorId = mVibratorInfo.getId();
125             VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId);
126             mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder);
127             mVibratorInfo = vibratorInfoBuilder.build();
128             if (!mVibratorInfoLoadSuccessful) {
129                 Slog.e(TAG, "Failed retry of HAL getInfo for vibrator " + vibratorId);
130             }
131         }
132     }
133 
134     /** Checks if the {@link VibratorInfo} was loaded from the vibrator hardware successfully. */
isVibratorInfoLoadSuccessful()135     boolean isVibratorInfoLoadSuccessful() {
136         return mVibratorInfoLoadSuccessful;
137     }
138 
139     /** Return the {@link VibratorInfo} representing the vibrator controlled by this instance. */
getVibratorInfo()140     public VibratorInfo getVibratorInfo() {
141         return mVibratorInfo;
142     }
143 
144     /**
145      * Return {@code true} is this vibrator is currently vibrating, false otherwise.
146      *
147      * <p>This state is controlled by calls to {@link #on} and {@link #off} methods, and is
148      * automatically notified to any registered {@link IVibratorStateListener} on change.
149      */
isVibrating()150     public boolean isVibrating() {
151         return mIsVibrating;
152     }
153 
154     /**
155      * Returns the current amplitude the device is vibrating.
156      *
157      * <p>This value is set to 1 by the method {@link #on(long, long)}, and can be updated via
158      * {@link #setAmplitude(float)} if called while the device is vibrating.
159      *
160      * <p>If the device is vibrating via any other {@link #on} method then the current amplitude is
161      * unknown and this will return -1.
162      *
163      * <p>If {@link #isVibrating()} is false then this will be zero.
164      */
getCurrentAmplitude()165     public float getCurrentAmplitude() {
166         return mCurrentAmplitude;
167     }
168 
169     /** Return {@code true} if this vibrator is under external control, false otherwise. */
isUnderExternalControl()170     public boolean isUnderExternalControl() {
171         return mIsUnderExternalControl;
172     }
173 
174     /**
175      * Check against this vibrator capabilities.
176      *
177      * @param capability one of IVibrator.CAP_*
178      * @return true if this vibrator has this capability, false otherwise
179      */
hasCapability(long capability)180     public boolean hasCapability(long capability) {
181         return mVibratorInfo.hasCapability(capability);
182     }
183 
184     /** Return {@code true} if the underlying vibrator is currently available, false otherwise. */
isAvailable()185     public boolean isAvailable() {
186         synchronized (mLock) {
187             return mNativeWrapper.isAvailable();
188         }
189     }
190 
191     /**
192      * Set the vibrator control to be external or not, based on given flag.
193      *
194      * <p>This will affect the state of {@link #isUnderExternalControl()}.
195      */
setExternalControl(boolean externalControl)196     public void setExternalControl(boolean externalControl) {
197         if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
198             return;
199         }
200         synchronized (mLock) {
201             mIsUnderExternalControl = externalControl;
202             mNativeWrapper.setExternalControl(externalControl);
203         }
204     }
205 
206     /**
207      * Update the predefined vibration effect saved with given id. This will remove the saved effect
208      * if given {@code effect} is {@code null}.
209      */
updateAlwaysOn(int id, @Nullable PrebakedSegment prebaked)210     public void updateAlwaysOn(int id, @Nullable PrebakedSegment prebaked) {
211         if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
212             return;
213         }
214         synchronized (mLock) {
215             if (prebaked == null) {
216                 mNativeWrapper.alwaysOnDisable(id);
217             } else {
218                 mNativeWrapper.alwaysOnEnable(id, prebaked.getEffectId(),
219                         prebaked.getEffectStrength());
220             }
221         }
222     }
223 
224     /** Set the vibration amplitude. This will NOT affect the state of {@link #isVibrating()}. */
setAmplitude(float amplitude)225     public void setAmplitude(float amplitude) {
226         synchronized (mLock) {
227             if (mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
228                 mNativeWrapper.setAmplitude(amplitude);
229             }
230             if (mIsVibrating) {
231                 mCurrentAmplitude = amplitude;
232             }
233         }
234     }
235 
236     /**
237      * Turn on the vibrator for {@code milliseconds} time, using {@code vibrationId} or completion
238      * callback to {@link OnVibrationCompleteListener}.
239      *
240      * <p>This will affect the state of {@link #isVibrating()}.
241      *
242      * @return The positive duration of the vibration started, if successful, zero if the vibrator
243      * do not support the input or a negative number if the operation failed.
244      */
on(long milliseconds, long vibrationId)245     public long on(long milliseconds, long vibrationId) {
246         synchronized (mLock) {
247             long duration = mNativeWrapper.on(milliseconds, vibrationId);
248             if (duration > 0) {
249                 mCurrentAmplitude = -1;
250                 notifyListenerOnVibrating(true);
251             }
252             return duration;
253         }
254     }
255 
256     /**
257      * Plays predefined vibration effect, using {@code vibrationId} or completion callback to
258      * {@link OnVibrationCompleteListener}.
259      *
260      * <p>This will affect the state of {@link #isVibrating()}.
261      *
262      * @return The positive duration of the vibration started, if successful, zero if the vibrator
263      * do not support the input or a negative number if the operation failed.
264      */
on(PrebakedSegment prebaked, long vibrationId)265     public long on(PrebakedSegment prebaked, long vibrationId) {
266         synchronized (mLock) {
267             long duration = mNativeWrapper.perform(prebaked.getEffectId(),
268                     prebaked.getEffectStrength(), vibrationId);
269             if (duration > 0) {
270                 mCurrentAmplitude = -1;
271                 notifyListenerOnVibrating(true);
272             }
273             return duration;
274         }
275     }
276 
277     /**
278      * Plays a composition of vibration primitives, using {@code vibrationId} or completion callback
279      * to {@link OnVibrationCompleteListener}.
280      *
281      * <p>This will affect the state of {@link #isVibrating()}.
282      *
283      * @return The positive duration of the vibration started, if successful, zero if the vibrator
284      * do not support the input or a negative number if the operation failed.
285      */
on(PrimitiveSegment[] primitives, long vibrationId)286     public long on(PrimitiveSegment[] primitives, long vibrationId) {
287         if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
288             return 0;
289         }
290         synchronized (mLock) {
291             long duration = mNativeWrapper.compose(primitives, vibrationId);
292             if (duration > 0) {
293                 mCurrentAmplitude = -1;
294                 notifyListenerOnVibrating(true);
295             }
296             return duration;
297         }
298     }
299 
300     /**
301      * Plays a composition of pwle primitives, using {@code vibrationId} or completion callback
302      * to {@link OnVibrationCompleteListener}.
303      *
304      * <p>This will affect the state of {@link #isVibrating()}.
305      *
306      * @return The duration of the effect playing, or 0 if unsupported.
307      */
on(RampSegment[] primitives, long vibrationId)308     public long on(RampSegment[] primitives, long vibrationId) {
309         if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
310             return 0;
311         }
312         synchronized (mLock) {
313             int braking = mVibratorInfo.getDefaultBraking();
314             long duration = mNativeWrapper.composePwle(primitives, braking, vibrationId);
315             if (duration > 0) {
316                 mCurrentAmplitude = -1;
317                 notifyListenerOnVibrating(true);
318             }
319             return duration;
320         }
321     }
322 
323     /** Turns off the vibrator. This will affect the state of {@link #isVibrating()}. */
off()324     public void off() {
325         synchronized (mLock) {
326             mNativeWrapper.off();
327             mCurrentAmplitude = 0;
328             notifyListenerOnVibrating(false);
329         }
330     }
331 
332     /**
333      * Resets the vibrator hardware to a default state.
334      * This turns the vibrator off, which will affect the state of {@link #isVibrating()}.
335      */
reset()336     public void reset() {
337         setExternalControl(false);
338         off();
339     }
340 
341     @Override
toString()342     public String toString() {
343         return "VibratorController{"
344                 + "mVibratorInfo=" + mVibratorInfo
345                 + ", mVibratorInfoLoadSuccessful=" + mVibratorInfoLoadSuccessful
346                 + ", mIsVibrating=" + mIsVibrating
347                 + ", mCurrentAmplitude=" + mCurrentAmplitude
348                 + ", mIsUnderExternalControl=" + mIsUnderExternalControl
349                 + ", mVibratorStateListeners count="
350                 + mVibratorStateListeners.getRegisteredCallbackCount()
351                 + '}';
352     }
353 
354     @GuardedBy("mLock")
notifyListenerOnVibrating(boolean isVibrating)355     private void notifyListenerOnVibrating(boolean isVibrating) {
356         if (mIsVibrating != isVibrating) {
357             mIsVibrating = isVibrating;
358             // The broadcast method is safe w.r.t. register/unregister listener methods, but lock
359             // is required here to guarantee delivery order.
360             mVibratorStateListeners.broadcast(
361                     listener -> notifyStateListener(listener, isVibrating));
362         }
363     }
364 
notifyStateListener(IVibratorStateListener listener, boolean isVibrating)365     private void notifyStateListener(IVibratorStateListener listener, boolean isVibrating) {
366         try {
367             listener.onVibrating(isVibrating);
368         } catch (RemoteException | RuntimeException e) {
369             Slog.e(TAG, "Vibrator state listener failed to call", e);
370         }
371     }
372 
373     /** Wrapper around the static-native methods of {@link VibratorController} for tests. */
374     @VisibleForTesting
375     public static class NativeWrapper {
376         /**
377          * Initializes the native part of this controller, creating a global reference to given
378          * {@link OnVibrationCompleteListener} and returns a newly allocated native pointer. This
379          * wrapper is responsible for deleting this pointer by calling the method pointed
380          * by {@link #getNativeFinalizer()}.
381          *
382          * <p><b>Note:</b> Make sure the given implementation of {@link OnVibrationCompleteListener}
383          * do not hold any strong reference to the instance responsible for deleting the returned
384          * pointer, to avoid creating a cyclic GC root reference.
385          */
nativeInit(int vibratorId, OnVibrationCompleteListener listener)386         private static native long nativeInit(int vibratorId, OnVibrationCompleteListener listener);
387 
388         /**
389          * Returns pointer to native function responsible for cleaning up the native pointer
390          * allocated and returned by {@link #nativeInit(int, OnVibrationCompleteListener)}.
391          */
getNativeFinalizer()392         private static native long getNativeFinalizer();
393 
isAvailable(long nativePtr)394         private static native boolean isAvailable(long nativePtr);
395 
on(long nativePtr, long milliseconds, long vibrationId)396         private static native long on(long nativePtr, long milliseconds, long vibrationId);
397 
off(long nativePtr)398         private static native void off(long nativePtr);
399 
setAmplitude(long nativePtr, float amplitude)400         private static native void setAmplitude(long nativePtr, float amplitude);
401 
performEffect(long nativePtr, long effect, long strength, long vibrationId)402         private static native long performEffect(long nativePtr, long effect, long strength,
403                 long vibrationId);
404 
performComposedEffect(long nativePtr, PrimitiveSegment[] effect, long vibrationId)405         private static native long performComposedEffect(long nativePtr, PrimitiveSegment[] effect,
406                 long vibrationId);
407 
performPwleEffect(long nativePtr, RampSegment[] effect, int braking, long vibrationId)408         private static native long performPwleEffect(long nativePtr, RampSegment[] effect,
409                 int braking, long vibrationId);
410 
setExternalControl(long nativePtr, boolean enabled)411         private static native void setExternalControl(long nativePtr, boolean enabled);
412 
alwaysOnEnable(long nativePtr, long id, long effect, long strength)413         private static native void alwaysOnEnable(long nativePtr, long id, long effect,
414                 long strength);
415 
alwaysOnDisable(long nativePtr, long id)416         private static native void alwaysOnDisable(long nativePtr, long id);
417 
getInfo(long nativePtr, VibratorInfo.Builder infoBuilder)418         private static native boolean getInfo(long nativePtr, VibratorInfo.Builder infoBuilder);
419 
420         private long mNativePtr = 0;
421 
422         /** Initializes native controller and allocation registry to destroy native instances. */
init(int vibratorId, OnVibrationCompleteListener listener)423         public void init(int vibratorId, OnVibrationCompleteListener listener) {
424             mNativePtr = nativeInit(vibratorId, listener);
425             long finalizerPtr = getNativeFinalizer();
426 
427             if (finalizerPtr != 0) {
428                 NativeAllocationRegistry registry =
429                         NativeAllocationRegistry.createMalloced(
430                                 VibratorController.class.getClassLoader(), finalizerPtr);
431                 registry.registerNativeAllocation(this, mNativePtr);
432             }
433         }
434 
435         /** Check if the vibrator is currently available. */
isAvailable()436         public boolean isAvailable() {
437             return isAvailable(mNativePtr);
438         }
439 
440         /** Turns vibrator on for given time. */
on(long milliseconds, long vibrationId)441         public long on(long milliseconds, long vibrationId) {
442             return on(mNativePtr, milliseconds, vibrationId);
443         }
444 
445         /** Turns vibrator off. */
off()446         public void off() {
447             off(mNativePtr);
448         }
449 
450         /** Sets the amplitude for the vibrator to run. */
setAmplitude(float amplitude)451         public void setAmplitude(float amplitude) {
452             setAmplitude(mNativePtr, amplitude);
453         }
454 
455         /** Turns vibrator on to perform one of the supported effects. */
perform(long effect, long strength, long vibrationId)456         public long perform(long effect, long strength, long vibrationId) {
457             return performEffect(mNativePtr, effect, strength, vibrationId);
458         }
459 
460         /** Turns vibrator on to perform effect composed of give primitives effect. */
compose(PrimitiveSegment[] primitives, long vibrationId)461         public long compose(PrimitiveSegment[] primitives, long vibrationId) {
462             return performComposedEffect(mNativePtr, primitives, vibrationId);
463         }
464 
465         /** Turns vibrator on to perform PWLE effect composed of given primitives. */
composePwle(RampSegment[] primitives, int braking, long vibrationId)466         public long composePwle(RampSegment[] primitives, int braking, long vibrationId) {
467             return performPwleEffect(mNativePtr, primitives, braking, vibrationId);
468         }
469 
470         /** Enabled the device vibrator to be controlled by another service. */
setExternalControl(boolean enabled)471         public void setExternalControl(boolean enabled) {
472             setExternalControl(mNativePtr, enabled);
473         }
474 
475         /** Enable always-on vibration with given id and effect. */
alwaysOnEnable(long id, long effect, long strength)476         public void alwaysOnEnable(long id, long effect, long strength) {
477             alwaysOnEnable(mNativePtr, id, effect, strength);
478         }
479 
480         /** Disable always-on vibration for given id. */
alwaysOnDisable(long id)481         public void alwaysOnDisable(long id) {
482             alwaysOnDisable(mNativePtr, id);
483         }
484 
485         /**
486          * Loads device vibrator metadata and returns true if all metadata was loaded successfully.
487          */
getInfo(VibratorInfo.Builder infoBuilder)488         public boolean getInfo(VibratorInfo.Builder infoBuilder) {
489             return getInfo(mNativePtr, infoBuilder);
490         }
491     }
492 }
493