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