/services/java/com/android/server/VibratorService.java

https://github.com/aizuzi/platform_frameworks_base · Java · 613 lines · 490 code · 66 blank · 57 comment · 87 complexity · 3858bab4bdff009bda8cf93da0e8edad MD5 · raw file

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