VibratorService.java revision 8fd7f1ed7c11d35b3f2a97878e68ee38a551dd15
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 17package com.android.server; 18 19import android.app.AppOpsManager; 20import android.content.BroadcastReceiver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.content.pm.PackageManager; 25import android.database.ContentObserver; 26import android.hardware.input.InputManager; 27import android.os.BatteryStats; 28import android.os.Handler; 29import android.os.IVibratorService; 30import android.os.PowerManager; 31import android.os.Process; 32import android.os.RemoteException; 33import android.os.IBinder; 34import android.os.Binder; 35import android.os.ServiceManager; 36import android.os.SystemClock; 37import android.os.UserHandle; 38import android.os.Vibrator; 39import android.os.WorkSource; 40import android.provider.Settings; 41import android.provider.Settings.SettingNotFoundException; 42import android.util.Slog; 43import android.view.InputDevice; 44 45import com.android.internal.app.IAppOpsService; 46import com.android.internal.app.IBatteryStats; 47 48import java.util.ArrayList; 49import java.util.LinkedList; 50import java.util.ListIterator; 51 52public class VibratorService extends IVibratorService.Stub 53 implements InputManager.InputDeviceListener { 54 private static final String TAG = "VibratorService"; 55 56 private final LinkedList<Vibration> mVibrations; 57 private Vibration mCurrentVibration; 58 private final WorkSource mTmpWorkSource = new WorkSource(); 59 private final Handler mH = new Handler(); 60 61 private final Context mContext; 62 private final PowerManager.WakeLock mWakeLock; 63 private final IAppOpsService mAppOpsService; 64 private final IBatteryStats mBatteryStatsService; 65 private InputManager mIm; 66 67 volatile VibrateThread mThread; 68 69 // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are 70 // to be acquired 71 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>(); 72 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators 73 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators 74 75 private int mCurVibUid = -1; 76 77 native static boolean vibratorExists(); 78 native static void vibratorOn(long milliseconds); 79 native static void vibratorOff(); 80 81 private class Vibration implements IBinder.DeathRecipient { 82 private final IBinder mToken; 83 private final long mTimeout; 84 private final long mStartTime; 85 private final long[] mPattern; 86 private final int mRepeat; 87 private final int mStreamHint; 88 private final int mUid; 89 private final String mOpPkg; 90 91 Vibration(IBinder token, long millis, int streamHint, int uid, String opPkg) { 92 this(token, millis, null, 0, streamHint, uid, opPkg); 93 } 94 95 Vibration(IBinder token, long[] pattern, int repeat, int streamHint, int uid, 96 String opPkg) { 97 this(token, 0, pattern, repeat, streamHint, uid, opPkg); 98 } 99 100 private Vibration(IBinder token, long millis, long[] pattern, 101 int repeat, int streamHint, int uid, String opPkg) { 102 mToken = token; 103 mTimeout = millis; 104 mStartTime = SystemClock.uptimeMillis(); 105 mPattern = pattern; 106 mRepeat = repeat; 107 mStreamHint = streamHint; 108 mUid = uid; 109 mOpPkg = opPkg; 110 } 111 112 public void binderDied() { 113 synchronized (mVibrations) { 114 mVibrations.remove(this); 115 if (this == mCurrentVibration) { 116 doCancelVibrateLocked(); 117 startNextVibrationLocked(); 118 } 119 } 120 } 121 122 public boolean hasLongerTimeout(long millis) { 123 if (mTimeout == 0) { 124 // This is a pattern, return false to play the simple 125 // vibration. 126 return false; 127 } 128 if ((mStartTime + mTimeout) 129 < (SystemClock.uptimeMillis() + millis)) { 130 // If this vibration will end before the time passed in, let 131 // the new vibration play. 132 return false; 133 } 134 return true; 135 } 136 } 137 138 VibratorService(Context context) { 139 // Reset the hardware to a default state, in case this is a runtime 140 // restart instead of a fresh boot. 141 vibratorOff(); 142 143 mContext = context; 144 PowerManager pm = (PowerManager)context.getSystemService( 145 Context.POWER_SERVICE); 146 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*"); 147 mWakeLock.setReferenceCounted(true); 148 149 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE)); 150 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService( 151 BatteryStats.SERVICE_NAME)); 152 153 mVibrations = new LinkedList<Vibration>(); 154 155 IntentFilter filter = new IntentFilter(); 156 filter.addAction(Intent.ACTION_SCREEN_OFF); 157 context.registerReceiver(mIntentReceiver, filter); 158 } 159 160 public void systemReady() { 161 mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE); 162 163 mContext.getContentResolver().registerContentObserver( 164 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true, 165 new ContentObserver(mH) { 166 @Override 167 public void onChange(boolean selfChange) { 168 updateInputDeviceVibrators(); 169 } 170 }, UserHandle.USER_ALL); 171 172 mContext.registerReceiver(new BroadcastReceiver() { 173 @Override 174 public void onReceive(Context context, Intent intent) { 175 updateInputDeviceVibrators(); 176 } 177 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH); 178 179 updateInputDeviceVibrators(); 180 } 181 182 public boolean hasVibrator() { 183 return doVibratorExists(); 184 } 185 186 private void verifyIncomingUid(int uid) { 187 if (uid == Binder.getCallingUid()) { 188 return; 189 } 190 if (Binder.getCallingPid() == Process.myPid()) { 191 return; 192 } 193 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 194 Binder.getCallingPid(), Binder.getCallingUid(), null); 195 } 196 197 public void vibrate(int uid, String opPkg, long milliseconds, int streamHint, 198 IBinder token) { 199 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 200 != PackageManager.PERMISSION_GRANTED) { 201 throw new SecurityException("Requires VIBRATE permission"); 202 } 203 verifyIncomingUid(uid); 204 // We're running in the system server so we cannot crash. Check for a 205 // timeout of 0 or negative. This will ensure that a vibration has 206 // either a timeout of > 0 or a non-null pattern. 207 if (milliseconds <= 0 || (mCurrentVibration != null 208 && mCurrentVibration.hasLongerTimeout(milliseconds))) { 209 // Ignore this vibration since the current vibration will play for 210 // longer than milliseconds. 211 return; 212 } 213 214 Vibration vib = new Vibration(token, milliseconds, streamHint, uid, opPkg); 215 216 final long ident = Binder.clearCallingIdentity(); 217 try { 218 synchronized (mVibrations) { 219 removeVibrationLocked(token); 220 doCancelVibrateLocked(); 221 mCurrentVibration = vib; 222 startVibrationLocked(vib); 223 } 224 } finally { 225 Binder.restoreCallingIdentity(ident); 226 } 227 } 228 229 private boolean isAll0(long[] pattern) { 230 int N = pattern.length; 231 for (int i = 0; i < N; i++) { 232 if (pattern[i] != 0) { 233 return false; 234 } 235 } 236 return true; 237 } 238 239 public void vibratePattern(int uid, String packageName, long[] pattern, int repeat, 240 int streamHint, IBinder token) { 241 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 242 != PackageManager.PERMISSION_GRANTED) { 243 throw new SecurityException("Requires VIBRATE permission"); 244 } 245 verifyIncomingUid(uid); 246 // so wakelock calls will succeed 247 long identity = Binder.clearCallingIdentity(); 248 try { 249 if (false) { 250 String s = ""; 251 int N = pattern.length; 252 for (int i=0; i<N; i++) { 253 s += " " + pattern[i]; 254 } 255 Slog.i(TAG, "vibrating with pattern: " + s); 256 } 257 258 // we're running in the server so we can't fail 259 if (pattern == null || pattern.length == 0 260 || isAll0(pattern) 261 || repeat >= pattern.length || token == null) { 262 return; 263 } 264 265 Vibration vib = new Vibration(token, pattern, repeat, streamHint, uid, packageName); 266 try { 267 token.linkToDeath(vib, 0); 268 } catch (RemoteException e) { 269 return; 270 } 271 272 synchronized (mVibrations) { 273 removeVibrationLocked(token); 274 doCancelVibrateLocked(); 275 if (repeat >= 0) { 276 mVibrations.addFirst(vib); 277 startNextVibrationLocked(); 278 } else { 279 // A negative repeat means that this pattern is not meant 280 // to repeat. Treat it like a simple vibration. 281 mCurrentVibration = vib; 282 startVibrationLocked(vib); 283 } 284 } 285 } 286 finally { 287 Binder.restoreCallingIdentity(identity); 288 } 289 } 290 291 public void cancelVibrate(IBinder token) { 292 mContext.enforceCallingOrSelfPermission( 293 android.Manifest.permission.VIBRATE, 294 "cancelVibrate"); 295 296 // so wakelock calls will succeed 297 long identity = Binder.clearCallingIdentity(); 298 try { 299 synchronized (mVibrations) { 300 final Vibration vib = removeVibrationLocked(token); 301 if (vib == mCurrentVibration) { 302 doCancelVibrateLocked(); 303 startNextVibrationLocked(); 304 } 305 } 306 } 307 finally { 308 Binder.restoreCallingIdentity(identity); 309 } 310 } 311 312 private final Runnable mVibrationRunnable = new Runnable() { 313 public void run() { 314 synchronized (mVibrations) { 315 doCancelVibrateLocked(); 316 startNextVibrationLocked(); 317 } 318 } 319 }; 320 321 // Lock held on mVibrations 322 private void doCancelVibrateLocked() { 323 if (mThread != null) { 324 synchronized (mThread) { 325 mThread.mDone = true; 326 mThread.notify(); 327 } 328 mThread = null; 329 } 330 doVibratorOff(); 331 mH.removeCallbacks(mVibrationRunnable); 332 reportFinishVibrationLocked(); 333 } 334 335 // Lock held on mVibrations 336 private void startNextVibrationLocked() { 337 if (mVibrations.size() <= 0) { 338 reportFinishVibrationLocked(); 339 mCurrentVibration = null; 340 return; 341 } 342 mCurrentVibration = mVibrations.getFirst(); 343 startVibrationLocked(mCurrentVibration); 344 } 345 346 // Lock held on mVibrations 347 private void startVibrationLocked(final Vibration vib) { 348 try { 349 int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE, 350 vib.mStreamHint, vib.mUid, vib.mOpPkg); 351 if (mode == AppOpsManager.MODE_ALLOWED) { 352 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), 353 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg); 354 } 355 if (mode != AppOpsManager.MODE_ALLOWED) { 356 if (mode == AppOpsManager.MODE_ERRORED) { 357 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid); 358 } 359 mH.post(mVibrationRunnable); 360 return; 361 } 362 } catch (RemoteException e) { 363 } 364 if (vib.mTimeout != 0) { 365 doVibratorOn(vib.mTimeout, vib.mUid, vib.mStreamHint); 366 mH.postDelayed(mVibrationRunnable, vib.mTimeout); 367 } else { 368 // mThread better be null here. doCancelVibrate should always be 369 // called before startNextVibrationLocked or startVibrationLocked. 370 mThread = new VibrateThread(vib); 371 mThread.start(); 372 } 373 } 374 375 private void reportFinishVibrationLocked() { 376 if (mCurrentVibration != null) { 377 try { 378 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), 379 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid, 380 mCurrentVibration.mOpPkg); 381 } catch (RemoteException e) { 382 } 383 mCurrentVibration = null; 384 } 385 } 386 387 // Lock held on mVibrations 388 private Vibration removeVibrationLocked(IBinder token) { 389 ListIterator<Vibration> iter = mVibrations.listIterator(0); 390 while (iter.hasNext()) { 391 Vibration vib = iter.next(); 392 if (vib.mToken == token) { 393 iter.remove(); 394 unlinkVibration(vib); 395 return vib; 396 } 397 } 398 // We might be looking for a simple vibration which is only stored in 399 // mCurrentVibration. 400 if (mCurrentVibration != null && mCurrentVibration.mToken == token) { 401 unlinkVibration(mCurrentVibration); 402 return mCurrentVibration; 403 } 404 return null; 405 } 406 407 private void unlinkVibration(Vibration vib) { 408 if (vib.mPattern != null) { 409 // If Vibration object has a pattern, 410 // the Vibration object has also been linkedToDeath. 411 vib.mToken.unlinkToDeath(vib, 0); 412 } 413 } 414 415 private void updateInputDeviceVibrators() { 416 synchronized (mVibrations) { 417 doCancelVibrateLocked(); 418 419 synchronized (mInputDeviceVibrators) { 420 mVibrateInputDevicesSetting = false; 421 try { 422 mVibrateInputDevicesSetting = Settings.System.getIntForUser( 423 mContext.getContentResolver(), 424 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0; 425 } catch (SettingNotFoundException snfe) { 426 } 427 428 if (mVibrateInputDevicesSetting) { 429 if (!mInputDeviceListenerRegistered) { 430 mInputDeviceListenerRegistered = true; 431 mIm.registerInputDeviceListener(this, mH); 432 } 433 } else { 434 if (mInputDeviceListenerRegistered) { 435 mInputDeviceListenerRegistered = false; 436 mIm.unregisterInputDeviceListener(this); 437 } 438 } 439 440 mInputDeviceVibrators.clear(); 441 if (mVibrateInputDevicesSetting) { 442 int[] ids = mIm.getInputDeviceIds(); 443 for (int i = 0; i < ids.length; i++) { 444 InputDevice device = mIm.getInputDevice(ids[i]); 445 Vibrator vibrator = device.getVibrator(); 446 if (vibrator.hasVibrator()) { 447 mInputDeviceVibrators.add(vibrator); 448 } 449 } 450 } 451 } 452 453 startNextVibrationLocked(); 454 } 455 } 456 457 @Override 458 public void onInputDeviceAdded(int deviceId) { 459 updateInputDeviceVibrators(); 460 } 461 462 @Override 463 public void onInputDeviceChanged(int deviceId) { 464 updateInputDeviceVibrators(); 465 } 466 467 @Override 468 public void onInputDeviceRemoved(int deviceId) { 469 updateInputDeviceVibrators(); 470 } 471 472 private boolean doVibratorExists() { 473 // For now, we choose to ignore the presence of input devices that have vibrators 474 // when reporting whether the device has a vibrator. Applications often use this 475 // information to decide whether to enable certain features so they expect the 476 // result of hasVibrator() to be constant. For now, just report whether 477 // the device has a built-in vibrator. 478 //synchronized (mInputDeviceVibrators) { 479 // return !mInputDeviceVibrators.isEmpty() || vibratorExists(); 480 //} 481 return vibratorExists(); 482 } 483 484 private void doVibratorOn(long millis, int uid, int streamHint) { 485 synchronized (mInputDeviceVibrators) { 486 try { 487 mBatteryStatsService.noteVibratorOn(uid, millis); 488 mCurVibUid = uid; 489 } catch (RemoteException e) { 490 } 491 final int vibratorCount = mInputDeviceVibrators.size(); 492 if (vibratorCount != 0) { 493 for (int i = 0; i < vibratorCount; i++) { 494 mInputDeviceVibrators.get(i).vibrate(millis, streamHint); 495 } 496 } else { 497 vibratorOn(millis); 498 } 499 } 500 } 501 502 private void doVibratorOff() { 503 synchronized (mInputDeviceVibrators) { 504 if (mCurVibUid >= 0) { 505 try { 506 mBatteryStatsService.noteVibratorOff(mCurVibUid); 507 } catch (RemoteException e) { 508 } 509 mCurVibUid = -1; 510 } 511 final int vibratorCount = mInputDeviceVibrators.size(); 512 if (vibratorCount != 0) { 513 for (int i = 0; i < vibratorCount; i++) { 514 mInputDeviceVibrators.get(i).cancel(); 515 } 516 } else { 517 vibratorOff(); 518 } 519 } 520 } 521 522 private class VibrateThread extends Thread { 523 final Vibration mVibration; 524 boolean mDone; 525 526 VibrateThread(Vibration vib) { 527 mVibration = vib; 528 mTmpWorkSource.set(vib.mUid); 529 mWakeLock.setWorkSource(mTmpWorkSource); 530 mWakeLock.acquire(); 531 } 532 533 private void delay(long duration) { 534 if (duration > 0) { 535 long bedtime = duration + SystemClock.uptimeMillis(); 536 do { 537 try { 538 this.wait(duration); 539 } 540 catch (InterruptedException e) { 541 } 542 if (mDone) { 543 break; 544 } 545 duration = bedtime - SystemClock.uptimeMillis(); 546 } while (duration > 0); 547 } 548 } 549 550 public void run() { 551 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 552 synchronized (this) { 553 final long[] pattern = mVibration.mPattern; 554 final int len = pattern.length; 555 final int repeat = mVibration.mRepeat; 556 final int uid = mVibration.mUid; 557 final int streamHint = mVibration.mStreamHint; 558 int index = 0; 559 long duration = 0; 560 561 while (!mDone) { 562 // add off-time duration to any accumulated on-time duration 563 if (index < len) { 564 duration += pattern[index++]; 565 } 566 567 // sleep until it is time to start the vibrator 568 delay(duration); 569 if (mDone) { 570 break; 571 } 572 573 if (index < len) { 574 // read on-time duration and start the vibrator 575 // duration is saved for delay() at top of loop 576 duration = pattern[index++]; 577 if (duration > 0) { 578 VibratorService.this.doVibratorOn(duration, uid, streamHint); 579 } 580 } else { 581 if (repeat < 0) { 582 break; 583 } else { 584 index = repeat; 585 duration = 0; 586 } 587 } 588 } 589 mWakeLock.release(); 590 } 591 synchronized (mVibrations) { 592 if (mThread == this) { 593 mThread = null; 594 } 595 if (!mDone) { 596 // If this vibration finished naturally, start the next 597 // vibration. 598 mVibrations.remove(mVibration); 599 unlinkVibration(mVibration); 600 startNextVibrationLocked(); 601 } 602 } 603 } 604 }; 605 606 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 607 public void onReceive(Context context, Intent intent) { 608 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 609 synchronized (mVibrations) { 610 doCancelVibrateLocked(); 611 612 int size = mVibrations.size(); 613 for(int i = 0; i < size; i++) { 614 unlinkVibration(mVibrations.get(i)); 615 } 616 617 mVibrations.clear(); 618 } 619 } 620 } 621 }; 622} 623