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