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