VibratorService.java revision eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3a
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.AudioManager; 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 mStreamHint; 94 private final int mUid; 95 private final String mOpPkg; 96 97 Vibration(IBinder token, long millis, int streamHint, int uid, String opPkg) { 98 this(token, millis, null, 0, streamHint, uid, opPkg); 99 } 100 101 Vibration(IBinder token, long[] pattern, int repeat, int streamHint, int uid, 102 String opPkg) { 103 this(token, 0, pattern, repeat, streamHint, uid, opPkg); 104 } 105 106 private Vibration(IBinder token, long millis, long[] pattern, 107 int repeat, int streamHint, int uid, String opPkg) { 108 mToken = token; 109 mTimeout = millis; 110 mStartTime = SystemClock.uptimeMillis(); 111 mPattern = pattern; 112 mRepeat = repeat; 113 mStreamHint = streamHint; 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 streamHint, 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, streamHint, 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 streamHint, 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, streamHint, 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 && vib.mStreamHint != AudioManager.STREAM_RING) { 376 return; 377 } 378 379 int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE, 380 vib.mStreamHint, vib.mUid, vib.mOpPkg); 381 if (mode == AppOpsManager.MODE_ALLOWED) { 382 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), 383 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg); 384 } 385 if (mode != AppOpsManager.MODE_ALLOWED) { 386 if (mode == AppOpsManager.MODE_ERRORED) { 387 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid); 388 } 389 mH.post(mVibrationRunnable); 390 return; 391 } 392 } catch (RemoteException e) { 393 } 394 if (vib.mTimeout != 0) { 395 doVibratorOn(vib.mTimeout, vib.mUid, vib.mStreamHint); 396 mH.postDelayed(mVibrationRunnable, vib.mTimeout); 397 } else { 398 // mThread better be null here. doCancelVibrate should always be 399 // called before startNextVibrationLocked or startVibrationLocked. 400 mThread = new VibrateThread(vib); 401 mThread.start(); 402 } 403 } 404 405 private void reportFinishVibrationLocked() { 406 if (mCurrentVibration != null) { 407 try { 408 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), 409 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid, 410 mCurrentVibration.mOpPkg); 411 } catch (RemoteException e) { 412 } 413 mCurrentVibration = null; 414 } 415 } 416 417 // Lock held on mVibrations 418 private Vibration removeVibrationLocked(IBinder token) { 419 ListIterator<Vibration> iter = mVibrations.listIterator(0); 420 while (iter.hasNext()) { 421 Vibration vib = iter.next(); 422 if (vib.mToken == token) { 423 iter.remove(); 424 unlinkVibration(vib); 425 return vib; 426 } 427 } 428 // We might be looking for a simple vibration which is only stored in 429 // mCurrentVibration. 430 if (mCurrentVibration != null && mCurrentVibration.mToken == token) { 431 unlinkVibration(mCurrentVibration); 432 return mCurrentVibration; 433 } 434 return null; 435 } 436 437 private void unlinkVibration(Vibration vib) { 438 if (vib.mPattern != null) { 439 // If Vibration object has a pattern, 440 // the Vibration object has also been linkedToDeath. 441 vib.mToken.unlinkToDeath(vib, 0); 442 } 443 } 444 445 private void updateInputDeviceVibrators() { 446 synchronized (mVibrations) { 447 doCancelVibrateLocked(); 448 449 synchronized (mInputDeviceVibrators) { 450 mVibrateInputDevicesSetting = false; 451 try { 452 mVibrateInputDevicesSetting = Settings.System.getIntForUser( 453 mContext.getContentResolver(), 454 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0; 455 } catch (SettingNotFoundException snfe) { 456 } 457 458 mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled(); 459 460 if (mVibrateInputDevicesSetting) { 461 if (!mInputDeviceListenerRegistered) { 462 mInputDeviceListenerRegistered = true; 463 mIm.registerInputDeviceListener(this, mH); 464 } 465 } else { 466 if (mInputDeviceListenerRegistered) { 467 mInputDeviceListenerRegistered = false; 468 mIm.unregisterInputDeviceListener(this); 469 } 470 } 471 472 mInputDeviceVibrators.clear(); 473 if (mVibrateInputDevicesSetting) { 474 int[] ids = mIm.getInputDeviceIds(); 475 for (int i = 0; i < ids.length; i++) { 476 InputDevice device = mIm.getInputDevice(ids[i]); 477 Vibrator vibrator = device.getVibrator(); 478 if (vibrator.hasVibrator()) { 479 mInputDeviceVibrators.add(vibrator); 480 } 481 } 482 } 483 } 484 485 startNextVibrationLocked(); 486 } 487 } 488 489 @Override 490 public void onInputDeviceAdded(int deviceId) { 491 updateInputDeviceVibrators(); 492 } 493 494 @Override 495 public void onInputDeviceChanged(int deviceId) { 496 updateInputDeviceVibrators(); 497 } 498 499 @Override 500 public void onInputDeviceRemoved(int deviceId) { 501 updateInputDeviceVibrators(); 502 } 503 504 private boolean doVibratorExists() { 505 // For now, we choose to ignore the presence of input devices that have vibrators 506 // when reporting whether the device has a vibrator. Applications often use this 507 // information to decide whether to enable certain features so they expect the 508 // result of hasVibrator() to be constant. For now, just report whether 509 // the device has a built-in vibrator. 510 //synchronized (mInputDeviceVibrators) { 511 // return !mInputDeviceVibrators.isEmpty() || vibratorExists(); 512 //} 513 return vibratorExists(); 514 } 515 516 private void doVibratorOn(long millis, int uid, int streamHint) { 517 synchronized (mInputDeviceVibrators) { 518 try { 519 mBatteryStatsService.noteVibratorOn(uid, millis); 520 mCurVibUid = uid; 521 } catch (RemoteException e) { 522 } 523 final int vibratorCount = mInputDeviceVibrators.size(); 524 if (vibratorCount != 0) { 525 for (int i = 0; i < vibratorCount; i++) { 526 mInputDeviceVibrators.get(i).vibrate(millis, streamHint); 527 } 528 } else { 529 vibratorOn(millis); 530 } 531 } 532 } 533 534 private void doVibratorOff() { 535 synchronized (mInputDeviceVibrators) { 536 if (mCurVibUid >= 0) { 537 try { 538 mBatteryStatsService.noteVibratorOff(mCurVibUid); 539 } catch (RemoteException e) { 540 } 541 mCurVibUid = -1; 542 } 543 final int vibratorCount = mInputDeviceVibrators.size(); 544 if (vibratorCount != 0) { 545 for (int i = 0; i < vibratorCount; i++) { 546 mInputDeviceVibrators.get(i).cancel(); 547 } 548 } else { 549 vibratorOff(); 550 } 551 } 552 } 553 554 private class VibrateThread extends Thread { 555 final Vibration mVibration; 556 boolean mDone; 557 558 VibrateThread(Vibration vib) { 559 mVibration = vib; 560 mTmpWorkSource.set(vib.mUid); 561 mWakeLock.setWorkSource(mTmpWorkSource); 562 mWakeLock.acquire(); 563 } 564 565 private void delay(long duration) { 566 if (duration > 0) { 567 long bedtime = duration + SystemClock.uptimeMillis(); 568 do { 569 try { 570 this.wait(duration); 571 } 572 catch (InterruptedException e) { 573 } 574 if (mDone) { 575 break; 576 } 577 duration = bedtime - SystemClock.uptimeMillis(); 578 } while (duration > 0); 579 } 580 } 581 582 public void run() { 583 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 584 synchronized (this) { 585 final long[] pattern = mVibration.mPattern; 586 final int len = pattern.length; 587 final int repeat = mVibration.mRepeat; 588 final int uid = mVibration.mUid; 589 final int streamHint = mVibration.mStreamHint; 590 int index = 0; 591 long duration = 0; 592 593 while (!mDone) { 594 // add off-time duration to any accumulated on-time duration 595 if (index < len) { 596 duration += pattern[index++]; 597 } 598 599 // sleep until it is time to start the vibrator 600 delay(duration); 601 if (mDone) { 602 break; 603 } 604 605 if (index < len) { 606 // read on-time duration and start the vibrator 607 // duration is saved for delay() at top of loop 608 duration = pattern[index++]; 609 if (duration > 0) { 610 VibratorService.this.doVibratorOn(duration, uid, streamHint); 611 } 612 } else { 613 if (repeat < 0) { 614 break; 615 } else { 616 index = repeat; 617 duration = 0; 618 } 619 } 620 } 621 mWakeLock.release(); 622 } 623 synchronized (mVibrations) { 624 if (mThread == this) { 625 mThread = null; 626 } 627 if (!mDone) { 628 // If this vibration finished naturally, start the next 629 // vibration. 630 mVibrations.remove(mVibration); 631 unlinkVibration(mVibration); 632 startNextVibrationLocked(); 633 } 634 } 635 } 636 } 637 638 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 639 @Override 640 public void onReceive(Context context, Intent intent) { 641 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 642 synchronized (mVibrations) { 643 // When the system is entering a non-interactive state, we want 644 // to cancel vibrations in case a misbehaving app has abandoned 645 // them. However it may happen that the system is currently playing 646 // haptic feedback as part of the transition. So we don't cancel 647 // system vibrations. 648 if (mCurrentVibration != null 649 && !mCurrentVibration.isSystemHapticFeedback()) { 650 doCancelVibrateLocked(); 651 } 652 653 // Clear all remaining vibrations. 654 Iterator<Vibration> it = mVibrations.iterator(); 655 while (it.hasNext()) { 656 Vibration vibration = it.next(); 657 if (vibration != mCurrentVibration) { 658 unlinkVibration(vibration); 659 it.remove(); 660 } 661 } 662 } 663 } 664 } 665 }; 666} 667