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