• 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 android.app.AppOpsManager;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.pm.PackageManager;
25 import android.database.ContentObserver;
26 import android.hardware.input.InputManager;
27 import android.media.AudioManager;
28 import android.os.BatteryStats;
29 import android.os.Handler;
30 import android.os.IVibratorService;
31 import android.os.PowerManager;
32 import android.os.PowerManagerInternal;
33 import android.os.Process;
34 import android.os.RemoteException;
35 import android.os.IBinder;
36 import android.os.Binder;
37 import android.os.ServiceManager;
38 import android.os.SystemClock;
39 import android.os.UserHandle;
40 import android.os.Vibrator;
41 import android.os.WorkSource;
42 import android.provider.Settings;
43 import android.provider.Settings.SettingNotFoundException;
44 import android.util.Slog;
45 import android.view.InputDevice;
46 import android.media.AudioAttributes;
47 
48 import com.android.internal.app.IAppOpsService;
49 import com.android.internal.app.IBatteryStats;
50 
51 import java.io.FileDescriptor;
52 import java.io.PrintWriter;
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.Iterator;
56 import java.util.LinkedList;
57 import java.util.ListIterator;
58 
59 public class VibratorService extends IVibratorService.Stub
60         implements InputManager.InputDeviceListener {
61     private static final String TAG = "VibratorService";
62     private static final boolean DEBUG = false;
63     private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
64 
65     private final LinkedList<Vibration> mVibrations;
66     private final LinkedList<VibrationInfo> mPreviousVibrations;
67     private final int mPreviousVibrationsLimit;
68     private Vibration mCurrentVibration;
69     private final WorkSource mTmpWorkSource = new WorkSource();
70     private final Handler mH = new Handler();
71 
72     private final Context mContext;
73     private final PowerManager.WakeLock mWakeLock;
74     private final IAppOpsService mAppOpsService;
75     private final IBatteryStats mBatteryStatsService;
76     private PowerManagerInternal mPowerManagerInternal;
77     private InputManager mIm;
78 
79     volatile VibrateThread mThread;
80 
81     // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
82     // to be acquired
83     private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
84     private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
85     private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
86 
87     private int mCurVibUid = -1;
88     private boolean mLowPowerMode;
89     private SettingsObserver mSettingObserver;
90 
vibratorExists()91     native static boolean vibratorExists();
vibratorInit()92     native static void vibratorInit();
vibratorOn(long milliseconds)93     native static void vibratorOn(long milliseconds);
vibratorOff()94     native static void vibratorOff();
95 
96     private class Vibration implements IBinder.DeathRecipient {
97         private final IBinder mToken;
98         private final long    mTimeout;
99         private final long    mStartTime;
100         private final long[]  mPattern;
101         private final int     mRepeat;
102         private final int     mUsageHint;
103         private final int     mUid;
104         private final String  mOpPkg;
105 
Vibration(IBinder token, long millis, int usageHint, int uid, String opPkg)106         Vibration(IBinder token, long millis, int usageHint, int uid, String opPkg) {
107             this(token, millis, null, 0, usageHint, uid, opPkg);
108         }
109 
Vibration(IBinder token, long[] pattern, int repeat, int usageHint, int uid, String opPkg)110         Vibration(IBinder token, long[] pattern, int repeat, int usageHint, int uid,
111                 String opPkg) {
112             this(token, 0, pattern, repeat, usageHint, uid, opPkg);
113         }
114 
Vibration(IBinder token, long millis, long[] pattern, int repeat, int usageHint, int uid, String opPkg)115         private Vibration(IBinder token, long millis, long[] pattern,
116                 int repeat, int usageHint, int uid, String opPkg) {
117             mToken = token;
118             mTimeout = millis;
119             mStartTime = SystemClock.uptimeMillis();
120             mPattern = pattern;
121             mRepeat = repeat;
122             mUsageHint = usageHint;
123             mUid = uid;
124             mOpPkg = opPkg;
125         }
126 
binderDied()127         public void binderDied() {
128             synchronized (mVibrations) {
129                 mVibrations.remove(this);
130                 if (this == mCurrentVibration) {
131                     doCancelVibrateLocked();
132                     startNextVibrationLocked();
133                 }
134             }
135         }
136 
hasLongerTimeout(long millis)137         public boolean hasLongerTimeout(long millis) {
138             if (mTimeout == 0) {
139                 // This is a pattern, return false to play the simple
140                 // vibration.
141                 return false;
142             }
143             if ((mStartTime + mTimeout)
144                     < (SystemClock.uptimeMillis() + millis)) {
145                 // If this vibration will end before the time passed in, let
146                 // the new vibration play.
147                 return false;
148             }
149             return true;
150         }
151 
isSystemHapticFeedback()152         public boolean isSystemHapticFeedback() {
153             return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
154                     && mRepeat < 0;
155         }
156     }
157 
158     private static class VibrationInfo {
159         long timeout;
160         long startTime;
161         long[] pattern;
162         int repeat;
163         int usageHint;
164         int uid;
165         String opPkg;
166 
VibrationInfo(long timeout, long startTime, long[] pattern, int repeat, int usageHint, int uid, String opPkg)167         public VibrationInfo(long timeout, long startTime, long[] pattern, int repeat,
168                 int usageHint, int uid, String opPkg) {
169             this.timeout = timeout;
170             this.startTime = startTime;
171             this.pattern = pattern;
172             this.repeat = repeat;
173             this.usageHint = usageHint;
174             this.uid = uid;
175             this.opPkg = opPkg;
176         }
177 
178         @Override
toString()179         public String toString() {
180             return new StringBuilder()
181                     .append("timeout: ")
182                     .append(timeout)
183                     .append(", startTime: ")
184                     .append(startTime)
185                     .append(", pattern: ")
186                     .append(Arrays.toString(pattern))
187                     .append(", repeat: ")
188                     .append(repeat)
189                     .append(", usageHint: ")
190                     .append(usageHint)
191                     .append(", uid: ")
192                     .append(uid)
193                     .append(", opPkg: ")
194                     .append(opPkg)
195                     .toString();
196         }
197     }
198 
VibratorService(Context context)199     VibratorService(Context context) {
200         vibratorInit();
201         // Reset the hardware to a default state, in case this is a runtime
202         // restart instead of a fresh boot.
203         vibratorOff();
204 
205         mContext = context;
206         PowerManager pm = (PowerManager)context.getSystemService(
207                 Context.POWER_SERVICE);
208         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
209         mWakeLock.setReferenceCounted(true);
210 
211         mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
212         mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
213                 BatteryStats.SERVICE_NAME));
214 
215         mPreviousVibrationsLimit = mContext.getResources().getInteger(
216                 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
217 
218         mVibrations = new LinkedList<>();
219         mPreviousVibrations = new LinkedList<>();
220 
221         IntentFilter filter = new IntentFilter();
222         filter.addAction(Intent.ACTION_SCREEN_OFF);
223         context.registerReceiver(mIntentReceiver, filter);
224     }
225 
systemReady()226     public void systemReady() {
227         mIm = mContext.getSystemService(InputManager.class);
228         mSettingObserver = new SettingsObserver(mH);
229 
230         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
231         mPowerManagerInternal.registerLowPowerModeObserver(
232                 new PowerManagerInternal.LowPowerModeListener() {
233             @Override
234             public void onLowPowerModeChanged(boolean enabled) {
235                 updateInputDeviceVibrators();
236             }
237         });
238 
239         mContext.getContentResolver().registerContentObserver(
240                 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
241                 true, mSettingObserver, UserHandle.USER_ALL);
242 
243         mContext.registerReceiver(new BroadcastReceiver() {
244             @Override
245             public void onReceive(Context context, Intent intent) {
246                 updateInputDeviceVibrators();
247             }
248         }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
249 
250         updateInputDeviceVibrators();
251     }
252 
253     private final class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler)254         public SettingsObserver(Handler handler) {
255             super(handler);
256         }
257 
258         @Override
onChange(boolean SelfChange)259         public void onChange(boolean SelfChange) {
260             updateInputDeviceVibrators();
261         }
262     }
263 
264     @Override // Binder call
hasVibrator()265     public boolean hasVibrator() {
266         return doVibratorExists();
267     }
268 
verifyIncomingUid(int uid)269     private void verifyIncomingUid(int uid) {
270         if (uid == Binder.getCallingUid()) {
271             return;
272         }
273         if (Binder.getCallingPid() == Process.myPid()) {
274             return;
275         }
276         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
277                 Binder.getCallingPid(), Binder.getCallingUid(), null);
278     }
279 
280     @Override // Binder call
vibrate(int uid, String opPkg, long milliseconds, int usageHint, IBinder token)281     public void vibrate(int uid, String opPkg, long milliseconds, int usageHint,
282             IBinder token) {
283         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
284                 != PackageManager.PERMISSION_GRANTED) {
285             throw new SecurityException("Requires VIBRATE permission");
286         }
287         verifyIncomingUid(uid);
288         // We're running in the system server so we cannot crash. Check for a
289         // timeout of 0 or negative. This will ensure that a vibration has
290         // either a timeout of > 0 or a non-null pattern.
291         if (milliseconds <= 0 || (mCurrentVibration != null
292                 && mCurrentVibration.hasLongerTimeout(milliseconds))) {
293             // Ignore this vibration since the current vibration will play for
294             // longer than milliseconds.
295             return;
296         }
297 
298         if (DEBUG) {
299             Slog.d(TAG, "Vibrating for " + milliseconds + " ms.");
300         }
301 
302         Vibration vib = new Vibration(token, milliseconds, usageHint, uid, opPkg);
303 
304         final long ident = Binder.clearCallingIdentity();
305         try {
306             synchronized (mVibrations) {
307                 removeVibrationLocked(token);
308                 doCancelVibrateLocked();
309                 addToPreviousVibrationsLocked(vib);
310                 startVibrationLocked(vib);
311             }
312         } finally {
313             Binder.restoreCallingIdentity(ident);
314         }
315     }
316 
isAll0(long[] pattern)317     private boolean isAll0(long[] pattern) {
318         int N = pattern.length;
319         for (int i = 0; i < N; i++) {
320             if (pattern[i] != 0) {
321                 return false;
322             }
323         }
324         return true;
325     }
326 
327     @Override // Binder call
vibratePattern(int uid, String packageName, long[] pattern, int repeat, int usageHint, IBinder token)328     public void vibratePattern(int uid, String packageName, long[] pattern, int repeat,
329             int usageHint, IBinder token) {
330         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
331                 != PackageManager.PERMISSION_GRANTED) {
332             throw new SecurityException("Requires VIBRATE permission");
333         }
334         verifyIncomingUid(uid);
335         // so wakelock calls will succeed
336         long identity = Binder.clearCallingIdentity();
337         try {
338             if (DEBUG) {
339                 String s = "";
340                 int N = pattern.length;
341                 for (int i=0; i<N; i++) {
342                     s += " " + pattern[i];
343                 }
344                 Slog.d(TAG, "Vibrating with pattern:" + s);
345             }
346 
347             // we're running in the server so we can't fail
348             if (pattern == null || pattern.length == 0
349                     || isAll0(pattern)
350                     || repeat >= pattern.length || token == null) {
351                 return;
352             }
353 
354             Vibration vib = new Vibration(token, pattern, repeat, usageHint, uid, packageName);
355             try {
356                 token.linkToDeath(vib, 0);
357             } catch (RemoteException e) {
358                 return;
359             }
360 
361             synchronized (mVibrations) {
362                 removeVibrationLocked(token);
363                 doCancelVibrateLocked();
364                 if (repeat >= 0) {
365                     mVibrations.addFirst(vib);
366                     startNextVibrationLocked();
367                 } else {
368                     // A negative repeat means that this pattern is not meant
369                     // to repeat. Treat it like a simple vibration.
370                     startVibrationLocked(vib);
371                 }
372                 addToPreviousVibrationsLocked(vib);
373             }
374         }
375         finally {
376             Binder.restoreCallingIdentity(identity);
377         }
378     }
379 
addToPreviousVibrationsLocked(Vibration vib)380     private void addToPreviousVibrationsLocked(Vibration vib) {
381         if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
382             mPreviousVibrations.removeFirst();
383         }
384         mPreviousVibrations.addLast(new VibratorService.VibrationInfo(vib.mTimeout, vib.mStartTime,
385                 vib.mPattern, vib.mRepeat, vib.mUsageHint, vib.mUid, vib.mOpPkg));
386     }
387 
388     @Override // Binder call
cancelVibrate(IBinder token)389     public void cancelVibrate(IBinder token) {
390         mContext.enforceCallingOrSelfPermission(
391                 android.Manifest.permission.VIBRATE,
392                 "cancelVibrate");
393 
394         // so wakelock calls will succeed
395         long identity = Binder.clearCallingIdentity();
396         try {
397             synchronized (mVibrations) {
398                 final Vibration vib = removeVibrationLocked(token);
399                 if (vib == mCurrentVibration) {
400                     if (DEBUG) {
401                         Slog.d(TAG, "Canceling vibration.");
402                     }
403                     doCancelVibrateLocked();
404                     startNextVibrationLocked();
405                 }
406             }
407         }
408         finally {
409             Binder.restoreCallingIdentity(identity);
410         }
411     }
412 
413     private final Runnable mVibrationRunnable = new Runnable() {
414         @Override
415         public void run() {
416             synchronized (mVibrations) {
417                 doCancelVibrateLocked();
418                 startNextVibrationLocked();
419             }
420         }
421     };
422 
423     // Lock held on mVibrations
doCancelVibrateLocked()424     private void doCancelVibrateLocked() {
425         if (mThread != null) {
426             synchronized (mThread) {
427                 mThread.mDone = true;
428                 mThread.notify();
429             }
430             mThread = null;
431         }
432         doVibratorOff();
433         mH.removeCallbacks(mVibrationRunnable);
434         reportFinishVibrationLocked();
435     }
436 
437     // Lock held on mVibrations
startNextVibrationLocked()438     private void startNextVibrationLocked() {
439         if (mVibrations.size() <= 0) {
440             reportFinishVibrationLocked();
441             mCurrentVibration = null;
442             return;
443         }
444         startVibrationLocked(mVibrations.getFirst());
445     }
446 
447     // Lock held on mVibrations
startVibrationLocked(final Vibration vib)448     private void startVibrationLocked(final Vibration vib) {
449         try {
450             if (mLowPowerMode
451                     && vib.mUsageHint != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
452                 return;
453             }
454 
455             if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
456                     !shouldVibrateForRingtone()) {
457                 return;
458             }
459 
460             int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
461                     vib.mUsageHint, vib.mUid, vib.mOpPkg);
462             if (mode == AppOpsManager.MODE_ALLOWED) {
463                 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
464                     AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
465             }
466             if (mode == AppOpsManager.MODE_ALLOWED) {
467                 mCurrentVibration = vib;
468             } else {
469                 if (mode == AppOpsManager.MODE_ERRORED) {
470                     Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
471                 }
472                 mH.post(mVibrationRunnable);
473                 return;
474             }
475         } catch (RemoteException e) {
476         }
477         if (vib.mTimeout != 0) {
478             doVibratorOn(vib.mTimeout, vib.mUid, vib.mUsageHint);
479             mH.postDelayed(mVibrationRunnable, vib.mTimeout);
480         } else {
481             // mThread better be null here. doCancelVibrate should always be
482             // called before startNextVibrationLocked or startVibrationLocked.
483             mThread = new VibrateThread(vib);
484             mThread.start();
485         }
486     }
487 
shouldVibrateForRingtone()488     private boolean shouldVibrateForRingtone() {
489         AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
490         int ringerMode = audioManager.getRingerModeInternal();
491         // "Also vibrate for calls" Setting in Sound
492         if (Settings.System.getInt(
493                 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
494             return ringerMode != AudioManager.RINGER_MODE_SILENT;
495         } else {
496             return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
497         }
498     }
499 
reportFinishVibrationLocked()500     private void reportFinishVibrationLocked() {
501         if (mCurrentVibration != null) {
502             try {
503                 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
504                         AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
505                         mCurrentVibration.mOpPkg);
506             } catch (RemoteException e) {
507             }
508             mCurrentVibration = null;
509         }
510     }
511 
512     // Lock held on mVibrations
removeVibrationLocked(IBinder token)513     private Vibration removeVibrationLocked(IBinder token) {
514         ListIterator<Vibration> iter = mVibrations.listIterator(0);
515         while (iter.hasNext()) {
516             Vibration vib = iter.next();
517             if (vib.mToken == token) {
518                 iter.remove();
519                 unlinkVibration(vib);
520                 return vib;
521             }
522         }
523         // We might be looking for a simple vibration which is only stored in
524         // mCurrentVibration.
525         if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
526             unlinkVibration(mCurrentVibration);
527             return mCurrentVibration;
528         }
529         return null;
530     }
531 
unlinkVibration(Vibration vib)532     private void unlinkVibration(Vibration vib) {
533         if (vib.mPattern != null) {
534             // If Vibration object has a pattern,
535             // the Vibration object has also been linkedToDeath.
536             vib.mToken.unlinkToDeath(vib, 0);
537         }
538     }
539 
updateInputDeviceVibrators()540     private void updateInputDeviceVibrators() {
541         synchronized (mVibrations) {
542             doCancelVibrateLocked();
543 
544             synchronized (mInputDeviceVibrators) {
545                 mVibrateInputDevicesSetting = false;
546                 try {
547                     mVibrateInputDevicesSetting = Settings.System.getIntForUser(
548                             mContext.getContentResolver(),
549                             Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
550                 } catch (SettingNotFoundException snfe) {
551                 }
552 
553                 mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled();
554 
555                 if (mVibrateInputDevicesSetting) {
556                     if (!mInputDeviceListenerRegistered) {
557                         mInputDeviceListenerRegistered = true;
558                         mIm.registerInputDeviceListener(this, mH);
559                     }
560                 } else {
561                     if (mInputDeviceListenerRegistered) {
562                         mInputDeviceListenerRegistered = false;
563                         mIm.unregisterInputDeviceListener(this);
564                     }
565                 }
566 
567                 mInputDeviceVibrators.clear();
568                 if (mVibrateInputDevicesSetting) {
569                     int[] ids = mIm.getInputDeviceIds();
570                     for (int i = 0; i < ids.length; i++) {
571                         InputDevice device = mIm.getInputDevice(ids[i]);
572                         Vibrator vibrator = device.getVibrator();
573                         if (vibrator.hasVibrator()) {
574                             mInputDeviceVibrators.add(vibrator);
575                         }
576                     }
577                 }
578             }
579 
580             startNextVibrationLocked();
581         }
582     }
583 
584     @Override
onInputDeviceAdded(int deviceId)585     public void onInputDeviceAdded(int deviceId) {
586         updateInputDeviceVibrators();
587     }
588 
589     @Override
onInputDeviceChanged(int deviceId)590     public void onInputDeviceChanged(int deviceId) {
591         updateInputDeviceVibrators();
592     }
593 
594     @Override
onInputDeviceRemoved(int deviceId)595     public void onInputDeviceRemoved(int deviceId) {
596         updateInputDeviceVibrators();
597     }
598 
doVibratorExists()599     private boolean doVibratorExists() {
600         // For now, we choose to ignore the presence of input devices that have vibrators
601         // when reporting whether the device has a vibrator.  Applications often use this
602         // information to decide whether to enable certain features so they expect the
603         // result of hasVibrator() to be constant.  For now, just report whether
604         // the device has a built-in vibrator.
605         //synchronized (mInputDeviceVibrators) {
606         //    return !mInputDeviceVibrators.isEmpty() || vibratorExists();
607         //}
608         return vibratorExists();
609     }
610 
doVibratorOn(long millis, int uid, int usageHint)611     private void doVibratorOn(long millis, int uid, int usageHint) {
612         synchronized (mInputDeviceVibrators) {
613             if (DEBUG) {
614                 Slog.d(TAG, "Turning vibrator on for " + millis + " ms.");
615             }
616             try {
617                 mBatteryStatsService.noteVibratorOn(uid, millis);
618                 mCurVibUid = uid;
619             } catch (RemoteException e) {
620             }
621             final int vibratorCount = mInputDeviceVibrators.size();
622             if (vibratorCount != 0) {
623                 final AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usageHint)
624                         .build();
625                 for (int i = 0; i < vibratorCount; i++) {
626                     mInputDeviceVibrators.get(i).vibrate(millis, attributes);
627                 }
628             } else {
629                 vibratorOn(millis);
630             }
631         }
632     }
633 
doVibratorOff()634     private void doVibratorOff() {
635         synchronized (mInputDeviceVibrators) {
636             if (DEBUG) {
637                 Slog.d(TAG, "Turning vibrator off.");
638             }
639             if (mCurVibUid >= 0) {
640                 try {
641                     mBatteryStatsService.noteVibratorOff(mCurVibUid);
642                 } catch (RemoteException e) {
643                 }
644                 mCurVibUid = -1;
645             }
646             final int vibratorCount = mInputDeviceVibrators.size();
647             if (vibratorCount != 0) {
648                 for (int i = 0; i < vibratorCount; i++) {
649                     mInputDeviceVibrators.get(i).cancel();
650                 }
651             } else {
652                 vibratorOff();
653             }
654         }
655     }
656 
657     private class VibrateThread extends Thread {
658         final Vibration mVibration;
659         boolean mDone;
660 
VibrateThread(Vibration vib)661         VibrateThread(Vibration vib) {
662             mVibration = vib;
663             mTmpWorkSource.set(vib.mUid);
664             mWakeLock.setWorkSource(mTmpWorkSource);
665             mWakeLock.acquire();
666         }
667 
delay(long duration)668         private void delay(long duration) {
669             if (duration > 0) {
670                 long bedtime = duration + SystemClock.uptimeMillis();
671                 do {
672                     try {
673                         this.wait(duration);
674                     }
675                     catch (InterruptedException e) {
676                     }
677                     if (mDone) {
678                         break;
679                     }
680                     duration = bedtime - SystemClock.uptimeMillis();
681                 } while (duration > 0);
682             }
683         }
684 
run()685         public void run() {
686             Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
687             synchronized (this) {
688                 final long[] pattern = mVibration.mPattern;
689                 final int len = pattern.length;
690                 final int repeat = mVibration.mRepeat;
691                 final int uid = mVibration.mUid;
692                 final int usageHint = mVibration.mUsageHint;
693                 int index = 0;
694                 long duration = 0;
695 
696                 while (!mDone) {
697                     // add off-time duration to any accumulated on-time duration
698                     if (index < len) {
699                         duration += pattern[index++];
700                     }
701 
702                     // sleep until it is time to start the vibrator
703                     delay(duration);
704                     if (mDone) {
705                         break;
706                     }
707 
708                     if (index < len) {
709                         // read on-time duration and start the vibrator
710                         // duration is saved for delay() at top of loop
711                         duration = pattern[index++];
712                         if (duration > 0) {
713                             VibratorService.this.doVibratorOn(duration, uid, usageHint);
714                         }
715                     } else {
716                         if (repeat < 0) {
717                             break;
718                         } else {
719                             index = repeat;
720                             duration = 0;
721                         }
722                     }
723                 }
724                 mWakeLock.release();
725             }
726             synchronized (mVibrations) {
727                 if (mThread == this) {
728                     mThread = null;
729                 }
730                 if (!mDone) {
731                     // If this vibration finished naturally, start the next
732                     // vibration.
733                     unlinkVibration(mVibration);
734                     startNextVibrationLocked();
735                 }
736             }
737         }
738     }
739 
740     BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
741         @Override
742         public void onReceive(Context context, Intent intent) {
743             if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
744                 synchronized (mVibrations) {
745                     // When the system is entering a non-interactive state, we want
746                     // to cancel vibrations in case a misbehaving app has abandoned
747                     // them.  However it may happen that the system is currently playing
748                     // haptic feedback as part of the transition.  So we don't cancel
749                     // system vibrations.
750                     if (mCurrentVibration != null
751                             && !mCurrentVibration.isSystemHapticFeedback()) {
752                         doCancelVibrateLocked();
753                     }
754 
755                     // Clear all remaining vibrations.
756                     Iterator<Vibration> it = mVibrations.iterator();
757                     while (it.hasNext()) {
758                         Vibration vibration = it.next();
759                         if (vibration != mCurrentVibration) {
760                             unlinkVibration(vibration);
761                             it.remove();
762                         }
763                     }
764                 }
765             }
766         }
767     };
768 
769     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)770     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
771         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
772                 != PackageManager.PERMISSION_GRANTED) {
773 
774             pw.println("Permission Denial: can't dump vibrator service from from pid="
775                     + Binder.getCallingPid()
776                     + ", uid=" + Binder.getCallingUid());
777             return;
778         }
779         pw.println("Previous vibrations:");
780         synchronized (mVibrations) {
781             for (VibrationInfo info : mPreviousVibrations) {
782                 pw.print("  ");
783                 pw.println(info.toString());
784             }
785         }
786     }
787 }
788