Home | History | Annotate | Download | only in server
      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 
     91     native static boolean vibratorExists();
     92     native static void vibratorInit();
     93     native static void vibratorOn(long milliseconds);
     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 
    106         Vibration(IBinder token, long millis, int usageHint, int uid, String opPkg) {
    107             this(token, millis, null, 0, usageHint, uid, opPkg);
    108         }
    109 
    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 
    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 
    127         public void binderDied() {
    128             synchronized (mVibrations) {
    129                 mVibrations.remove(this);
    130                 if (this == mCurrentVibration) {
    131                     doCancelVibrateLocked();
    132                     startNextVibrationLocked();
    133                 }
    134             }
    135         }
    136 
    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 
    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 
    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
    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 
    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 
    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 {
    254         public SettingsObserver(Handler handler) {
    255             super(handler);
    256         }
    257 
    258         @Override
    259         public void onChange(boolean SelfChange) {
    260             updateInputDeviceVibrators();
    261         }
    262     }
    263 
    264     @Override // Binder call
    265     public boolean hasVibrator() {
    266         return doVibratorExists();
    267     }
    268 
    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
    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 
    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
    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 
    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
    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
    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
    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
    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 
    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 
    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
    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 
    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 
    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
    585     public void onInputDeviceAdded(int deviceId) {
    586         updateInputDeviceVibrators();
    587     }
    588 
    589     @Override
    590     public void onInputDeviceChanged(int deviceId) {
    591         updateInputDeviceVibrators();
    592     }
    593 
    594     @Override
    595     public void onInputDeviceRemoved(int deviceId) {
    596         updateInputDeviceVibrators();
    597     }
    598 
    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 
    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 
    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 
    661         VibrateThread(Vibration vib) {
    662             mVibration = vib;
    663             mTmpWorkSource.set(vib.mUid);
    664             mWakeLock.setWorkSource(mTmpWorkSource);
    665             mWakeLock.acquire();
    666         }
    667 
    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 
    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
    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