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