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