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