• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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;
18 
19 import static android.os.VibrationEffect.Composition.PrimitiveEffect;
20 
21 import android.annotation.Nullable;
22 import android.app.ActivityManager;
23 import android.app.AppOpsManager;
24 import android.app.IUidObserver;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.pm.PackageManager;
30 import android.content.pm.PackageManagerInternal;
31 import android.content.res.Resources;
32 import android.database.ContentObserver;
33 import android.hardware.input.InputManager;
34 import android.hardware.vibrator.IVibrator;
35 import android.hardware.vibrator.V1_0.EffectStrength;
36 import android.icu.text.DateFormat;
37 import android.media.AudioManager;
38 import android.os.BatteryStats;
39 import android.os.Binder;
40 import android.os.ExternalVibration;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.IExternalVibratorService;
44 import android.os.IVibratorService;
45 import android.os.IVibratorStateListener;
46 import android.os.PowerManager;
47 import android.os.PowerManager.ServiceType;
48 import android.os.PowerManagerInternal;
49 import android.os.PowerSaveState;
50 import android.os.Process;
51 import android.os.RemoteCallbackList;
52 import android.os.RemoteException;
53 import android.os.ResultReceiver;
54 import android.os.ServiceManager;
55 import android.os.ShellCallback;
56 import android.os.ShellCommand;
57 import android.os.SystemClock;
58 import android.os.Trace;
59 import android.os.UserHandle;
60 import android.os.VibrationAttributes;
61 import android.os.VibrationEffect;
62 import android.os.Vibrator;
63 import android.os.WorkSource;
64 import android.provider.Settings;
65 import android.provider.Settings.SettingNotFoundException;
66 import android.util.DebugUtils;
67 import android.util.Slog;
68 import android.util.SparseArray;
69 import android.util.proto.ProtoOutputStream;
70 import android.view.InputDevice;
71 
72 import com.android.internal.annotations.GuardedBy;
73 import com.android.internal.app.IBatteryStats;
74 import com.android.internal.util.DumpUtils;
75 import com.android.internal.util.FrameworkStatsLog;
76 
77 import java.io.FileDescriptor;
78 import java.io.PrintWriter;
79 import java.util.ArrayList;
80 import java.util.Arrays;
81 import java.util.Date;
82 import java.util.LinkedList;
83 import java.util.List;
84 
85 public class VibratorService extends IVibratorService.Stub
86         implements InputManager.InputDeviceListener {
87     private static final String TAG = "VibratorService";
88     private static final boolean DEBUG = false;
89     private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
90 
91     private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
92 
93     // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
94     // and the default intensity for that type of vibration (i.e. current - default).
95     private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
96     private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
97     private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
98     private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
99     private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
100     private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
101 
102     // Gamma adjustments for scale levels.
103     private static final float SCALE_VERY_LOW_GAMMA = 2.0f;
104     private static final float SCALE_LOW_GAMMA = 1.5f;
105     private static final float SCALE_NONE_GAMMA = 1.0f;
106     private static final float SCALE_HIGH_GAMMA = 0.5f;
107     private static final float SCALE_VERY_HIGH_GAMMA = 0.25f;
108 
109     // Max amplitudes for scale levels. If one is not listed, then the max amplitude is the default
110     // max amplitude.
111     private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255
112     private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255
113 
114     // Default vibration attributes. Used when vibration is requested without attributes
115     private static final VibrationAttributes DEFAULT_ATTRIBUTES =
116             new VibrationAttributes.Builder().build();
117 
118     // If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration.
119     private static final long ASYNC_TIMEOUT_MULTIPLIER = 2;
120 
121 
122     // A mapping from the intensity adjustment to the scaling to apply, where the intensity
123     // adjustment is defined as the delta between the default intensity level and the user selected
124     // intensity level. It's important that we apply the scaling on the delta between the two so
125     // that the default intensity level applies no scaling to application provided effects.
126     private final SparseArray<ScaleLevel> mScaleLevels;
127     private final LinkedList<VibrationInfo> mPreviousRingVibrations;
128     private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
129     private final LinkedList<VibrationInfo> mPreviousAlarmVibrations;
130     private final LinkedList<ExternalVibration> mPreviousExternalVibrations;
131     private final LinkedList<VibrationInfo> mPreviousVibrations;
132     private final int mPreviousVibrationsLimit;
133     private final boolean mAllowPriorityVibrationsInLowPowerMode;
134     private final boolean mSupportsAmplitudeControl;
135     private final boolean mSupportsExternalControl;
136     private final List<Integer> mSupportedEffects;
137     private final long mCapabilities;
138     private final int mDefaultVibrationAmplitude;
139     private final SparseArray<VibrationEffect> mFallbackEffects;
140     private final SparseArray<Integer> mProcStatesCache = new SparseArray<>();
141     private final WorkSource mTmpWorkSource = new WorkSource();
142     private final Handler mH = new Handler();
143     private final Object mLock = new Object();
144 
145     private final Context mContext;
146     private final PowerManager.WakeLock mWakeLock;
147     private final AppOpsManager mAppOps;
148     private final IBatteryStats mBatteryStatsService;
149     private final String mSystemUiPackage;
150     private PowerManagerInternal mPowerManagerInternal;
151     private InputManager mIm;
152     private Vibrator mVibrator;
153     private SettingsObserver mSettingObserver;
154 
155     private volatile VibrateThread mThread;
156 
157     // mInputDeviceVibrators lock should be acquired after mLock, if both are
158     // to be acquired
159     private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<>();
160     private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
161     private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
162 
163     @GuardedBy("mLock")
164     private Vibration mCurrentVibration;
165     private int mCurVibUid = -1;
166     private ExternalVibration mCurrentExternalVibration;
167     private boolean mVibratorUnderExternalControl;
168     private boolean mLowPowerMode;
169     @GuardedBy("mLock")
170     private boolean mIsVibrating;
171     @GuardedBy("mLock")
172     private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
173                 new RemoteCallbackList<>();
174     private int mHapticFeedbackIntensity;
175     private int mNotificationIntensity;
176     private int mRingIntensity;
177     private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
178 
vibratorExists()179     static native boolean vibratorExists();
vibratorInit()180     static native void vibratorInit();
vibratorOn(long milliseconds)181     static native void vibratorOn(long milliseconds);
vibratorOff()182     static native void vibratorOff();
vibratorSupportsAmplitudeControl()183     static native boolean vibratorSupportsAmplitudeControl();
vibratorSetAmplitude(int amplitude)184     static native void vibratorSetAmplitude(int amplitude);
vibratorGetSupportedEffects()185     static native int[] vibratorGetSupportedEffects();
vibratorPerformEffect(long effect, long strength, Vibration vibration, boolean withCallback)186     static native long vibratorPerformEffect(long effect, long strength, Vibration vibration,
187             boolean withCallback);
vibratorPerformComposedEffect( VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration)188     static native void vibratorPerformComposedEffect(
189             VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration);
vibratorSupportsExternalControl()190     static native boolean vibratorSupportsExternalControl();
vibratorSetExternalControl(boolean enabled)191     static native void vibratorSetExternalControl(boolean enabled);
vibratorGetCapabilities()192     static native long vibratorGetCapabilities();
vibratorAlwaysOnEnable(long id, long effect, long strength)193     static native void vibratorAlwaysOnEnable(long id, long effect, long strength);
vibratorAlwaysOnDisable(long id)194     static native void vibratorAlwaysOnDisable(long id);
195 
196     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
197         @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
198                 int capability) {
199             mProcStatesCache.put(uid, procState);
200         }
201 
202         @Override public void onUidGone(int uid, boolean disabled) {
203             mProcStatesCache.delete(uid);
204         }
205 
206         @Override public void onUidActive(int uid) {
207         }
208 
209         @Override public void onUidIdle(int uid, boolean disabled) {
210         }
211 
212         @Override public void onUidCachedChanged(int uid, boolean cached) {
213         }
214     };
215 
216     private class Vibration implements IBinder.DeathRecipient {
217         public final IBinder token;
218         // Start time in CLOCK_BOOTTIME base.
219         public final long startTime;
220         // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
221         // with other system events, any duration calculations should be done use startTime so as
222         // not to be affected by discontinuities created by RTC adjustments.
223         public final long startTimeDebug;
224         public final VibrationAttributes attrs;
225         public final int uid;
226         public final String opPkg;
227         public final String reason;
228 
229         // The actual effect to be played.
230         public VibrationEffect effect;
231         // The original effect that was requested. This is non-null only when the original effect
232         // differs from the effect that's being played. Typically these two things differ because
233         // the effect was scaled based on the users vibration intensity settings.
234         public VibrationEffect originalEffect;
235 
Vibration(IBinder token, VibrationEffect effect, VibrationAttributes attrs, int uid, String opPkg, String reason)236         private Vibration(IBinder token, VibrationEffect effect,
237                 VibrationAttributes attrs, int uid, String opPkg, String reason) {
238             this.token = token;
239             this.effect = effect;
240             this.startTime = SystemClock.elapsedRealtime();
241             this.startTimeDebug = System.currentTimeMillis();
242             this.attrs = attrs;
243             this.uid = uid;
244             this.opPkg = opPkg;
245             this.reason = reason;
246         }
247 
binderDied()248         public void binderDied() {
249             synchronized (mLock) {
250                 if (this == mCurrentVibration) {
251                     doCancelVibrateLocked();
252                 }
253             }
254         }
255 
256         // Called by native
257         @SuppressWarnings("unused")
onComplete()258         private void onComplete() {
259             synchronized (mLock) {
260                 if (this == mCurrentVibration) {
261                     doCancelVibrateLocked();
262                 }
263             }
264         }
265 
hasTimeoutLongerThan(long millis)266         public boolean hasTimeoutLongerThan(long millis) {
267             final long duration = effect.getDuration();
268             return duration >= 0 && duration > millis;
269         }
270 
isHapticFeedback()271         public boolean isHapticFeedback() {
272             return VibratorService.this.isHapticFeedback(attrs.getUsage());
273         }
274 
isNotification()275         public boolean isNotification() {
276             return VibratorService.this.isNotification(attrs.getUsage());
277         }
278 
isRingtone()279         public boolean isRingtone() {
280             return VibratorService.this.isRingtone(attrs.getUsage());
281         }
282 
isAlarm()283         public boolean isAlarm() {
284             return VibratorService.this.isAlarm(attrs.getUsage());
285         }
286 
isFromSystem()287         public boolean isFromSystem() {
288             return uid == Process.SYSTEM_UID || uid == 0 || mSystemUiPackage.equals(opPkg);
289         }
290 
toInfo()291         public VibrationInfo toInfo() {
292             return new VibrationInfo(
293                     startTimeDebug, effect, originalEffect, attrs, uid, opPkg, reason);
294         }
295     }
296 
297     private static class VibrationInfo {
298         private final long mStartTimeDebug;
299         private final VibrationEffect mEffect;
300         private final VibrationEffect mOriginalEffect;
301         private final VibrationAttributes mAttrs;
302         private final int mUid;
303         private final String mOpPkg;
304         private final String mReason;
305 
VibrationInfo(long startTimeDebug, VibrationEffect effect, VibrationEffect originalEffect, VibrationAttributes attrs, int uid, String opPkg, String reason)306         VibrationInfo(long startTimeDebug, VibrationEffect effect,
307                 VibrationEffect originalEffect, VibrationAttributes attrs, int uid,
308                 String opPkg, String reason) {
309             mStartTimeDebug = startTimeDebug;
310             mEffect = effect;
311             mOriginalEffect = originalEffect;
312             mAttrs = attrs;
313             mUid = uid;
314             mOpPkg = opPkg;
315             mReason = reason;
316         }
317 
318         @Override
toString()319         public String toString() {
320             return new StringBuilder()
321                     .append("startTime: ")
322                     .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
323                     .append(", effect: ")
324                     .append(mEffect)
325                     .append(", originalEffect: ")
326                     .append(mOriginalEffect)
327                     .append(", attrs: ")
328                     .append(mAttrs)
329                     .append(", uid: ")
330                     .append(mUid)
331                     .append(", opPkg: ")
332                     .append(mOpPkg)
333                     .append(", reason: ")
334                     .append(mReason)
335                     .toString();
336         }
337 
dumpProto(ProtoOutputStream proto, long fieldId)338         void dumpProto(ProtoOutputStream proto, long fieldId) {
339             synchronized (this) {
340                 final long token = proto.start(fieldId);
341                 proto.write(VibrationProto.START_TIME, mStartTimeDebug);
342                 proto.end(token);
343             }
344         }
345     }
346 
347     private static final class ScaleLevel {
348         public final float gamma;
349         public final int maxAmplitude;
350 
ScaleLevel(float gamma)351         public ScaleLevel(float gamma) {
352             this(gamma, VibrationEffect.MAX_AMPLITUDE);
353         }
354 
ScaleLevel(float gamma, int maxAmplitude)355         public ScaleLevel(float gamma, int maxAmplitude) {
356             this.gamma = gamma;
357             this.maxAmplitude = maxAmplitude;
358         }
359 
360         @Override
toString()361         public String toString() {
362             return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}";
363         }
364     }
365 
VibratorService(Context context)366     VibratorService(Context context) {
367         vibratorInit();
368         // Reset the hardware to a default state, in case this is a runtime
369         // restart instead of a fresh boot.
370         vibratorOff();
371 
372         mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
373         mSupportsExternalControl = vibratorSupportsExternalControl();
374         mSupportedEffects = asList(vibratorGetSupportedEffects());
375         mCapabilities = vibratorGetCapabilities();
376 
377         mContext = context;
378         PowerManager pm = context.getSystemService(PowerManager.class);
379         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
380         mWakeLock.setReferenceCounted(true);
381 
382         mAppOps = mContext.getSystemService(AppOpsManager.class);
383         mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
384                 BatteryStats.SERVICE_NAME));
385         mSystemUiPackage = LocalServices.getService(PackageManagerInternal.class)
386                 .getSystemUiServiceComponent().getPackageName();
387 
388         mPreviousVibrationsLimit = mContext.getResources().getInteger(
389                 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
390 
391         mDefaultVibrationAmplitude = mContext.getResources().getInteger(
392                 com.android.internal.R.integer.config_defaultVibrationAmplitude);
393 
394         mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
395                 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
396 
397         mPreviousRingVibrations = new LinkedList<>();
398         mPreviousNotificationVibrations = new LinkedList<>();
399         mPreviousAlarmVibrations = new LinkedList<>();
400         mPreviousVibrations = new LinkedList<>();
401         mPreviousExternalVibrations = new LinkedList<>();
402 
403         IntentFilter filter = new IntentFilter();
404         filter.addAction(Intent.ACTION_SCREEN_OFF);
405         context.registerReceiver(mIntentReceiver, filter);
406 
407         VibrationEffect clickEffect = createEffectFromResource(
408                 com.android.internal.R.array.config_virtualKeyVibePattern);
409         VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
410                 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
411         VibrationEffect heavyClickEffect = createEffectFromResource(
412                 com.android.internal.R.array.config_longPressVibePattern);
413         VibrationEffect tickEffect = createEffectFromResource(
414                 com.android.internal.R.array.config_clockTickVibePattern);
415 
416         mFallbackEffects = new SparseArray<>();
417         mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
418         mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
419         mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
420         mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
421 
422         mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK,
423                 VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
424 
425         mScaleLevels = new SparseArray<>();
426         mScaleLevels.put(SCALE_VERY_LOW,
427                 new ScaleLevel(SCALE_VERY_LOW_GAMMA, SCALE_VERY_LOW_MAX_AMPLITUDE));
428         mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_LOW_GAMMA, SCALE_LOW_MAX_AMPLITUDE));
429         mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA));
430         mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA));
431         mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA));
432 
433         ServiceManager.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
434     }
435 
createEffectFromResource(int resId)436     private VibrationEffect createEffectFromResource(int resId) {
437         long[] timings = getLongIntArray(mContext.getResources(), resId);
438         return createEffectFromTimings(timings);
439     }
440 
createEffectFromTimings(long[] timings)441     private static VibrationEffect createEffectFromTimings(long[] timings) {
442         if (timings == null || timings.length == 0) {
443             return null;
444         } else if (timings.length == 1) {
445             return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
446         } else {
447             return VibrationEffect.createWaveform(timings, -1);
448         }
449     }
450 
systemReady()451     public void systemReady() {
452         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
453         try {
454             mIm = mContext.getSystemService(InputManager.class);
455             mVibrator = mContext.getSystemService(Vibrator.class);
456             mSettingObserver = new SettingsObserver(mH);
457 
458             mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
459             mPowerManagerInternal.registerLowPowerModeObserver(
460                     new PowerManagerInternal.LowPowerModeListener() {
461                         @Override
462                         public int getServiceType() {
463                             return ServiceType.VIBRATION;
464                         }
465 
466                         @Override
467                         public void onLowPowerModeChanged(PowerSaveState result) {
468                             updateVibrators();
469                         }
470             });
471 
472             mContext.getContentResolver().registerContentObserver(
473                     Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
474                     true, mSettingObserver, UserHandle.USER_ALL);
475 
476             mContext.getContentResolver().registerContentObserver(
477                     Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
478                     true, mSettingObserver, UserHandle.USER_ALL);
479 
480             mContext.getContentResolver().registerContentObserver(
481                     Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
482                     true, mSettingObserver, UserHandle.USER_ALL);
483 
484             mContext.getContentResolver().registerContentObserver(
485                     Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
486                     true, mSettingObserver, UserHandle.USER_ALL);
487 
488             mContext.getContentResolver().registerContentObserver(
489                     Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
490                     true, mSettingObserver, UserHandle.USER_ALL);
491 
492             mContext.registerReceiver(new BroadcastReceiver() {
493                 @Override
494                 public void onReceive(Context context, Intent intent) {
495                     updateVibrators();
496                 }
497             }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
498 
499             try {
500                 ActivityManager.getService().registerUidObserver(mUidObserver,
501                         ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
502                         ActivityManager.PROCESS_STATE_UNKNOWN, null);
503             } catch (RemoteException e) {
504                 // ignored; both services live in system_server
505             }
506 
507             updateVibrators();
508         } finally {
509             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
510         }
511     }
512 
513     private final class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler)514         public SettingsObserver(Handler handler) {
515             super(handler);
516         }
517 
518         @Override
onChange(boolean SelfChange)519         public void onChange(boolean SelfChange) {
520             updateVibrators();
521         }
522     }
523 
524     @Override // Binder call
hasVibrator()525     public boolean hasVibrator() {
526         return doVibratorExists();
527     }
528 
529     @Override // Binder call
isVibrating()530     public boolean isVibrating() {
531         if (!hasPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE)) {
532             throw new SecurityException("Requires ACCESS_VIBRATOR_STATE permission");
533         }
534         synchronized (mLock) {
535             return mIsVibrating;
536         }
537     }
538 
539     @GuardedBy("mLock")
notifyStateListenerLocked(IVibratorStateListener listener)540     private void notifyStateListenerLocked(IVibratorStateListener listener) {
541         try {
542             listener.onVibrating(mIsVibrating);
543         } catch (RemoteException | RuntimeException e) {
544             Slog.e(TAG, "Vibrator callback failed to call", e);
545         }
546     }
547 
548     @GuardedBy("mLock")
notifyStateListenersLocked()549     private void notifyStateListenersLocked() {
550         final int length = mVibratorStateListeners.beginBroadcast();
551         try {
552             for (int i = 0; i < length; i++) {
553                 final IVibratorStateListener listener =
554                         mVibratorStateListeners.getBroadcastItem(i);
555                 notifyStateListenerLocked(listener);
556             }
557         } finally {
558             mVibratorStateListeners.finishBroadcast();
559         }
560     }
561 
562     @Override // Binder call
registerVibratorStateListener(IVibratorStateListener listener)563     public boolean registerVibratorStateListener(IVibratorStateListener listener) {
564         if (!hasPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE)) {
565             throw new SecurityException("Requires ACCESS_VIBRATOR_STATE permission");
566         }
567         synchronized (mLock) {
568             final long token = Binder.clearCallingIdentity();
569             try {
570                 if (!mVibratorStateListeners.register(listener)) {
571                     return false;
572                 }
573                 // Notify its callback after new client registered.
574                 notifyStateListenerLocked(listener);
575                 return true;
576             } finally {
577                 Binder.restoreCallingIdentity(token);
578             }
579         }
580     }
581 
582     @Override // Binder call
583     @GuardedBy("mLock")
unregisterVibratorStateListener(IVibratorStateListener listener)584     public boolean unregisterVibratorStateListener(IVibratorStateListener listener) {
585         if (!hasPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE)) {
586             throw new SecurityException("Requires ACCESS_VIBRATOR_STATE permission");
587         }
588         synchronized (mLock) {
589             final long token = Binder.clearCallingIdentity();
590             try {
591                 return mVibratorStateListeners.unregister(listener);
592             } finally {
593                 Binder.restoreCallingIdentity(token);
594             }
595         }
596     }
597 
598     @Override // Binder call
hasAmplitudeControl()599     public boolean hasAmplitudeControl() {
600         synchronized (mInputDeviceVibrators) {
601             // Input device vibrators don't support amplitude controls yet, but are still used over
602             // the system vibrator when connected.
603             return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
604         }
605     }
606 
607     @Override // Binder call
areEffectsSupported(int[] effectIds)608     public int[] areEffectsSupported(int[] effectIds) {
609         int[] supported = new int[effectIds.length];
610         if (mSupportedEffects == null) {
611             Arrays.fill(supported, Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN);
612         } else {
613             for (int i = 0; i < effectIds.length; i++) {
614                 supported[i] = mSupportedEffects.contains(effectIds[i])
615                         ? Vibrator.VIBRATION_EFFECT_SUPPORT_YES
616                         : Vibrator.VIBRATION_EFFECT_SUPPORT_NO;
617             }
618         }
619         return supported;
620     }
621 
622     @Override // Binder call
arePrimitivesSupported(int[] primitiveIds)623     public boolean[] arePrimitivesSupported(int[] primitiveIds) {
624         boolean[] supported = new boolean[primitiveIds.length];
625         if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
626             Arrays.fill(supported, true);
627         }
628         return supported;
629     }
630 
631 
asList(int... vals)632     private static List<Integer> asList(int... vals) {
633         if (vals == null) {
634             return null;
635         }
636         List<Integer> l = new ArrayList<>(vals.length);
637         for (int val : vals) {
638             l.add(val);
639         }
640         return l;
641     }
642 
643     @Override // Binder call
setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, VibrationAttributes attrs)644     public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect,
645             VibrationAttributes attrs) {
646         if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) {
647             throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission");
648         }
649         if (!hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
650             Slog.e(TAG, "Always-on effects not supported.");
651             return false;
652         }
653         if (effect == null) {
654             synchronized (mLock) {
655                 mAlwaysOnEffects.delete(alwaysOnId);
656                 vibratorAlwaysOnDisable(alwaysOnId);
657             }
658         } else {
659             if (!verifyVibrationEffect(effect)) {
660                 return false;
661             }
662             if (!(effect instanceof VibrationEffect.Prebaked)) {
663                 Slog.e(TAG, "Only prebaked effects supported for always-on.");
664                 return false;
665             }
666             attrs = fixupVibrationAttributes(attrs);
667             synchronized (mLock) {
668                 Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null);
669                 mAlwaysOnEffects.put(alwaysOnId, vib);
670                 updateAlwaysOnLocked(alwaysOnId, vib);
671             }
672         }
673         return true;
674     }
675 
verifyIncomingUid(int uid)676     private void verifyIncomingUid(int uid) {
677         if (uid == Binder.getCallingUid()) {
678             return;
679         }
680         if (Binder.getCallingPid() == Process.myPid()) {
681             return;
682         }
683         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
684                 Binder.getCallingPid(), Binder.getCallingUid(), null);
685     }
686 
687     /**
688      * Validate the incoming VibrationEffect.
689      *
690      * We can't throw exceptions here since we might be called from some system_server component,
691      * which would bring the whole system down.
692      *
693      * @return whether the VibrationEffect is valid
694      */
verifyVibrationEffect(VibrationEffect effect)695     private static boolean verifyVibrationEffect(VibrationEffect effect) {
696         if (effect == null) {
697             // Effect must not be null.
698             Slog.wtf(TAG, "effect must not be null");
699             return false;
700         }
701         try {
702             effect.validate();
703         } catch (Exception e) {
704             Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
705             return false;
706         }
707         return true;
708     }
709 
fixupVibrationAttributes(VibrationAttributes attrs)710     private VibrationAttributes fixupVibrationAttributes(VibrationAttributes attrs) {
711         if (attrs == null) {
712             attrs = DEFAULT_ATTRIBUTES;
713         }
714         if (shouldBypassDnd(attrs)) {
715             if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
716                     || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
717                     || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
718                 final int flags = attrs.getFlags()
719                         & ~VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
720                 attrs = new VibrationAttributes.Builder(attrs).replaceFlags(flags).build();
721             }
722         }
723 
724         return attrs;
725     }
726 
getLongIntArray(Resources r, int resid)727     private static long[] getLongIntArray(Resources r, int resid) {
728         int[] ar = r.getIntArray(resid);
729         if (ar == null) {
730             return null;
731         }
732         long[] out = new long[ar.length];
733         for (int i = 0; i < ar.length; i++) {
734             out[i] = ar[i];
735         }
736         return out;
737     }
738 
739     @Override // Binder call
vibrate(int uid, String opPkg, VibrationEffect effect, @Nullable VibrationAttributes attrs, String reason, IBinder token)740     public void vibrate(int uid, String opPkg, VibrationEffect effect,
741             @Nullable VibrationAttributes attrs, String reason, IBinder token) {
742         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
743         try {
744             if (!hasPermission(android.Manifest.permission.VIBRATE)) {
745                 throw new SecurityException("Requires VIBRATE permission");
746             }
747             if (token == null) {
748                 Slog.e(TAG, "token must not be null");
749                 return;
750             }
751             verifyIncomingUid(uid);
752             if (!verifyVibrationEffect(effect)) {
753                 return;
754             }
755 
756             attrs = fixupVibrationAttributes(attrs);
757 
758             // If our current vibration is longer than the new vibration and is the same amplitude,
759             // then just let the current one finish.
760             synchronized (mLock) {
761                 if (effect instanceof VibrationEffect.OneShot
762                         && mCurrentVibration != null
763                         && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
764                     VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
765                     VibrationEffect.OneShot currentOneShot =
766                             (VibrationEffect.OneShot) mCurrentVibration.effect;
767                     if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
768                             && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
769                         if (DEBUG) {
770                             Slog.d(TAG,
771                                     "Ignoring incoming vibration in favor of current vibration");
772                         }
773                         return;
774                     }
775                 }
776 
777 
778                 // If something has external control of the vibrator, assume that it's more
779                 // important for now.
780                 if (mCurrentExternalVibration != null) {
781                     if (DEBUG) {
782                         Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
783                     }
784                     return;
785                 }
786 
787                 // If the current vibration is repeating and the incoming one is non-repeating,
788                 // then ignore the non-repeating vibration. This is so that we don't cancel
789                 // vibrations that are meant to grab the attention of the user, like ringtones and
790                 // alarms, in favor of one-shot vibrations that are likely quite short.
791                 if (!isRepeatingVibration(effect)
792                         && mCurrentVibration != null
793                         && isRepeatingVibration(mCurrentVibration.effect)) {
794                     if (DEBUG) {
795                         Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
796                     }
797                     return;
798                 }
799 
800                 Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason);
801                 if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
802                         > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
803                         && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
804                     Slog.e(TAG, "Ignoring incoming vibration as process with"
805                             + " uid= " + uid + " is background,"
806                             + " attrs= " + vib.attrs);
807                     return;
808                 }
809                 linkVibration(vib);
810                 long ident = Binder.clearCallingIdentity();
811                 try {
812                     doCancelVibrateLocked();
813                     startVibrationLocked(vib);
814                     addToPreviousVibrationsLocked(vib);
815                 } finally {
816                     Binder.restoreCallingIdentity(ident);
817                 }
818             }
819         } finally {
820             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
821         }
822     }
823 
hasPermission(String permission)824     private boolean hasPermission(String permission) {
825         return mContext.checkCallingOrSelfPermission(permission)
826                 == PackageManager.PERMISSION_GRANTED;
827     }
828 
isRepeatingVibration(VibrationEffect effect)829     private static boolean isRepeatingVibration(VibrationEffect effect) {
830         return effect.getDuration() == Long.MAX_VALUE;
831     }
832 
addToPreviousVibrationsLocked(Vibration vib)833     private void addToPreviousVibrationsLocked(Vibration vib) {
834         final LinkedList<VibrationInfo> previousVibrations;
835         if (vib.isRingtone()) {
836             previousVibrations = mPreviousRingVibrations;
837         } else if (vib.isNotification()) {
838             previousVibrations = mPreviousNotificationVibrations;
839         } else if (vib.isAlarm()) {
840             previousVibrations = mPreviousAlarmVibrations;
841         } else {
842             previousVibrations = mPreviousVibrations;
843         }
844 
845         if (previousVibrations.size() > mPreviousVibrationsLimit) {
846             previousVibrations.removeFirst();
847         }
848         previousVibrations.addLast(vib.toInfo());
849     }
850 
851     @Override // Binder call
cancelVibrate(IBinder token)852     public void cancelVibrate(IBinder token) {
853         mContext.enforceCallingOrSelfPermission(
854                 android.Manifest.permission.VIBRATE,
855                 "cancelVibrate");
856 
857         synchronized (mLock) {
858             if (mCurrentVibration != null && mCurrentVibration.token == token) {
859                 if (DEBUG) {
860                     Slog.d(TAG, "Canceling vibration.");
861                 }
862                 long ident = Binder.clearCallingIdentity();
863                 try {
864                     doCancelVibrateLocked();
865                 } finally {
866                     Binder.restoreCallingIdentity(ident);
867                 }
868             }
869         }
870     }
871 
872     private final Runnable mVibrationEndRunnable = new Runnable() {
873         @Override
874         public void run() {
875             onVibrationFinished();
876         }
877     };
878 
879     @GuardedBy("mLock")
doCancelVibrateLocked()880     private void doCancelVibrateLocked() {
881         Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
882         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
883         try {
884             mH.removeCallbacks(mVibrationEndRunnable);
885             if (mThread != null) {
886                 mThread.cancel();
887                 mThread = null;
888             }
889             if (mCurrentExternalVibration != null) {
890                 mCurrentExternalVibration.mute();
891                 mCurrentExternalVibration = null;
892                 setVibratorUnderExternalControl(false);
893             }
894             doVibratorOff();
895             reportFinishVibrationLocked();
896         } finally {
897             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
898         }
899     }
900 
901     // Callback for whenever the current vibration has finished played out
onVibrationFinished()902     public void onVibrationFinished() {
903         if (DEBUG) {
904             Slog.e(TAG, "Vibration finished, cleaning up");
905         }
906         synchronized (mLock) {
907             // Make sure the vibration is really done. This also reports that the vibration is
908             // finished.
909             doCancelVibrateLocked();
910         }
911     }
912 
913     @GuardedBy("mLock")
startVibrationLocked(final Vibration vib)914     private void startVibrationLocked(final Vibration vib) {
915         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
916         try {
917             final int intensity = getCurrentIntensityLocked(vib);
918             if (!shouldVibrate(vib, intensity)) {
919                 return;
920             }
921             applyVibrationIntensityScalingLocked(vib, intensity);
922             startVibrationInnerLocked(vib);
923         } finally {
924             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
925         }
926     }
927 
928     @GuardedBy("mLock")
startVibrationInnerLocked(Vibration vib)929     private void startVibrationInnerLocked(Vibration vib) {
930         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
931         try {
932             mCurrentVibration = vib;
933             if (vib.effect instanceof VibrationEffect.OneShot) {
934                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
935                 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
936                 doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.attrs);
937                 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
938             } else if (vib.effect instanceof VibrationEffect.Waveform) {
939                 // mThread better be null here. doCancelVibrate should always be
940                 // called before startNextVibrationLocked or startVibrationLocked.
941                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
942                 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
943                 mThread = new VibrateThread(waveform, vib.uid, vib.attrs);
944                 mThread.start();
945             } else if (vib.effect instanceof VibrationEffect.Prebaked) {
946                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
947                 long timeout = doVibratorPrebakedEffectLocked(vib);
948                 if (timeout > 0) {
949                     mH.postDelayed(mVibrationEndRunnable, timeout);
950                 }
951             } else if (vib.effect instanceof  VibrationEffect.Composed) {
952                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
953                 doVibratorComposedEffectLocked(vib);
954                 // FIXME: We rely on the completion callback here, but I don't think we require that
955                 // devices which support composition also support the completion callback. If we
956                 // ever get a device that supports the former but not the latter, then we have no
957                 // real way of knowing how long a given effect should last.
958                 mH.postDelayed(mVibrationEndRunnable, 10000);
959             } else {
960                 Slog.e(TAG, "Unknown vibration type, ignoring");
961             }
962         } finally {
963             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
964         }
965     }
966 
isAllowedToVibrateLocked(Vibration vib)967     private boolean isAllowedToVibrateLocked(Vibration vib) {
968         if (!mLowPowerMode) {
969             return true;
970         }
971 
972         int usage = vib.attrs.getUsage();
973         return usage == VibrationAttributes.USAGE_RINGTONE
974                 || usage == VibrationAttributes.USAGE_ALARM
975                 || usage == VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
976     }
977 
getCurrentIntensityLocked(Vibration vib)978     private int getCurrentIntensityLocked(Vibration vib) {
979         if (vib.isRingtone()) {
980             return mRingIntensity;
981         } else if (vib.isNotification()) {
982             return mNotificationIntensity;
983         } else if (vib.isHapticFeedback()) {
984             return mHapticFeedbackIntensity;
985         } else if (vib.isAlarm()) {
986             return Vibrator.VIBRATION_INTENSITY_HIGH;
987         } else {
988             return Vibrator.VIBRATION_INTENSITY_MEDIUM;
989         }
990     }
991 
992     /**
993      * Scale the vibration effect by the intensity as appropriate based its intent.
994      */
applyVibrationIntensityScalingLocked(Vibration vib, int intensity)995     private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
996         if (vib.effect instanceof VibrationEffect.Prebaked) {
997             // Prebaked effects are always just a direct translation from intensity to
998             // EffectStrength.
999             VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect;
1000             prebaked.setEffectStrength(intensityToEffectStrength(intensity));
1001             return;
1002         }
1003 
1004         final int defaultIntensity;
1005         if (vib.isRingtone()) {
1006             defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
1007         } else if (vib.isNotification()) {
1008             defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
1009         } else if (vib.isHapticFeedback()) {
1010             defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
1011         } else if (vib.isAlarm()) {
1012             defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
1013         } else {
1014             // If we don't know what kind of vibration we're playing then just skip scaling for
1015             // now.
1016             return;
1017         }
1018 
1019         final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
1020         if (scale == null) {
1021             // We should have scaling levels for all cases, so not being able to scale because of a
1022             // missing level is unexpected.
1023             Slog.e(TAG, "No configured scaling level!"
1024                     + " (current=" + intensity + ", default= " + defaultIntensity + ")");
1025             return;
1026         }
1027 
1028         VibrationEffect scaledEffect = null;
1029         if (vib.effect instanceof VibrationEffect.OneShot) {
1030             VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
1031             oneShot = oneShot.resolve(mDefaultVibrationAmplitude);
1032             scaledEffect = oneShot.scale(scale.gamma, scale.maxAmplitude);
1033         } else if (vib.effect instanceof VibrationEffect.Waveform) {
1034             VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
1035             waveform = waveform.resolve(mDefaultVibrationAmplitude);
1036             scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
1037         } else if (vib.effect instanceof VibrationEffect.Composed) {
1038             VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.effect;
1039             scaledEffect = composed.scale(scale.gamma, scale.maxAmplitude);
1040         } else {
1041             Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
1042         }
1043 
1044         if (scaledEffect != null) {
1045             vib.originalEffect = vib.effect;
1046             vib.effect = scaledEffect;
1047         }
1048     }
1049 
shouldVibrateForRingtone()1050     private boolean shouldVibrateForRingtone() {
1051         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
1052         int ringerMode = audioManager.getRingerModeInternal();
1053         // "Also vibrate for calls" Setting in Sound
1054         if (Settings.System.getInt(
1055                 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
1056             return ringerMode != AudioManager.RINGER_MODE_SILENT;
1057         } else if (Settings.Global.getInt(
1058                     mContext.getContentResolver(), Settings.Global.APPLY_RAMPING_RINGER, 0) != 0) {
1059             return ringerMode != AudioManager.RINGER_MODE_SILENT;
1060         } else {
1061             return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
1062         }
1063     }
1064 
shouldBypassDnd(VibrationAttributes attrs)1065     private static boolean shouldBypassDnd(VibrationAttributes attrs) {
1066         return attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY);
1067     }
1068 
getAppOpMode(int uid, String packageName, VibrationAttributes attrs)1069     private int getAppOpMode(int uid, String packageName, VibrationAttributes attrs) {
1070         int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
1071                 attrs.getAudioAttributes().getUsage(), uid, packageName);
1072         if (mode == AppOpsManager.MODE_ALLOWED) {
1073             mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, uid, packageName);
1074         }
1075 
1076         if (mode == AppOpsManager.MODE_IGNORED && shouldBypassDnd(attrs)) {
1077             // If we're just ignoring the vibration op then this is set by DND and we should ignore
1078             // if we're asked to bypass. AppOps won't be able to record this operation, so make
1079             // sure we at least note it in the logs for debugging.
1080             Slog.d(TAG, "Bypassing DND for vibrate from uid " + uid);
1081             mode = AppOpsManager.MODE_ALLOWED;
1082         }
1083         return mode;
1084     }
1085 
shouldVibrate(Vibration vib, int intensity)1086     private boolean shouldVibrate(Vibration vib, int intensity) {
1087         if (!isAllowedToVibrateLocked(vib)) {
1088             return false;
1089         }
1090 
1091         if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
1092             return false;
1093         }
1094 
1095         if (vib.isRingtone() && !shouldVibrateForRingtone()) {
1096             if (DEBUG) {
1097                 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
1098             }
1099             return false;
1100         }
1101 
1102         final int mode = getAppOpMode(vib.uid, vib.opPkg, vib.attrs);
1103         if (mode != AppOpsManager.MODE_ALLOWED) {
1104             if (mode == AppOpsManager.MODE_ERRORED) {
1105                 // We might be getting calls from within system_server, so we don't actually
1106                 // want to throw a SecurityException here.
1107                 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
1108             }
1109             return false;
1110         }
1111 
1112         return true;
1113     }
1114 
1115     @GuardedBy("mLock")
reportFinishVibrationLocked()1116     private void reportFinishVibrationLocked() {
1117         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
1118         try {
1119             if (mCurrentVibration != null) {
1120                 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
1121                         mCurrentVibration.opPkg);
1122                 unlinkVibration(mCurrentVibration);
1123                 mCurrentVibration = null;
1124             }
1125         } finally {
1126             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1127         }
1128     }
1129 
linkVibration(Vibration vib)1130     private void linkVibration(Vibration vib) {
1131         // Only link against waveforms since they potentially don't have a finish if
1132         // they're repeating. Let other effects just play out until they're done.
1133         if (vib.effect instanceof VibrationEffect.Waveform) {
1134             try {
1135                 vib.token.linkToDeath(vib, 0);
1136             } catch (RemoteException e) {
1137                 return;
1138             }
1139         }
1140     }
1141 
unlinkVibration(Vibration vib)1142     private void unlinkVibration(Vibration vib) {
1143         if (vib.effect instanceof VibrationEffect.Waveform) {
1144             vib.token.unlinkToDeath(vib, 0);
1145         }
1146     }
1147 
updateVibrators()1148     private void updateVibrators() {
1149         synchronized (mLock) {
1150             boolean devicesUpdated = updateInputDeviceVibratorsLocked();
1151             boolean lowPowerModeUpdated = updateLowPowerModeLocked();
1152             updateVibrationIntensityLocked();
1153 
1154             if (devicesUpdated || lowPowerModeUpdated) {
1155                 // If the state changes out from under us then just reset.
1156                 doCancelVibrateLocked();
1157             }
1158 
1159             updateAlwaysOnLocked();
1160         }
1161     }
1162 
updateInputDeviceVibratorsLocked()1163     private boolean updateInputDeviceVibratorsLocked() {
1164         boolean changed = false;
1165         boolean vibrateInputDevices = false;
1166         try {
1167             vibrateInputDevices = Settings.System.getIntForUser(
1168                     mContext.getContentResolver(),
1169                     Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
1170         } catch (SettingNotFoundException snfe) {
1171         }
1172         if (vibrateInputDevices != mVibrateInputDevicesSetting) {
1173             changed = true;
1174             mVibrateInputDevicesSetting = vibrateInputDevices;
1175         }
1176 
1177         if (mVibrateInputDevicesSetting) {
1178             if (!mInputDeviceListenerRegistered) {
1179                 mInputDeviceListenerRegistered = true;
1180                 mIm.registerInputDeviceListener(this, mH);
1181             }
1182         } else {
1183             if (mInputDeviceListenerRegistered) {
1184                 mInputDeviceListenerRegistered = false;
1185                 mIm.unregisterInputDeviceListener(this);
1186             }
1187         }
1188 
1189         mInputDeviceVibrators.clear();
1190         if (mVibrateInputDevicesSetting) {
1191             int[] ids = mIm.getInputDeviceIds();
1192             for (int i = 0; i < ids.length; i++) {
1193                 InputDevice device = mIm.getInputDevice(ids[i]);
1194                 Vibrator vibrator = device.getVibrator();
1195                 if (vibrator.hasVibrator()) {
1196                     mInputDeviceVibrators.add(vibrator);
1197                 }
1198             }
1199             return true;
1200         }
1201         return changed;
1202     }
1203 
updateLowPowerModeLocked()1204     private boolean updateLowPowerModeLocked() {
1205         boolean lowPowerMode = mPowerManagerInternal
1206                 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
1207         if (lowPowerMode != mLowPowerMode) {
1208             mLowPowerMode = lowPowerMode;
1209             return true;
1210         }
1211         return false;
1212     }
1213 
updateVibrationIntensityLocked()1214     private void updateVibrationIntensityLocked() {
1215         mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
1216                 Settings.System.HAPTIC_FEEDBACK_INTENSITY,
1217                 mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
1218         mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
1219                 Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
1220                 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
1221         mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
1222                 Settings.System.RING_VIBRATION_INTENSITY,
1223                 mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
1224     }
1225 
updateAlwaysOnLocked(int id, Vibration vib)1226     private void updateAlwaysOnLocked(int id, Vibration vib) {
1227         final int intensity = getCurrentIntensityLocked(vib);
1228         if (!shouldVibrate(vib, intensity)) {
1229             vibratorAlwaysOnDisable(id);
1230         } else {
1231             final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
1232             final int strength = intensityToEffectStrength(intensity);
1233             vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
1234         }
1235     }
1236 
updateAlwaysOnLocked()1237     private void updateAlwaysOnLocked() {
1238         for (int i = 0; i < mAlwaysOnEffects.size(); i++) {
1239             int id = mAlwaysOnEffects.keyAt(i);
1240             Vibration vib = mAlwaysOnEffects.valueAt(i);
1241             updateAlwaysOnLocked(id, vib);
1242         }
1243     }
1244 
1245     @Override
onInputDeviceAdded(int deviceId)1246     public void onInputDeviceAdded(int deviceId) {
1247         updateVibrators();
1248     }
1249 
1250     @Override
onInputDeviceChanged(int deviceId)1251     public void onInputDeviceChanged(int deviceId) {
1252         updateVibrators();
1253     }
1254 
1255     @Override
onInputDeviceRemoved(int deviceId)1256     public void onInputDeviceRemoved(int deviceId) {
1257         updateVibrators();
1258     }
1259 
doVibratorExists()1260     private boolean doVibratorExists() {
1261         // For now, we choose to ignore the presence of input devices that have vibrators
1262         // when reporting whether the device has a vibrator.  Applications often use this
1263         // information to decide whether to enable certain features so they expect the
1264         // result of hasVibrator() to be constant.  For now, just report whether
1265         // the device has a built-in vibrator.
1266         //synchronized (mInputDeviceVibrators) {
1267         //    return !mInputDeviceVibrators.isEmpty() || vibratorExists();
1268         //}
1269         return vibratorExists();
1270     }
1271 
doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs)1272     private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) {
1273         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
1274         try {
1275             synchronized (mInputDeviceVibrators) {
1276                 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
1277                     amplitude = mDefaultVibrationAmplitude;
1278                 }
1279                 if (DEBUG) {
1280                     Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
1281                             " with amplitude " + amplitude + ".");
1282                 }
1283                 noteVibratorOnLocked(uid, millis);
1284                 final int vibratorCount = mInputDeviceVibrators.size();
1285                 if (vibratorCount != 0) {
1286                     for (int i = 0; i < vibratorCount; i++) {
1287                         mInputDeviceVibrators.get(i).vibrate(millis, attrs.getAudioAttributes());
1288                     }
1289                 } else {
1290                     // Note: ordering is important here! Many haptic drivers will reset their
1291                     // amplitude when enabled, so we always have to enable first, then set the
1292                     // amplitude.
1293                     vibratorOn(millis);
1294                     doVibratorSetAmplitude(amplitude);
1295                 }
1296             }
1297         } finally {
1298             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1299         }
1300     }
1301 
doVibratorSetAmplitude(int amplitude)1302     private void doVibratorSetAmplitude(int amplitude) {
1303         if (mSupportsAmplitudeControl) {
1304             vibratorSetAmplitude(amplitude);
1305         }
1306     }
1307 
doVibratorOff()1308     private void doVibratorOff() {
1309         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
1310         try {
1311             synchronized (mInputDeviceVibrators) {
1312                 if (DEBUG) {
1313                     Slog.d(TAG, "Turning vibrator off.");
1314                 }
1315                 noteVibratorOffLocked();
1316                 final int vibratorCount = mInputDeviceVibrators.size();
1317                 if (vibratorCount != 0) {
1318                     for (int i = 0; i < vibratorCount; i++) {
1319                         mInputDeviceVibrators.get(i).cancel();
1320                     }
1321                 } else {
1322                     vibratorOff();
1323                 }
1324             }
1325         } finally {
1326             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1327         }
1328     }
1329 
1330     @GuardedBy("mLock")
doVibratorPrebakedEffectLocked(Vibration vib)1331     private long doVibratorPrebakedEffectLocked(Vibration vib) {
1332         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
1333         try {
1334             final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
1335             final boolean usingInputDeviceVibrators;
1336             synchronized (mInputDeviceVibrators) {
1337                 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
1338             }
1339             // Input devices don't support prebaked effect, so skip trying it with them.
1340             if (!usingInputDeviceVibrators) {
1341                 long duration = vibratorPerformEffect(prebaked.getId(),
1342                         prebaked.getEffectStrength(), vib,
1343                         hasCapability(IVibrator.CAP_PERFORM_CALLBACK));
1344                 long timeout = duration;
1345                 if (hasCapability(IVibrator.CAP_PERFORM_CALLBACK)) {
1346                     timeout *= ASYNC_TIMEOUT_MULTIPLIER;
1347                 }
1348                 if (timeout > 0) {
1349                     noteVibratorOnLocked(vib.uid, duration);
1350                     return timeout;
1351                 }
1352             }
1353             if (!prebaked.shouldFallback()) {
1354                 return 0;
1355             }
1356             VibrationEffect effect = getFallbackEffect(prebaked.getId());
1357             if (effect == null) {
1358                 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
1359                 return 0;
1360             }
1361             Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid,
1362                     vib.opPkg, vib.reason + " (fallback)");
1363             final int intensity = getCurrentIntensityLocked(fallbackVib);
1364             linkVibration(fallbackVib);
1365             applyVibrationIntensityScalingLocked(fallbackVib, intensity);
1366             startVibrationInnerLocked(fallbackVib);
1367             return 0;
1368         } finally {
1369             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1370         }
1371     }
1372 
1373     @GuardedBy("mLock")
doVibratorComposedEffectLocked(Vibration vib)1374     private void doVibratorComposedEffectLocked(Vibration vib) {
1375         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorComposedEffectLocked");
1376 
1377         try {
1378             final VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.effect;
1379             final boolean usingInputDeviceVibrators;
1380             synchronized (mInputDeviceVibrators) {
1381                 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
1382             }
1383             // Input devices don't support composed effect, so skip trying it with them.
1384             if (usingInputDeviceVibrators) {
1385                 return;
1386             }
1387 
1388             if (!hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
1389                 return;
1390             }
1391 
1392             PrimitiveEffect[] primitiveEffects =
1393                     composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]);
1394             vibratorPerformComposedEffect(primitiveEffects, vib);
1395 
1396             // Composed effects don't actually give us an estimated duration, so we just guess here.
1397             noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length);
1398         } finally {
1399             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1400         }
1401 
1402     }
1403 
hasCapability(long capability)1404     private boolean hasCapability(long capability) {
1405         return (mCapabilities & capability) == capability;
1406     }
1407 
getFallbackEffect(int effectId)1408     private VibrationEffect getFallbackEffect(int effectId) {
1409         return mFallbackEffects.get(effectId);
1410     }
1411 
1412     /**
1413      * Return the current desired effect strength.
1414      *
1415      * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
1416      */
intensityToEffectStrength(int intensity)1417     private static int intensityToEffectStrength(int intensity) {
1418         switch (intensity) {
1419             case Vibrator.VIBRATION_INTENSITY_LOW:
1420                 return EffectStrength.LIGHT;
1421             case Vibrator.VIBRATION_INTENSITY_MEDIUM:
1422                 return EffectStrength.MEDIUM;
1423             case Vibrator.VIBRATION_INTENSITY_HIGH:
1424                 return EffectStrength.STRONG;
1425             default:
1426                 Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
1427                 return EffectStrength.STRONG;
1428         }
1429     }
1430 
isNotification(int usageHint)1431     private static boolean isNotification(int usageHint) {
1432         return usageHint == VibrationAttributes.USAGE_NOTIFICATION;
1433     }
1434 
isRingtone(int usageHint)1435     private static boolean isRingtone(int usageHint) {
1436         return usageHint == VibrationAttributes.USAGE_RINGTONE;
1437     }
1438 
isHapticFeedback(int usageHint)1439     private static boolean isHapticFeedback(int usageHint) {
1440         return usageHint == VibrationAttributes.USAGE_TOUCH;
1441     }
1442 
isAlarm(int usageHint)1443     private static boolean isAlarm(int usageHint) {
1444         return usageHint == VibrationAttributes.USAGE_ALARM;
1445     }
1446 
noteVibratorOnLocked(int uid, long millis)1447     private void noteVibratorOnLocked(int uid, long millis) {
1448         try {
1449             mBatteryStatsService.noteVibratorOn(uid, millis);
1450             FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED, uid, null,
1451                     FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis);
1452             mCurVibUid = uid;
1453             if (!mIsVibrating) {
1454                 mIsVibrating = true;
1455                 notifyStateListenersLocked();
1456             }
1457         } catch (RemoteException e) {
1458         }
1459     }
1460 
noteVibratorOffLocked()1461     private void noteVibratorOffLocked() {
1462         if (mCurVibUid >= 0) {
1463             try {
1464                 mBatteryStatsService.noteVibratorOff(mCurVibUid);
1465                 FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
1466                         mCurVibUid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF, 0);
1467             } catch (RemoteException e) { }
1468             mCurVibUid = -1;
1469         }
1470         if (mIsVibrating) {
1471             mIsVibrating = false;
1472             notifyStateListenersLocked();
1473         }
1474     }
1475 
setVibratorUnderExternalControl(boolean externalControl)1476     private void setVibratorUnderExternalControl(boolean externalControl) {
1477         if (DEBUG) {
1478             if (externalControl) {
1479                 Slog.d(TAG, "Vibrator going under external control.");
1480             } else {
1481                 Slog.d(TAG, "Taking back control of vibrator.");
1482             }
1483         }
1484         mVibratorUnderExternalControl = externalControl;
1485         vibratorSetExternalControl(externalControl);
1486     }
1487 
dumpInternal(PrintWriter pw)1488     private void dumpInternal(PrintWriter pw) {
1489         pw.println("Vibrator Service:");
1490         synchronized (mLock) {
1491             pw.print("  mCurrentVibration=");
1492             if (mCurrentVibration != null) {
1493                 pw.println(mCurrentVibration.toInfo().toString());
1494             } else {
1495                 pw.println("null");
1496             }
1497             pw.print("  mCurrentExternalVibration=" + mCurrentExternalVibration);
1498             pw.println("  mVibratorUnderExternalControl=" + mVibratorUnderExternalControl);
1499             pw.println("  mIsVibrating=" + mIsVibrating);
1500             pw.println("  mVibratorStateListeners Count=" +
1501                             mVibratorStateListeners.getRegisteredCallbackCount());
1502             pw.println("  mLowPowerMode=" + mLowPowerMode);
1503             pw.println("  mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
1504             pw.println("  mNotificationIntensity=" + mNotificationIntensity);
1505             pw.println("  mRingIntensity=" + mRingIntensity);
1506             pw.println("  mSupportedEffects=" + mSupportedEffects);
1507             pw.println();
1508             pw.println("  Previous ring vibrations:");
1509             for (VibrationInfo info : mPreviousRingVibrations) {
1510                 pw.print("    ");
1511                 pw.println(info.toString());
1512             }
1513 
1514             pw.println("  Previous notification vibrations:");
1515             for (VibrationInfo info : mPreviousNotificationVibrations) {
1516                 pw.println("    " + info);
1517             }
1518 
1519             pw.println("  Previous alarm vibrations:");
1520             for (VibrationInfo info : mPreviousAlarmVibrations) {
1521                 pw.println("    " + info);
1522             }
1523 
1524             pw.println("  Previous vibrations:");
1525             for (VibrationInfo info : mPreviousVibrations) {
1526                 pw.println("    " + info);
1527             }
1528 
1529             pw.println("  Previous external vibrations:");
1530             for (ExternalVibration vib : mPreviousExternalVibrations) {
1531                 pw.println("    " + vib);
1532             }
1533         }
1534     }
1535 
dumpProto(FileDescriptor fd)1536     private void dumpProto(FileDescriptor fd) {
1537         final ProtoOutputStream proto = new ProtoOutputStream(fd);
1538 
1539         synchronized (mLock) {
1540             if (mCurrentVibration != null) {
1541                 mCurrentVibration.toInfo().dumpProto(proto,
1542                     VibratorServiceDumpProto.CURRENT_VIBRATION);
1543             }
1544             proto.write(VibratorServiceDumpProto.IS_VIBRATING, mIsVibrating);
1545             proto.write(VibratorServiceDumpProto.VIBRATOR_UNDER_EXTERNAL_CONTROL,
1546                 mVibratorUnderExternalControl);
1547             proto.write(VibratorServiceDumpProto.LOW_POWER_MODE, mLowPowerMode);
1548             proto.write(VibratorServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY,
1549                 mHapticFeedbackIntensity);
1550             proto.write(VibratorServiceDumpProto.NOTIFICATION_INTENSITY,
1551                 mNotificationIntensity);
1552             proto.write(VibratorServiceDumpProto.RING_INTENSITY, mRingIntensity);
1553 
1554             for (VibrationInfo info : mPreviousRingVibrations) {
1555                 info.dumpProto(proto,
1556                     VibratorServiceDumpProto.PREVIOUS_RING_VIBRATIONS);
1557             }
1558 
1559             for (VibrationInfo info : mPreviousNotificationVibrations) {
1560                 info.dumpProto(proto,
1561                     VibratorServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS);
1562             }
1563 
1564             for (VibrationInfo info : mPreviousAlarmVibrations) {
1565                 info.dumpProto(proto,
1566                     VibratorServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS);
1567             }
1568 
1569             for (VibrationInfo info : mPreviousVibrations) {
1570                 info.dumpProto(proto,
1571                     VibratorServiceDumpProto.PREVIOUS_VIBRATIONS);
1572             }
1573         }
1574         proto.flush();
1575     }
1576 
1577     private class VibrateThread extends Thread {
1578         private final VibrationEffect.Waveform mWaveform;
1579         private final int mUid;
1580         private final VibrationAttributes mAttrs;
1581 
1582         private boolean mForceStop;
1583 
VibrateThread(VibrationEffect.Waveform waveform, int uid, VibrationAttributes attrs)1584         VibrateThread(VibrationEffect.Waveform waveform, int uid, VibrationAttributes attrs) {
1585             mWaveform = waveform;
1586             mUid = uid;
1587             mAttrs = attrs;
1588             mTmpWorkSource.set(uid);
1589             mWakeLock.setWorkSource(mTmpWorkSource);
1590         }
1591 
delayLocked(long duration)1592         private long delayLocked(long duration) {
1593             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked");
1594             try {
1595                 long durationRemaining = duration;
1596                 if (duration > 0) {
1597                     final long bedtime = duration + SystemClock.uptimeMillis();
1598                     do {
1599                         try {
1600                             this.wait(durationRemaining);
1601                         }
1602                         catch (InterruptedException e) { }
1603                         if (mForceStop) {
1604                             break;
1605                         }
1606                         durationRemaining = bedtime - SystemClock.uptimeMillis();
1607                     } while (durationRemaining > 0);
1608                     return duration - durationRemaining;
1609                 }
1610                 return 0;
1611             } finally {
1612                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1613             }
1614         }
1615 
run()1616         public void run() {
1617             Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
1618             mWakeLock.acquire();
1619             try {
1620                 boolean finished = playWaveform();
1621                 if (finished) {
1622                     onVibrationFinished();
1623                 }
1624             } finally {
1625                 mWakeLock.release();
1626             }
1627         }
1628 
1629         /**
1630          * Play the waveform.
1631          *
1632          * @return true if it finished naturally, false otherwise (e.g. it was canceled).
1633          */
playWaveform()1634         public boolean playWaveform() {
1635             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform");
1636             try {
1637                 synchronized (this) {
1638                     final long[] timings = mWaveform.getTimings();
1639                     final int[] amplitudes = mWaveform.getAmplitudes();
1640                     final int len = timings.length;
1641                     final int repeat = mWaveform.getRepeatIndex();
1642 
1643                     int index = 0;
1644                     long onDuration = 0;
1645                     while (!mForceStop) {
1646                         if (index < len) {
1647                             final int amplitude = amplitudes[index];
1648                             final long duration = timings[index++];
1649                             if (duration <= 0) {
1650                                 continue;
1651                             }
1652                             if (amplitude != 0) {
1653                                 if (onDuration <= 0) {
1654                                     // Telling the vibrator to start multiple times usually causes
1655                                     // effects to feel "choppy" because the motor resets at every on
1656                                     // command.  Instead we figure out how long our next "on" period
1657                                     // is going to be, tell the motor to stay on for the full
1658                                     // duration, and then wake up to change the amplitude at the
1659                                     // appropriate intervals.
1660                                     onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
1661                                             repeat);
1662                                     doVibratorOn(onDuration, amplitude, mUid, mAttrs);
1663                                 } else {
1664                                     doVibratorSetAmplitude(amplitude);
1665                                 }
1666                             }
1667 
1668                             long waitTime = delayLocked(duration);
1669                             if (amplitude != 0) {
1670                                 onDuration -= waitTime;
1671                             }
1672                         } else if (repeat < 0) {
1673                             break;
1674                         } else {
1675                             index = repeat;
1676                         }
1677                     }
1678                     return !mForceStop;
1679                 }
1680             } finally {
1681                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1682             }
1683         }
1684 
cancel()1685         public void cancel() {
1686             synchronized (this) {
1687                 mThread.mForceStop = true;
1688                 mThread.notify();
1689             }
1690         }
1691 
1692         /**
1693          * Get the duration the vibrator will be on starting at startIndex until the next time it's
1694          * off.
1695          */
getTotalOnDuration( long[] timings, int[] amplitudes, int startIndex, int repeatIndex)1696         private long getTotalOnDuration(
1697                 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
1698             int i = startIndex;
1699             long timing = 0;
1700             while (amplitudes[i] != 0) {
1701                 timing += timings[i++];
1702                 if (i >= timings.length) {
1703                     if (repeatIndex >= 0) {
1704                         i = repeatIndex;
1705                         // prevent infinite loop
1706                         repeatIndex = -1;
1707                     } else {
1708                         break;
1709                     }
1710                 }
1711                 if (i == startIndex) {
1712                     return 1000;
1713                 }
1714             }
1715             return timing;
1716         }
1717     }
1718 
1719     BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1720         @Override
1721         public void onReceive(Context context, Intent intent) {
1722             if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
1723                 synchronized (mLock) {
1724                     // When the system is entering a non-interactive state, we want
1725                     // to cancel vibrations in case a misbehaving app has abandoned
1726                     // them.  However it may happen that the system is currently playing
1727                     // haptic feedback as part of the transition.  So we don't cancel
1728                     // system vibrations.
1729                     if (mCurrentVibration != null
1730                             && !(mCurrentVibration.isHapticFeedback()
1731                                 && mCurrentVibration.isFromSystem())) {
1732                         doCancelVibrateLocked();
1733                     }
1734                 }
1735             }
1736         }
1737     };
1738 
1739     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1740     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1741         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1742 
1743         final long ident = Binder.clearCallingIdentity();
1744 
1745         boolean isDumpProto = false;
1746         for (String arg : args) {
1747             if (arg.equals("--proto")) {
1748                 isDumpProto = true;
1749             }
1750         }
1751         try {
1752             if (isDumpProto) {
1753                 dumpProto(fd);
1754             } else {
1755                 dumpInternal(pw);
1756             }
1757         } finally {
1758             Binder.restoreCallingIdentity(ident);
1759         }
1760     }
1761 
1762     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1763     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1764             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
1765         new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
1766     }
1767 
1768     final class ExternalVibratorService extends IExternalVibratorService.Stub {
1769         ExternalVibrationDeathRecipient mCurrentExternalDeathRecipient;
1770 
1771         @Override
onExternalVibrationStart(ExternalVibration vib)1772         public int onExternalVibrationStart(ExternalVibration vib) {
1773             if (!mSupportsExternalControl) {
1774                 return SCALE_MUTE;
1775             }
1776             if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
1777                     vib.getUid(), -1 /*owningUid*/, true /*exported*/)
1778                     != PackageManager.PERMISSION_GRANTED) {
1779                 Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
1780                         + " tried to play externally controlled vibration"
1781                         + " without VIBRATE permission, ignoring.");
1782                 return SCALE_MUTE;
1783             }
1784 
1785             int mode = getAppOpMode(vib.getUid(), vib.getPackage(), vib.getVibrationAttributes());
1786             if (mode != AppOpsManager.MODE_ALLOWED) {
1787                 if (mode == AppOpsManager.MODE_ERRORED) {
1788                     Slog.w(TAG, "Would be an error: external vibrate from uid " + vib.getUid());
1789                 }
1790                 return SCALE_MUTE;
1791             }
1792 
1793             final int scaleLevel;
1794             synchronized (mLock) {
1795                 if (!vib.equals(mCurrentExternalVibration)) {
1796                     if (mCurrentExternalVibration == null) {
1797                         // If we're not under external control right now, then cancel any normal
1798                         // vibration that may be playing and ready the vibrator for external
1799                         // control.
1800                         doCancelVibrateLocked();
1801                         setVibratorUnderExternalControl(true);
1802                     }
1803                     // At this point we either have an externally controlled vibration playing, or
1804                     // no vibration playing. Since the interface defines that only one externally
1805                     // controlled vibration can play at a time, by returning something other than
1806                     // SCALE_MUTE from this function we can be assured that if we are currently
1807                     // playing vibration, it will be muted in favor of the new vibration.
1808                     //
1809                     // Note that this doesn't support multiple concurrent external controls, as we
1810                     // would need to mute the old one still if it came from a different controller.
1811                     mCurrentExternalVibration = vib;
1812                     mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient();
1813                     mCurrentExternalVibration.linkToDeath(mCurrentExternalDeathRecipient);
1814                     if (mPreviousExternalVibrations.size() > mPreviousVibrationsLimit) {
1815                         mPreviousExternalVibrations.removeFirst();
1816                     }
1817                     mPreviousExternalVibrations.addLast(vib);
1818                     if (DEBUG) {
1819                         Slog.e(TAG, "Playing external vibration: " + vib);
1820                     }
1821                 }
1822                 final int usage = vib.getVibrationAttributes().getUsage();
1823                 final int defaultIntensity;
1824                 final int currentIntensity;
1825                 if (isRingtone(usage)) {
1826                     defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
1827                     currentIntensity = mRingIntensity;
1828                 } else if (isNotification(usage)) {
1829                     defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
1830                     currentIntensity = mNotificationIntensity;
1831                 } else if (isHapticFeedback(usage)) {
1832                     defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
1833                     currentIntensity = mHapticFeedbackIntensity;
1834                 } else if (isAlarm(usage)) {
1835                     defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
1836                     currentIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
1837                 } else {
1838                     defaultIntensity = 0;
1839                     currentIntensity = 0;
1840                 }
1841                 scaleLevel = currentIntensity - defaultIntensity;
1842             }
1843             if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
1844                 return scaleLevel;
1845             } else {
1846                 // Presumably we want to play this but something about our scaling has gone
1847                 // wrong, so just play with no scaling.
1848                 Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
1849                         + scaleLevel + " for vibration " + vib);
1850                 return SCALE_NONE;
1851             }
1852         }
1853 
1854         @Override
onExternalVibrationStop(ExternalVibration vib)1855         public void onExternalVibrationStop(ExternalVibration vib) {
1856             synchronized (mLock) {
1857                 if (vib.equals(mCurrentExternalVibration)) {
1858                     mCurrentExternalVibration.unlinkToDeath(mCurrentExternalDeathRecipient);
1859                     mCurrentExternalDeathRecipient = null;
1860                     mCurrentExternalVibration = null;
1861                     setVibratorUnderExternalControl(false);
1862                     if (DEBUG) {
1863                         Slog.e(TAG, "Stopping external vibration" + vib);
1864                     }
1865                 }
1866             }
1867         }
1868 
1869         private class ExternalVibrationDeathRecipient implements IBinder.DeathRecipient {
binderDied()1870             public void binderDied() {
1871                 synchronized (mLock) {
1872                     onExternalVibrationStop(mCurrentExternalVibration);
1873                 }
1874             }
1875         }
1876     }
1877 
1878     private final class VibratorShellCommand extends ShellCommand {
1879 
1880         private final IBinder mToken;
1881 
1882         private final class CommonOptions {
1883             public boolean force = false;
check(String opt)1884             public void check(String opt) {
1885                 switch (opt) {
1886                     case "-f":
1887                         force = true;
1888                         break;
1889                 }
1890             }
1891         }
1892 
VibratorShellCommand(IBinder token)1893         private VibratorShellCommand(IBinder token) {
1894             mToken = token;
1895         }
1896 
1897         @Override
onCommand(String cmd)1898         public int onCommand(String cmd) {
1899             if ("vibrate".equals(cmd)) {
1900                 return runVibrate();
1901             } else if ("waveform".equals(cmd)) {
1902                 return runWaveform();
1903             } else if ("prebaked".equals(cmd)) {
1904                 return runPrebaked();
1905             } else if ("capabilities".equals(cmd)) {
1906                 return runCapabilities();
1907             } else if ("cancel".equals(cmd)) {
1908                 cancelVibrate(mToken);
1909                 return 0;
1910             }
1911             return handleDefaultCommands(cmd);
1912         }
1913 
checkDoNotDisturb(CommonOptions opts)1914         private boolean checkDoNotDisturb(CommonOptions opts) {
1915             try {
1916                 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
1917                         Settings.Global.ZEN_MODE);
1918                 if (zenMode != Settings.Global.ZEN_MODE_OFF && !opts.force) {
1919                     try (PrintWriter pw = getOutPrintWriter();) {
1920                         pw.print("Ignoring because device is on DND mode ");
1921                         pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
1922                                 zenMode));
1923                         return true;
1924                     }
1925                 }
1926             } catch (SettingNotFoundException e) {
1927                 // ignore
1928             }
1929 
1930             return false;
1931         }
1932 
runVibrate()1933         private int runVibrate() {
1934             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate");
1935             try {
1936                 CommonOptions commonOptions = new CommonOptions();
1937 
1938                 String opt;
1939                 while ((opt = getNextOption()) != null) {
1940                     commonOptions.check(opt);
1941                 }
1942 
1943                 if (checkDoNotDisturb(commonOptions)) {
1944                     return 0;
1945                 }
1946 
1947                 final long duration = Long.parseLong(getNextArgRequired());
1948                 String description = getNextArg();
1949                 if (description == null) {
1950                     description = "Shell command";
1951                 }
1952 
1953                 VibrationEffect effect =
1954                         VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1955                 VibrationAttributes attrs = createVibrationAttributes(commonOptions);
1956                 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
1957                         mToken);
1958                 return 0;
1959             } finally {
1960                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1961             }
1962         }
1963 
runWaveform()1964         private int runWaveform() {
1965             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runWaveform");
1966             try {
1967                 String description = "Shell command";
1968                 int repeat = -1;
1969                 ArrayList<Integer> amplitudesList = null;
1970                 CommonOptions commonOptions = new CommonOptions();
1971 
1972                 String opt;
1973                 while ((opt = getNextOption()) != null) {
1974                     switch (opt) {
1975                         case "-d":
1976                             description = getNextArgRequired();
1977                             break;
1978                         case "-r":
1979                             repeat = Integer.parseInt(getNextArgRequired());
1980                             break;
1981                         case "-a":
1982                             if (amplitudesList == null) {
1983                                 amplitudesList = new ArrayList<Integer>();
1984                             }
1985                             break;
1986                         default:
1987                             commonOptions.check(opt);
1988                             break;
1989                     }
1990                 }
1991 
1992                 if (checkDoNotDisturb(commonOptions)) {
1993                     return 0;
1994                 }
1995 
1996                 ArrayList<Long> timingsList = new ArrayList<Long>();
1997 
1998                 String arg;
1999                 while ((arg = getNextArg()) != null) {
2000                     if (amplitudesList != null && amplitudesList.size() < timingsList.size()) {
2001                         amplitudesList.add(Integer.parseInt(arg));
2002                     } else {
2003                         timingsList.add(Long.parseLong(arg));
2004                     }
2005                 }
2006 
2007                 VibrationEffect effect;
2008                 long[] timings = timingsList.stream().mapToLong(Long::longValue).toArray();
2009                 if (amplitudesList == null) {
2010                     effect = VibrationEffect.createWaveform(timings, repeat);
2011                 } else {
2012                     int[] amplitudes =
2013                             amplitudesList.stream().mapToInt(Integer::intValue).toArray();
2014                     effect = VibrationEffect.createWaveform(timings, amplitudes, repeat);
2015                 }
2016                 VibrationAttributes attrs = createVibrationAttributes(commonOptions);
2017                 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
2018                         mToken);
2019                 return 0;
2020             } finally {
2021                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
2022             }
2023         }
2024 
runPrebaked()2025         private int runPrebaked() {
2026             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
2027             try {
2028                 CommonOptions commonOptions = new CommonOptions();
2029                 boolean shouldFallback = false;
2030 
2031                 String opt;
2032                 while ((opt = getNextOption()) != null) {
2033                     if ("-b".equals(opt)) {
2034                         shouldFallback = true;
2035                     } else {
2036                         commonOptions.check(opt);
2037                     }
2038                 }
2039 
2040                 if (checkDoNotDisturb(commonOptions)) {
2041                     return 0;
2042                 }
2043 
2044                 final int id = Integer.parseInt(getNextArgRequired());
2045 
2046                 String description = getNextArg();
2047                 if (description == null) {
2048                     description = "Shell command";
2049                 }
2050 
2051                 VibrationEffect effect = VibrationEffect.get(id, shouldFallback);
2052                 VibrationAttributes attrs = createVibrationAttributes(commonOptions);
2053                 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
2054                         mToken);
2055                 return 0;
2056             } finally {
2057                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
2058             }
2059         }
2060 
runCapabilities()2061         private int runCapabilities() {
2062             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runCapabilities");
2063             try (PrintWriter pw = getOutPrintWriter();) {
2064                 pw.println("Vibrator capabilities:");
2065                 if (hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
2066                     pw.println("  Always on effects");
2067                 }
2068                 if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
2069                     pw.println("  Compose effects");
2070                 }
2071                 if (mSupportsAmplitudeControl || hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
2072                     pw.println("  Amplitude control");
2073                 }
2074                 if (mSupportsExternalControl || hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
2075                     pw.println("  External control");
2076                 }
2077                 if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
2078                     pw.println("  External amplitude control");
2079                 }
2080                 pw.println("");
2081                 return 0;
2082             } finally {
2083                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
2084             }
2085         }
2086 
createVibrationAttributes(CommonOptions commonOptions)2087         private VibrationAttributes createVibrationAttributes(CommonOptions commonOptions) {
2088             final int flags = commonOptions.force
2089                     ? VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
2090                     : 0;
2091             return new VibrationAttributes.Builder()
2092                     // Used to apply Settings.System.HAPTIC_FEEDBACK_INTENSITY to scale effects.
2093                     .setUsage(VibrationAttributes.USAGE_TOUCH)
2094                     .replaceFlags(flags)
2095                     .build();
2096         }
2097 
2098         @Override
onHelp()2099         public void onHelp() {
2100             try (PrintWriter pw = getOutPrintWriter();) {
2101                 pw.println("Vibrator commands:");
2102                 pw.println("  help");
2103                 pw.println("    Prints this help text.");
2104                 pw.println("");
2105                 pw.println("  vibrate duration [description]");
2106                 pw.println("    Vibrates for duration milliseconds; ignored when device is on ");
2107                 pw.println("    DND (Do Not Disturb) mode; touch feedback strength user setting ");
2108                 pw.println("    will be used to scale amplitude.");
2109                 pw.println("  waveform [-d description] [-r index] [-a] duration [amplitude] ...");
2110                 pw.println("    Vibrates for durations and amplitudes in list; ignored when ");
2111                 pw.println("    device is on DND (Do Not Disturb) mode; touch feedback strength ");
2112                 pw.println("    user setting will be used to scale amplitude.");
2113                 pw.println("    If -r is provided, the waveform loops back to the specified");
2114                 pw.println("    index (e.g. 0 loops from the beginning)");
2115                 pw.println("    If -a is provided, the command accepts duration-amplitude pairs;");
2116                 pw.println("    otherwise, it accepts durations only and alternates off/on");
2117                 pw.println("    Duration is in milliseconds; amplitude is a scale of 1-255.");
2118                 pw.println("  prebaked [-b] effect-id [description]");
2119                 pw.println("    Vibrates with prebaked effect; ignored when device is on DND ");
2120                 pw.println("    (Do Not Disturb) mode; touch feedback strength user setting ");
2121                 pw.println("    will be used to scale amplitude.");
2122                 pw.println("    If -b is provided, the prebaked fallback effect will be played if");
2123                 pw.println("    the device doesn't support the given effect-id.");
2124                 pw.println("  capabilities");
2125                 pw.println("    Prints capabilities of this device.");
2126                 pw.println("  cancel");
2127                 pw.println("    Cancels any active vibration");
2128                 pw.println("Common Options:");
2129                 pw.println("  -f - Force. Ignore Do Not Disturb setting.");
2130                 pw.println("");
2131             }
2132         }
2133     }
2134 
2135 }
2136