1 /* 2 * Copyright (C) 2021 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.vibrator; 18 19 import static android.os.VibrationEffect.VibrationParameter.targetAmplitude; 20 import static android.os.VibrationEffect.VibrationParameter.targetFrequency; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.app.ActivityManager; 25 import android.app.AppOpsManager; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.content.pm.PackageManager; 31 import android.hardware.vibrator.IVibrator; 32 import android.os.BatteryStats; 33 import android.os.Binder; 34 import android.os.Build; 35 import android.os.CombinedVibration; 36 import android.os.ExternalVibration; 37 import android.os.Handler; 38 import android.os.IBinder; 39 import android.os.IExternalVibratorService; 40 import android.os.IVibratorManagerService; 41 import android.os.IVibratorStateListener; 42 import android.os.Looper; 43 import android.os.PowerManager; 44 import android.os.Process; 45 import android.os.RemoteException; 46 import android.os.ResultReceiver; 47 import android.os.ServiceManager; 48 import android.os.ShellCallback; 49 import android.os.ShellCommand; 50 import android.os.SystemClock; 51 import android.os.Trace; 52 import android.os.VibrationAttributes; 53 import android.os.VibrationEffect; 54 import android.os.VibratorInfo; 55 import android.os.vibrator.PrebakedSegment; 56 import android.os.vibrator.VibrationEffectSegment; 57 import android.text.TextUtils; 58 import android.util.Slog; 59 import android.util.SparseArray; 60 import android.util.proto.ProtoOutputStream; 61 import android.view.Display; 62 63 import com.android.internal.annotations.GuardedBy; 64 import com.android.internal.annotations.VisibleForTesting; 65 import com.android.internal.app.IBatteryStats; 66 import com.android.internal.util.DumpUtils; 67 import com.android.internal.util.FrameworkStatsLog; 68 import com.android.server.SystemService; 69 70 import libcore.util.NativeAllocationRegistry; 71 72 import java.io.FileDescriptor; 73 import java.io.PrintWriter; 74 import java.lang.ref.WeakReference; 75 import java.time.Duration; 76 import java.util.ArrayList; 77 import java.util.Arrays; 78 import java.util.LinkedList; 79 import java.util.List; 80 import java.util.concurrent.atomic.AtomicInteger; 81 import java.util.function.Consumer; 82 import java.util.function.Function; 83 84 /** System implementation of {@link IVibratorManagerService}. */ 85 public class VibratorManagerService extends IVibratorManagerService.Stub { 86 private static final String TAG = "VibratorManagerService"; 87 private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service"; 88 private static final boolean DEBUG = false; 89 private static final VibrationAttributes DEFAULT_ATTRIBUTES = 90 new VibrationAttributes.Builder().build(); 91 private static final int ATTRIBUTES_ALL_BYPASS_FLAGS = 92 VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY 93 | VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF; 94 95 /** Fixed large duration used to note repeating vibrations to {@link IBatteryStats}. */ 96 private static final long BATTERY_STATS_REPEATING_VIBRATION_DURATION = 5_000; 97 98 /** 99 * Maximum millis to wait for a vibration thread cancellation to "clean up" and finish, when 100 * blocking for an external vibration. In practice, this should be plenty. 101 */ 102 private static final long VIBRATION_CANCEL_WAIT_MILLIS = 5000; 103 104 /** Lifecycle responsible for initializing this class at the right system server phases. */ 105 public static class Lifecycle extends SystemService { 106 private VibratorManagerService mService; 107 Lifecycle(Context context)108 public Lifecycle(Context context) { 109 super(context); 110 } 111 112 @Override onStart()113 public void onStart() { 114 mService = new VibratorManagerService(getContext(), new Injector()); 115 publishBinderService(Context.VIBRATOR_MANAGER_SERVICE, mService); 116 } 117 118 @Override onBootPhase(int phase)119 public void onBootPhase(int phase) { 120 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 121 mService.systemReady(); 122 } 123 } 124 } 125 126 // Used to generate globally unique vibration ids. 127 private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback 128 129 private final Object mLock = new Object(); 130 private final Context mContext; 131 private final PowerManager.WakeLock mWakeLock; 132 private final IBatteryStats mBatteryStatsService; 133 private final VibratorFrameworkStatsLogger mFrameworkStatsLogger; 134 private final Handler mHandler; 135 private final VibrationThread mVibrationThread; 136 private final AppOpsManager mAppOps; 137 private final NativeWrapper mNativeWrapper; 138 private final VibratorManagerRecords mVibratorManagerRecords; 139 private final long mCapabilities; 140 private final int[] mVibratorIds; 141 private final SparseArray<VibratorController> mVibrators; 142 private final VibrationThreadCallbacks mVibrationThreadCallbacks = 143 new VibrationThreadCallbacks(); 144 @GuardedBy("mLock") 145 private final SparseArray<AlwaysOnVibration> mAlwaysOnEffects = new SparseArray<>(); 146 @GuardedBy("mLock") 147 private VibrationStepConductor mCurrentVibration; 148 @GuardedBy("mLock") 149 private VibrationStepConductor mNextVibration; 150 @GuardedBy("mLock") 151 private ExternalVibrationHolder mCurrentExternalVibration; 152 @GuardedBy("mLock") 153 private boolean mServiceReady; 154 155 private final VibrationSettings mVibrationSettings; 156 private final VibrationScaler mVibrationScaler; 157 private final InputDeviceDelegate mInputDeviceDelegate; 158 private final DeviceVibrationEffectAdapter mDeviceVibrationEffectAdapter; 159 160 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 161 @Override 162 public void onReceive(Context context, Intent intent) { 163 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 164 synchronized (mLock) { 165 // When the system is entering a non-interactive state, we want to cancel 166 // vibrations in case a misbehaving app has abandoned them. 167 if (shouldCancelOnScreenOffLocked(mNextVibration)) { 168 clearNextVibrationLocked( 169 new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF)); 170 } 171 if (shouldCancelOnScreenOffLocked(mCurrentVibration)) { 172 mCurrentVibration.notifyCancelled( 173 new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF), 174 /* immediate= */ false); 175 } 176 } 177 } 178 } 179 }; 180 nativeInit(OnSyncedVibrationCompleteListener listener)181 static native long nativeInit(OnSyncedVibrationCompleteListener listener); 182 nativeGetFinalizer()183 static native long nativeGetFinalizer(); 184 nativeGetCapabilities(long nativeServicePtr)185 static native long nativeGetCapabilities(long nativeServicePtr); 186 nativeGetVibratorIds(long nativeServicePtr)187 static native int[] nativeGetVibratorIds(long nativeServicePtr); 188 nativePrepareSynced(long nativeServicePtr, int[] vibratorIds)189 static native boolean nativePrepareSynced(long nativeServicePtr, int[] vibratorIds); 190 nativeTriggerSynced(long nativeServicePtr, long vibrationId)191 static native boolean nativeTriggerSynced(long nativeServicePtr, long vibrationId); 192 nativeCancelSynced(long nativeServicePtr)193 static native void nativeCancelSynced(long nativeServicePtr); 194 195 @VisibleForTesting VibratorManagerService(Context context, Injector injector)196 VibratorManagerService(Context context, Injector injector) { 197 mContext = context; 198 mHandler = injector.createHandler(Looper.myLooper()); 199 200 mVibrationSettings = new VibrationSettings(mContext, mHandler); 201 mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings); 202 mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler); 203 mDeviceVibrationEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings); 204 205 VibrationCompleteListener listener = new VibrationCompleteListener(this); 206 mNativeWrapper = injector.getNativeWrapper(); 207 mNativeWrapper.init(listener); 208 209 int dumpLimit = mContext.getResources().getInteger( 210 com.android.internal.R.integer.config_previousVibrationsDumpLimit); 211 mVibratorManagerRecords = new VibratorManagerRecords(dumpLimit); 212 213 mBatteryStatsService = injector.getBatteryStatsService(); 214 mFrameworkStatsLogger = injector.getFrameworkStatsLogger(mHandler); 215 216 mAppOps = mContext.getSystemService(AppOpsManager.class); 217 218 PowerManager pm = context.getSystemService(PowerManager.class); 219 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*"); 220 mWakeLock.setReferenceCounted(true); 221 mVibrationThread = new VibrationThread(mWakeLock, mVibrationThreadCallbacks); 222 mVibrationThread.start(); 223 224 // Load vibrator hardware info. The vibrator ids and manager capabilities are loaded only 225 // once and assumed unchanged for the lifecycle of this service. Each individual vibrator 226 // can still retry loading each individual vibrator hardware spec once more at systemReady. 227 mCapabilities = mNativeWrapper.getCapabilities(); 228 int[] vibratorIds = mNativeWrapper.getVibratorIds(); 229 if (vibratorIds == null) { 230 mVibratorIds = new int[0]; 231 mVibrators = new SparseArray<>(0); 232 } else { 233 // Keep original vibrator id order, which might be meaningful. 234 mVibratorIds = vibratorIds; 235 mVibrators = new SparseArray<>(mVibratorIds.length); 236 for (int vibratorId : vibratorIds) { 237 mVibrators.put(vibratorId, injector.createVibratorController(vibratorId, listener)); 238 } 239 } 240 241 // Reset the hardware to a default state, in case this is a runtime restart instead of a 242 // fresh boot. 243 mNativeWrapper.cancelSynced(); 244 for (int i = 0; i < mVibrators.size(); i++) { 245 mVibrators.valueAt(i).reset(); 246 } 247 248 IntentFilter filter = new IntentFilter(); 249 filter.addAction(Intent.ACTION_SCREEN_OFF); 250 context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_NOT_EXPORTED); 251 252 injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService()); 253 } 254 255 /** Finish initialization at boot phase {@link SystemService#PHASE_SYSTEM_SERVICES_READY}. */ 256 @VisibleForTesting systemReady()257 void systemReady() { 258 Slog.v(TAG, "Initializing VibratorManager service..."); 259 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "systemReady"); 260 try { 261 // Will retry to load each vibrator's info, if any request have failed. 262 for (int i = 0; i < mVibrators.size(); i++) { 263 mVibrators.valueAt(i).reloadVibratorInfoIfNeeded(); 264 } 265 266 mVibrationSettings.onSystemReady(); 267 mInputDeviceDelegate.onSystemReady(); 268 269 mVibrationSettings.addListener(this::updateServiceState); 270 271 // Will update settings and input devices. 272 updateServiceState(); 273 } finally { 274 synchronized (mLock) { 275 mServiceReady = true; 276 } 277 Slog.v(TAG, "VibratorManager service initialized"); 278 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 279 } 280 } 281 282 @Override // Binder call getVibratorIds()283 public int[] getVibratorIds() { 284 return Arrays.copyOf(mVibratorIds, mVibratorIds.length); 285 } 286 287 @Override // Binder call 288 @Nullable getVibratorInfo(int vibratorId)289 public VibratorInfo getVibratorInfo(int vibratorId) { 290 final VibratorController controller = mVibrators.get(vibratorId); 291 if (controller == null) { 292 return null; 293 } 294 final VibratorInfo info = controller.getVibratorInfo(); 295 synchronized (mLock) { 296 if (mServiceReady) { 297 return info; 298 } 299 } 300 // If the service is not ready and the load was unsuccessful then return null while waiting 301 // for the service to be ready. It will retry to load the complete info from the HAL. 302 return controller.isVibratorInfoLoadSuccessful() ? info : null; 303 } 304 305 @Override // Binder call isVibrating(int vibratorId)306 public boolean isVibrating(int vibratorId) { 307 mContext.enforceCallingOrSelfPermission( 308 android.Manifest.permission.ACCESS_VIBRATOR_STATE, 309 "isVibrating"); 310 VibratorController controller = mVibrators.get(vibratorId); 311 return controller != null && controller.isVibrating(); 312 } 313 314 @Override // Binder call registerVibratorStateListener(int vibratorId, IVibratorStateListener listener)315 public boolean registerVibratorStateListener(int vibratorId, IVibratorStateListener listener) { 316 mContext.enforceCallingOrSelfPermission( 317 android.Manifest.permission.ACCESS_VIBRATOR_STATE, 318 "registerVibratorStateListener"); 319 VibratorController controller = mVibrators.get(vibratorId); 320 if (controller == null) { 321 return false; 322 } 323 return controller.registerVibratorStateListener(listener); 324 } 325 326 @Override // Binder call unregisterVibratorStateListener(int vibratorId, IVibratorStateListener listener)327 public boolean unregisterVibratorStateListener(int vibratorId, 328 IVibratorStateListener listener) { 329 mContext.enforceCallingOrSelfPermission( 330 android.Manifest.permission.ACCESS_VIBRATOR_STATE, 331 "unregisterVibratorStateListener"); 332 VibratorController controller = mVibrators.get(vibratorId); 333 if (controller == null) { 334 return false; 335 } 336 return controller.unregisterVibratorStateListener(listener); 337 } 338 339 @Override // Binder call setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, @Nullable CombinedVibration effect, @Nullable VibrationAttributes attrs)340 public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, 341 @Nullable CombinedVibration effect, @Nullable VibrationAttributes attrs) { 342 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "setAlwaysOnEffect"); 343 try { 344 mContext.enforceCallingOrSelfPermission( 345 android.Manifest.permission.VIBRATE_ALWAYS_ON, 346 "setAlwaysOnEffect"); 347 348 if (effect == null) { 349 synchronized (mLock) { 350 mAlwaysOnEffects.delete(alwaysOnId); 351 onAllVibratorsLocked(v -> { 352 if (v.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) { 353 v.updateAlwaysOn(alwaysOnId, /* effect= */ null); 354 } 355 }); 356 } 357 return true; 358 } 359 if (!isEffectValid(effect)) { 360 return false; 361 } 362 attrs = fixupVibrationAttributes(attrs, effect); 363 synchronized (mLock) { 364 SparseArray<PrebakedSegment> effects = fixupAlwaysOnEffectsLocked(effect); 365 if (effects == null) { 366 // Invalid effects set in CombinedVibrationEffect, or always-on capability is 367 // missing on individual vibrators. 368 return false; 369 } 370 AlwaysOnVibration alwaysOnVibration = new AlwaysOnVibration( 371 alwaysOnId, uid, opPkg, attrs, effects); 372 mAlwaysOnEffects.put(alwaysOnId, alwaysOnVibration); 373 updateAlwaysOnLocked(alwaysOnVibration); 374 } 375 return true; 376 } finally { 377 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 378 } 379 } 380 381 @Override // Binder call vibrate(int uid, int displayId, String opPkg, @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs, String reason, IBinder token)382 public void vibrate(int uid, int displayId, String opPkg, @NonNull CombinedVibration effect, 383 @Nullable VibrationAttributes attrs, String reason, IBinder token) { 384 vibrateInternal(uid, displayId, opPkg, effect, attrs, reason, token); 385 } 386 387 /** 388 * An internal-only version of vibrate that allows the caller access to the {@link Vibration}. 389 * The Vibration is only returned if it is ongoing after this method returns. 390 */ 391 @Nullable 392 @VisibleForTesting vibrateInternal(int uid, int displayId, String opPkg, @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs, String reason, IBinder token)393 Vibration vibrateInternal(int uid, int displayId, String opPkg, 394 @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs, 395 String reason, IBinder token) { 396 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason); 397 try { 398 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.VIBRATE, "vibrate"); 399 400 if (token == null) { 401 Slog.e(TAG, "token must not be null"); 402 return null; 403 } 404 enforceUpdateAppOpsStatsPermission(uid); 405 if (!isEffectValid(effect)) { 406 return null; 407 } 408 attrs = fixupVibrationAttributes(attrs, effect); 409 // Create Vibration.Stats as close to the received request as possible, for tracking. 410 Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs, 411 uid, displayId, opPkg, reason); 412 fillVibrationFallbacks(vib, effect); 413 414 if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) { 415 // Force update of user settings before checking if this vibration effect should 416 // be ignored or scaled. 417 mVibrationSettings.mSettingObserver.onChange(false); 418 } 419 420 synchronized (mLock) { 421 if (DEBUG) { 422 Slog.d(TAG, "Starting vibrate for vibration " + vib.id); 423 } 424 int ignoredByUid = -1; 425 int ignoredByUsage = -1; 426 Vibration.Status status = null; 427 428 // Check if user settings or DnD is set to ignore this vibration. 429 status = shouldIgnoreVibrationLocked(vib.uid, vib.displayId, vib.opPkg, vib.attrs); 430 431 // Check if something has external control, assume it's more important. 432 if ((status == null) && (mCurrentExternalVibration != null)) { 433 status = Vibration.Status.IGNORED_FOR_EXTERNAL; 434 ignoredByUid = mCurrentExternalVibration.externalVibration.getUid(); 435 ignoredByUsage = mCurrentExternalVibration.externalVibration 436 .getVibrationAttributes().getUsage(); 437 } 438 439 // Check if ongoing vibration is more important than this vibration. 440 if (status == null) { 441 status = shouldIgnoreVibrationForOngoingLocked(vib); 442 if (status != null) { 443 ignoredByUid = mCurrentVibration.getVibration().uid; 444 ignoredByUsage = mCurrentVibration.getVibration().attrs.getUsage(); 445 } 446 } 447 448 // If not ignored so far then try to start this vibration. 449 if (status == null) { 450 final long ident = Binder.clearCallingIdentity(); 451 try { 452 if (mCurrentVibration != null) { 453 vib.stats().reportInterruptedAnotherVibration( 454 mCurrentVibration.getVibration().attrs.getUsage()); 455 mCurrentVibration.notifyCancelled( 456 new Vibration.EndInfo( 457 Vibration.Status.CANCELLED_SUPERSEDED, vib.uid, 458 vib.attrs.getUsage()), 459 /* immediate= */ false); 460 } 461 status = startVibrationLocked(vib); 462 } finally { 463 Binder.restoreCallingIdentity(ident); 464 } 465 } 466 467 // Ignored or failed to start the vibration, end it and report metrics right away. 468 if (status != Vibration.Status.RUNNING) { 469 endVibrationLocked(vib, 470 new Vibration.EndInfo(status, ignoredByUid, ignoredByUsage), 471 /* shouldWriteStats= */ true); 472 } 473 return vib; 474 } 475 } finally { 476 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 477 } 478 } 479 480 @Override // Binder call cancelVibrate(int usageFilter, IBinder token)481 public void cancelVibrate(int usageFilter, IBinder token) { 482 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "cancelVibrate"); 483 try { 484 mContext.enforceCallingOrSelfPermission( 485 android.Manifest.permission.VIBRATE, 486 "cancelVibrate"); 487 488 synchronized (mLock) { 489 if (DEBUG) { 490 Slog.d(TAG, "Canceling vibration"); 491 } 492 Vibration.EndInfo cancelledByUserInfo = 493 new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER); 494 final long ident = Binder.clearCallingIdentity(); 495 try { 496 if (mNextVibration != null 497 && shouldCancelVibration(mNextVibration.getVibration(), 498 usageFilter, token)) { 499 clearNextVibrationLocked(cancelledByUserInfo); 500 } 501 if (mCurrentVibration != null 502 && shouldCancelVibration(mCurrentVibration.getVibration(), 503 usageFilter, token)) { 504 mCurrentVibration.notifyCancelled( 505 cancelledByUserInfo, /* immediate= */false); 506 } 507 if (mCurrentExternalVibration != null 508 && shouldCancelVibration( 509 mCurrentExternalVibration.externalVibration.getVibrationAttributes(), 510 usageFilter)) { 511 mCurrentExternalVibration.mute(); 512 endExternalVibrateLocked( 513 cancelledByUserInfo, /* continueExternalControl= */ false); 514 } 515 } finally { 516 Binder.restoreCallingIdentity(ident); 517 } 518 } 519 } finally { 520 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 521 } 522 } 523 524 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)525 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 526 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 527 528 final long ident = Binder.clearCallingIdentity(); 529 530 boolean isDumpProto = false; 531 for (String arg : args) { 532 if (arg.equals("--proto")) { 533 isDumpProto = true; 534 } 535 } 536 try { 537 if (isDumpProto) { 538 dumpProto(fd); 539 } else { 540 dumpText(pw); 541 } 542 } finally { 543 Binder.restoreCallingIdentity(ident); 544 } 545 } 546 dumpText(PrintWriter pw)547 private void dumpText(PrintWriter pw) { 548 if (DEBUG) { 549 Slog.d(TAG, "Dumping vibrator manager service to text..."); 550 } 551 synchronized (mLock) { 552 pw.println("Vibrator Manager Service:"); 553 pw.println(" mVibrationSettings:"); 554 pw.println(" " + mVibrationSettings); 555 pw.println(); 556 pw.println(" mVibratorControllers:"); 557 for (int i = 0; i < mVibrators.size(); i++) { 558 pw.println(" " + mVibrators.valueAt(i)); 559 } 560 pw.println(); 561 pw.println(" mCurrentVibration:"); 562 pw.println(" " + (mCurrentVibration == null 563 ? null : mCurrentVibration.getVibration().getDebugInfo())); 564 pw.println(); 565 pw.println(" mNextVibration:"); 566 pw.println(" " + (mNextVibration == null 567 ? null : mNextVibration.getVibration().getDebugInfo())); 568 pw.println(); 569 pw.println(" mCurrentExternalVibration:"); 570 pw.println(" " + (mCurrentExternalVibration == null 571 ? null : mCurrentExternalVibration.getDebugInfo())); 572 pw.println(); 573 } 574 mVibratorManagerRecords.dumpText(pw); 575 } 576 dumpProto(FileDescriptor fd)577 synchronized void dumpProto(FileDescriptor fd) { 578 final ProtoOutputStream proto = new ProtoOutputStream(fd); 579 if (DEBUG) { 580 Slog.d(TAG, "Dumping vibrator manager service to proto..."); 581 } 582 synchronized (mLock) { 583 mVibrationSettings.dumpProto(proto); 584 if (mCurrentVibration != null) { 585 mCurrentVibration.getVibration().getDebugInfo().dumpProto(proto, 586 VibratorManagerServiceDumpProto.CURRENT_VIBRATION); 587 } 588 if (mCurrentExternalVibration != null) { 589 mCurrentExternalVibration.getDebugInfo().dumpProto(proto, 590 VibratorManagerServiceDumpProto.CURRENT_EXTERNAL_VIBRATION); 591 } 592 593 boolean isVibrating = false; 594 boolean isUnderExternalControl = false; 595 for (int i = 0; i < mVibrators.size(); i++) { 596 proto.write(VibratorManagerServiceDumpProto.VIBRATOR_IDS, mVibrators.keyAt(i)); 597 isVibrating |= mVibrators.valueAt(i).isVibrating(); 598 isUnderExternalControl |= mVibrators.valueAt(i).isUnderExternalControl(); 599 } 600 proto.write(VibratorManagerServiceDumpProto.IS_VIBRATING, isVibrating); 601 proto.write(VibratorManagerServiceDumpProto.VIBRATOR_UNDER_EXTERNAL_CONTROL, 602 isUnderExternalControl); 603 } 604 mVibratorManagerRecords.dumpProto(proto); 605 proto.flush(); 606 } 607 608 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback cb, ResultReceiver resultReceiver)609 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 610 String[] args, ShellCallback cb, ResultReceiver resultReceiver) { 611 new VibratorManagerShellCommand(cb.getShellCallbackBinder()) 612 .exec(this, in, out, err, args, cb, resultReceiver); 613 } 614 615 @VisibleForTesting updateServiceState()616 void updateServiceState() { 617 synchronized (mLock) { 618 if (DEBUG) { 619 Slog.d(TAG, "Updating device state..."); 620 } 621 boolean inputDevicesChanged = mInputDeviceDelegate.updateInputDeviceVibrators( 622 mVibrationSettings.shouldVibrateInputDevices()); 623 624 for (int i = 0; i < mAlwaysOnEffects.size(); i++) { 625 updateAlwaysOnLocked(mAlwaysOnEffects.valueAt(i)); 626 } 627 628 if (mCurrentVibration == null) { 629 return; 630 } 631 632 Vibration vib = mCurrentVibration.getVibration(); 633 Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked( 634 vib.uid, vib.displayId, vib.opPkg, vib.attrs); 635 636 if (inputDevicesChanged || (ignoreStatus != null)) { 637 if (DEBUG) { 638 Slog.d(TAG, "Canceling vibration because settings changed: " 639 + (inputDevicesChanged ? "input devices changed" : ignoreStatus)); 640 } 641 mCurrentVibration.notifyCancelled( 642 new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE), 643 /* immediate= */ false); 644 } 645 } 646 } 647 setExternalControl(boolean externalControl, VibrationStats vibrationStats)648 private void setExternalControl(boolean externalControl, VibrationStats vibrationStats) { 649 for (int i = 0; i < mVibrators.size(); i++) { 650 mVibrators.valueAt(i).setExternalControl(externalControl); 651 vibrationStats.reportSetExternalControl(); 652 } 653 } 654 655 @GuardedBy("mLock") updateAlwaysOnLocked(AlwaysOnVibration vib)656 private void updateAlwaysOnLocked(AlwaysOnVibration vib) { 657 for (int i = 0; i < vib.effects.size(); i++) { 658 VibratorController vibrator = mVibrators.get(vib.effects.keyAt(i)); 659 PrebakedSegment effect = vib.effects.valueAt(i); 660 if (vibrator == null) { 661 continue; 662 } 663 Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked( 664 vib.uid, Display.DEFAULT_DISPLAY, vib.opPkg, vib.attrs); 665 if (ignoreStatus == null) { 666 effect = mVibrationScaler.scale(effect, vib.attrs.getUsage()); 667 } else { 668 // Vibration should not run, use null effect to remove registered effect. 669 effect = null; 670 } 671 vibrator.updateAlwaysOn(vib.alwaysOnId, effect); 672 } 673 } 674 675 @GuardedBy("mLock") startVibrationLocked(Vibration vib)676 private Vibration.Status startVibrationLocked(Vibration vib) { 677 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked"); 678 try { 679 vib.updateEffects(effect -> mVibrationScaler.scale(effect, vib.attrs.getUsage())); 680 boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable( 681 vib.uid, vib.opPkg, vib.getEffect(), vib.reason, vib.attrs); 682 if (inputDevicesAvailable) { 683 return Vibration.Status.FORWARDED_TO_INPUT_DEVICES; 684 } 685 686 VibrationStepConductor conductor = new VibrationStepConductor(vib, mVibrationSettings, 687 mDeviceVibrationEffectAdapter, mVibrators, mVibrationThreadCallbacks); 688 if (mCurrentVibration == null) { 689 return startVibrationOnThreadLocked(conductor); 690 } 691 // If there's already a vibration queued (waiting for the previous one to finish 692 // cancelling), end it cleanly and replace it with the new one. 693 clearNextVibrationLocked( 694 new Vibration.EndInfo(Vibration.Status.IGNORED_SUPERSEDED, 695 vib.uid, vib.attrs.getUsage())); 696 mNextVibration = conductor; 697 return Vibration.Status.RUNNING; 698 } finally { 699 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 700 } 701 } 702 703 @GuardedBy("mLock") startVibrationOnThreadLocked(VibrationStepConductor conductor)704 private Vibration.Status startVibrationOnThreadLocked(VibrationStepConductor conductor) { 705 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationThreadLocked"); 706 try { 707 Vibration vib = conductor.getVibration(); 708 int mode = startAppOpModeLocked(vib.uid, vib.opPkg, vib.attrs); 709 switch (mode) { 710 case AppOpsManager.MODE_ALLOWED: 711 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 712 // Make sure mCurrentVibration is set while triggering the VibrationThread. 713 mCurrentVibration = conductor; 714 if (!mVibrationThread.runVibrationOnVibrationThread(mCurrentVibration)) { 715 // Shouldn't happen. The method call already logs a wtf. 716 mCurrentVibration = null; // Aborted. 717 return Vibration.Status.IGNORED_ERROR_SCHEDULING; 718 } 719 return Vibration.Status.RUNNING; 720 case AppOpsManager.MODE_ERRORED: 721 Slog.w(TAG, "Start AppOpsManager operation errored for uid " + vib.uid); 722 return Vibration.Status.IGNORED_ERROR_APP_OPS; 723 default: 724 return Vibration.Status.IGNORED_APP_OPS; 725 } 726 } finally { 727 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 728 } 729 } 730 731 @GuardedBy("mLock") endVibrationLocked(Vibration vib, Vibration.EndInfo vibrationEndInfo, boolean shouldWriteStats)732 private void endVibrationLocked(Vibration vib, Vibration.EndInfo vibrationEndInfo, 733 boolean shouldWriteStats) { 734 vib.end(vibrationEndInfo); 735 logVibrationStatus(vib.uid, vib.attrs, vibrationEndInfo.status); 736 mVibratorManagerRecords.record(vib); 737 if (shouldWriteStats) { 738 mFrameworkStatsLogger.writeVibrationReportedAsync( 739 vib.getStatsInfo(/* completionUptimeMillis= */ SystemClock.uptimeMillis())); 740 } 741 } 742 743 @GuardedBy("mLock") endVibrationAndWriteStatsLocked(ExternalVibrationHolder vib, Vibration.EndInfo vibrationEndInfo)744 private void endVibrationAndWriteStatsLocked(ExternalVibrationHolder vib, 745 Vibration.EndInfo vibrationEndInfo) { 746 vib.end(vibrationEndInfo); 747 logVibrationStatus(vib.externalVibration.getUid(), 748 vib.externalVibration.getVibrationAttributes(), vibrationEndInfo.status); 749 mVibratorManagerRecords.record(vib); 750 mFrameworkStatsLogger.writeVibrationReportedAsync( 751 vib.getStatsInfo(/* completionUptimeMillis= */ SystemClock.uptimeMillis())); 752 } 753 logVibrationStatus(int uid, VibrationAttributes attrs, Vibration.Status status)754 private void logVibrationStatus(int uid, VibrationAttributes attrs, Vibration.Status status) { 755 switch (status) { 756 case IGNORED_BACKGROUND: 757 Slog.e(TAG, "Ignoring incoming vibration as process with" 758 + " uid= " + uid + " is background," + " attrs= " + attrs); 759 break; 760 case IGNORED_ERROR_APP_OPS: 761 Slog.w(TAG, "Would be an error: vibrate from uid " + uid); 762 break; 763 case IGNORED_FOR_EXTERNAL: 764 if (DEBUG) { 765 Slog.d(TAG, "Ignoring incoming vibration for current external vibration"); 766 } 767 break; 768 case IGNORED_FOR_HIGHER_IMPORTANCE: 769 if (DEBUG) { 770 Slog.d(TAG, "Ignoring incoming vibration in favor of ongoing vibration" 771 + " with higher importance"); 772 } 773 break; 774 case IGNORED_FOR_ONGOING: 775 if (DEBUG) { 776 Slog.d(TAG, "Ignoring incoming vibration in favor of repeating vibration"); 777 } 778 break; 779 case IGNORED_FOR_RINGER_MODE: 780 if (DEBUG) { 781 Slog.d(TAG, "Ignoring incoming vibration because of ringer mode, attrs=" 782 + attrs); 783 } 784 break; 785 case IGNORED_FROM_VIRTUAL_DEVICE: 786 if (DEBUG) { 787 Slog.d(TAG, "Ignoring incoming vibration because it came from a virtual" 788 + " device, attrs= " + attrs); 789 } 790 break; 791 default: 792 if (DEBUG) { 793 Slog.d(TAG, "Vibration for uid=" + uid + " and with attrs=" + attrs 794 + " ended with status " + status); 795 } 796 } 797 } 798 799 @GuardedBy("mLock") reportFinishedVibrationLocked(Vibration.EndInfo vibrationEndInfo)800 private void reportFinishedVibrationLocked(Vibration.EndInfo vibrationEndInfo) { 801 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked"); 802 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 803 try { 804 Vibration vib = mCurrentVibration.getVibration(); 805 if (DEBUG) { 806 Slog.d(TAG, "Reporting vibration " + vib.id + " finished with " + vibrationEndInfo); 807 } 808 // DO NOT write metrics at this point, wait for the VibrationThread to report the 809 // vibration was released, after all cleanup. The metrics will be reported then. 810 endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ false); 811 finishAppOpModeLocked(vib.uid, vib.opPkg); 812 } finally { 813 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 814 } 815 } 816 onSyncedVibrationComplete(long vibrationId)817 private void onSyncedVibrationComplete(long vibrationId) { 818 synchronized (mLock) { 819 if (mCurrentVibration != null && mCurrentVibration.getVibration().id == vibrationId) { 820 if (DEBUG) { 821 Slog.d(TAG, "Synced vibration " + vibrationId + " complete, notifying thread"); 822 } 823 mCurrentVibration.notifySyncedVibrationComplete(); 824 } 825 } 826 } 827 onVibrationComplete(int vibratorId, long vibrationId)828 private void onVibrationComplete(int vibratorId, long vibrationId) { 829 synchronized (mLock) { 830 if (mCurrentVibration != null && mCurrentVibration.getVibration().id == vibrationId) { 831 if (DEBUG) { 832 Slog.d(TAG, "Vibration " + vibrationId + " on vibrator " + vibratorId 833 + " complete, notifying thread"); 834 } 835 mCurrentVibration.notifyVibratorComplete(vibratorId); 836 } 837 } 838 } 839 840 /** 841 * Check if given vibration should be ignored by this service because of the ongoing vibration. 842 * 843 * @return One of Vibration.Status.IGNORED_* values if the vibration should be ignored, null 844 * otherwise. 845 */ 846 @GuardedBy("mLock") 847 @Nullable shouldIgnoreVibrationForOngoingLocked(Vibration vib)848 private Vibration.Status shouldIgnoreVibrationForOngoingLocked(Vibration vib) { 849 if (mCurrentVibration == null || vib.isRepeating()) { 850 // Incoming repeating vibrations always take precedence over ongoing vibrations. 851 return null; 852 } 853 854 Vibration currentVibration = mCurrentVibration.getVibration(); 855 if (currentVibration.hasEnded() || mCurrentVibration.wasNotifiedToCancel()) { 856 // Current vibration has ended or is cancelling, should not block incoming vibrations. 857 return null; 858 } 859 860 int currentUsage = currentVibration.attrs.getUsage(); 861 int newUsage = vib.attrs.getUsage(); 862 if (getVibrationImportance(currentUsage) > getVibrationImportance(newUsage)) { 863 // Current vibration has higher importance than this one and should not be cancelled. 864 return Vibration.Status.IGNORED_FOR_HIGHER_IMPORTANCE; 865 } 866 867 if (currentVibration.isRepeating()) { 868 // Current vibration is repeating, assume it's more important. 869 return Vibration.Status.IGNORED_FOR_ONGOING; 870 } 871 872 return null; 873 } 874 getVibrationImportance(@ibrationAttributes.Usage int usage)875 private static int getVibrationImportance(@VibrationAttributes.Usage int usage) { 876 switch (usage) { 877 case VibrationAttributes.USAGE_RINGTONE: 878 return 5; 879 case VibrationAttributes.USAGE_ALARM: 880 return 4; 881 case VibrationAttributes.USAGE_NOTIFICATION: 882 return 3; 883 case VibrationAttributes.USAGE_COMMUNICATION_REQUEST: 884 case VibrationAttributes.USAGE_ACCESSIBILITY: 885 return 2; 886 case VibrationAttributes.USAGE_HARDWARE_FEEDBACK: 887 case VibrationAttributes.USAGE_PHYSICAL_EMULATION: 888 return 1; 889 case VibrationAttributes.USAGE_MEDIA: 890 case VibrationAttributes.USAGE_TOUCH: 891 case VibrationAttributes.USAGE_UNKNOWN: 892 default: 893 return 0; 894 } 895 } 896 897 /** 898 * Check if given vibration should be ignored by this service. 899 * 900 * @return One of Vibration.Status.IGNORED_* values if the vibration should be ignored, null 901 * otherwise. 902 */ 903 @GuardedBy("mLock") 904 @Nullable shouldIgnoreVibrationLocked(int uid, int displayId, String opPkg, VibrationAttributes attrs)905 private Vibration.Status shouldIgnoreVibrationLocked(int uid, int displayId, String opPkg, 906 VibrationAttributes attrs) { 907 Vibration.Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(uid, 908 displayId, attrs); 909 if (statusFromSettings != null) { 910 return statusFromSettings; 911 } 912 913 int mode = checkAppOpModeLocked(uid, opPkg, attrs); 914 if (mode != AppOpsManager.MODE_ALLOWED) { 915 if (mode == AppOpsManager.MODE_ERRORED) { 916 // We might be getting calls from within system_server, so we don't actually 917 // want to throw a SecurityException here. 918 return Vibration.Status.IGNORED_ERROR_APP_OPS; 919 } else { 920 return Vibration.Status.IGNORED_APP_OPS; 921 } 922 } 923 924 return null; 925 } 926 927 /** 928 * Return true if the vibration has the same token and usage belongs to given usage class. 929 * 930 * @param vib The ongoing or pending vibration to be cancelled. 931 * @param usageFilter The vibration usages to be cancelled, any bitwise combination of 932 * VibrationAttributes.USAGE_* values. 933 * @param token The binder token to identify the vibration origin. Only vibrations 934 * started with the same token can be cancelled with it. 935 */ shouldCancelVibration(Vibration vib, int usageFilter, IBinder token)936 private boolean shouldCancelVibration(Vibration vib, int usageFilter, IBinder token) { 937 return (vib.token == token) && shouldCancelVibration(vib.attrs, usageFilter); 938 } 939 940 /** 941 * Return true if the external vibration usage belongs to given usage class. 942 * 943 * @param attrs The attributes of an ongoing or pending vibration to be cancelled. 944 * @param usageFilter The vibration usages to be cancelled, any bitwise combination of 945 * VibrationAttributes.USAGE_* values. 946 */ shouldCancelVibration(VibrationAttributes attrs, int usageFilter)947 private boolean shouldCancelVibration(VibrationAttributes attrs, int usageFilter) { 948 if (attrs.getUsage() == VibrationAttributes.USAGE_UNKNOWN) { 949 // Special case, usage UNKNOWN would match all filters. Instead it should only match if 950 // it's cancelling that usage specifically, or if cancelling all usages. 951 return usageFilter == VibrationAttributes.USAGE_UNKNOWN 952 || usageFilter == VibrationAttributes.USAGE_FILTER_MATCH_ALL; 953 } 954 return (usageFilter & attrs.getUsage()) == attrs.getUsage(); 955 } 956 957 /** 958 * Check which mode should be set for a vibration with given {@code uid}, {@code opPkg} and 959 * {@code attrs}. This will return one of the AppOpsManager.MODE_*. 960 */ 961 @GuardedBy("mLock") checkAppOpModeLocked(int uid, String opPkg, VibrationAttributes attrs)962 private int checkAppOpModeLocked(int uid, String opPkg, VibrationAttributes attrs) { 963 int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE, 964 attrs.getAudioUsage(), uid, opPkg); 965 int fixedMode = fixupAppOpModeLocked(mode, attrs); 966 if (mode != fixedMode && fixedMode == AppOpsManager.MODE_ALLOWED) { 967 // If we're just ignoring the vibration op then this is set by DND and we should ignore 968 // if we're asked to bypass. AppOps won't be able to record this operation, so make 969 // sure we at least note it in the logs for debugging. 970 Slog.d(TAG, "Bypassing DND for vibrate from uid " + uid); 971 } 972 return fixedMode; 973 } 974 975 /** Start an operation in {@link AppOpsManager}, if allowed. */ 976 @GuardedBy("mLock") startAppOpModeLocked(int uid, String opPkg, VibrationAttributes attrs)977 private int startAppOpModeLocked(int uid, String opPkg, VibrationAttributes attrs) { 978 return fixupAppOpModeLocked( 979 mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, uid, opPkg), attrs); 980 } 981 982 /** 983 * Finish a previously started operation in {@link AppOpsManager}. This will be a noop if no 984 * operation with same uid was previously started. 985 */ 986 @GuardedBy("mLock") finishAppOpModeLocked(int uid, String opPkg)987 private void finishAppOpModeLocked(int uid, String opPkg) { 988 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, uid, opPkg); 989 } 990 991 /** 992 * Enforces {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} to incoming UID if it's 993 * different from the calling UID. 994 */ enforceUpdateAppOpsStatsPermission(int uid)995 private void enforceUpdateAppOpsStatsPermission(int uid) { 996 if (uid == Binder.getCallingUid()) { 997 return; 998 } 999 if (Binder.getCallingPid() == Process.myPid()) { 1000 return; 1001 } 1002 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 1003 Binder.getCallingPid(), Binder.getCallingUid(), null); 1004 } 1005 1006 /** 1007 * Validate the incoming {@link CombinedVibration}. 1008 * 1009 * We can't throw exceptions here since we might be called from some system_server component, 1010 * which would bring the whole system down. 1011 * 1012 * @return whether the CombinedVibrationEffect is non-null and valid 1013 */ isEffectValid(@ullable CombinedVibration effect)1014 private static boolean isEffectValid(@Nullable CombinedVibration effect) { 1015 if (effect == null) { 1016 Slog.wtf(TAG, "effect must not be null"); 1017 return false; 1018 } 1019 try { 1020 effect.validate(); 1021 } catch (Exception e) { 1022 Slog.wtf(TAG, "Encountered issue when verifying CombinedVibrationEffect.", e); 1023 return false; 1024 } 1025 return true; 1026 } 1027 1028 /** 1029 * Sets fallback effects to all prebaked ones in given combination of effects, based on {@link 1030 * VibrationSettings#getFallbackEffect}. 1031 */ fillVibrationFallbacks(Vibration vib, CombinedVibration effect)1032 private void fillVibrationFallbacks(Vibration vib, CombinedVibration effect) { 1033 if (effect instanceof CombinedVibration.Mono) { 1034 fillVibrationFallbacks(vib, ((CombinedVibration.Mono) effect).getEffect()); 1035 } else if (effect instanceof CombinedVibration.Stereo) { 1036 SparseArray<VibrationEffect> effects = 1037 ((CombinedVibration.Stereo) effect).getEffects(); 1038 for (int i = 0; i < effects.size(); i++) { 1039 fillVibrationFallbacks(vib, effects.valueAt(i)); 1040 } 1041 } else if (effect instanceof CombinedVibration.Sequential) { 1042 List<CombinedVibration> effects = 1043 ((CombinedVibration.Sequential) effect).getEffects(); 1044 for (int i = 0; i < effects.size(); i++) { 1045 fillVibrationFallbacks(vib, effects.get(i)); 1046 } 1047 } 1048 } 1049 fillVibrationFallbacks(Vibration vib, VibrationEffect effect)1050 private void fillVibrationFallbacks(Vibration vib, VibrationEffect effect) { 1051 VibrationEffect.Composed composed = (VibrationEffect.Composed) effect; 1052 int segmentCount = composed.getSegments().size(); 1053 for (int i = 0; i < segmentCount; i++) { 1054 VibrationEffectSegment segment = composed.getSegments().get(i); 1055 if (segment instanceof PrebakedSegment) { 1056 PrebakedSegment prebaked = (PrebakedSegment) segment; 1057 VibrationEffect fallback = mVibrationSettings.getFallbackEffect( 1058 prebaked.getEffectId()); 1059 if (prebaked.shouldFallback() && fallback != null) { 1060 vib.addFallback(prebaked.getEffectId(), fallback); 1061 } 1062 } 1063 } 1064 } 1065 1066 /** 1067 * Return new {@link VibrationAttributes} that only applies flags that this user has permissions 1068 * to use. 1069 */ 1070 @NonNull fixupVibrationAttributes(@ullable VibrationAttributes attrs, @Nullable CombinedVibration effect)1071 private VibrationAttributes fixupVibrationAttributes(@Nullable VibrationAttributes attrs, 1072 @Nullable CombinedVibration effect) { 1073 if (attrs == null) { 1074 attrs = DEFAULT_ATTRIBUTES; 1075 } 1076 int usage = attrs.getUsage(); 1077 if ((usage == VibrationAttributes.USAGE_UNKNOWN) 1078 && (effect != null) && effect.isHapticFeedbackCandidate()) { 1079 usage = VibrationAttributes.USAGE_TOUCH; 1080 } 1081 int flags = attrs.getFlags(); 1082 if ((flags & ATTRIBUTES_ALL_BYPASS_FLAGS) != 0) { 1083 if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 1084 || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE) 1085 || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) { 1086 // Remove bypass flags from attributes if the app does not have permissions. 1087 flags &= ~ATTRIBUTES_ALL_BYPASS_FLAGS; 1088 } 1089 } 1090 if ((usage == attrs.getUsage()) && (flags == attrs.getFlags())) { 1091 return attrs; 1092 } 1093 return new VibrationAttributes.Builder(attrs) 1094 .setUsage(usage) 1095 .setFlags(flags, attrs.getFlags()) 1096 .build(); 1097 } 1098 1099 @GuardedBy("mLock") 1100 @Nullable fixupAlwaysOnEffectsLocked( CombinedVibration effect)1101 private SparseArray<PrebakedSegment> fixupAlwaysOnEffectsLocked( 1102 CombinedVibration effect) { 1103 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "fixupAlwaysOnEffectsLocked"); 1104 try { 1105 SparseArray<VibrationEffect> effects; 1106 if (effect instanceof CombinedVibration.Mono) { 1107 VibrationEffect syncedEffect = ((CombinedVibration.Mono) effect).getEffect(); 1108 effects = transformAllVibratorsLocked(unused -> syncedEffect); 1109 } else if (effect instanceof CombinedVibration.Stereo) { 1110 effects = ((CombinedVibration.Stereo) effect).getEffects(); 1111 } else { 1112 // Only synced combinations can be used for always-on effects. 1113 return null; 1114 } 1115 SparseArray<PrebakedSegment> result = new SparseArray<>(); 1116 for (int i = 0; i < effects.size(); i++) { 1117 PrebakedSegment prebaked = extractPrebakedSegment(effects.valueAt(i)); 1118 if (prebaked == null) { 1119 Slog.e(TAG, "Only prebaked effects supported for always-on."); 1120 return null; 1121 } 1122 int vibratorId = effects.keyAt(i); 1123 VibratorController vibrator = mVibrators.get(vibratorId); 1124 if (vibrator != null && vibrator.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) { 1125 result.put(vibratorId, prebaked); 1126 } 1127 } 1128 if (result.size() == 0) { 1129 return null; 1130 } 1131 return result; 1132 } finally { 1133 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1134 } 1135 } 1136 1137 @Nullable extractPrebakedSegment(VibrationEffect effect)1138 private static PrebakedSegment extractPrebakedSegment(VibrationEffect effect) { 1139 if (effect instanceof VibrationEffect.Composed) { 1140 VibrationEffect.Composed composed = (VibrationEffect.Composed) effect; 1141 if (composed.getSegments().size() == 1) { 1142 VibrationEffectSegment segment = composed.getSegments().get(0); 1143 if (segment instanceof PrebakedSegment) { 1144 return (PrebakedSegment) segment; 1145 } 1146 } 1147 } 1148 return null; 1149 } 1150 1151 /** 1152 * Check given mode, one of the AppOpsManager.MODE_*, against {@link VibrationAttributes} to 1153 * allow bypassing {@link AppOpsManager} checks. 1154 */ 1155 @GuardedBy("mLock") fixupAppOpModeLocked(int mode, VibrationAttributes attrs)1156 private int fixupAppOpModeLocked(int mode, VibrationAttributes attrs) { 1157 if (mode == AppOpsManager.MODE_IGNORED 1158 && attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)) { 1159 return AppOpsManager.MODE_ALLOWED; 1160 } 1161 return mode; 1162 } 1163 hasPermission(String permission)1164 private boolean hasPermission(String permission) { 1165 return mContext.checkCallingOrSelfPermission(permission) 1166 == PackageManager.PERMISSION_GRANTED; 1167 } 1168 1169 @GuardedBy("mLock") shouldCancelOnScreenOffLocked(@ullable VibrationStepConductor conductor)1170 private boolean shouldCancelOnScreenOffLocked(@Nullable VibrationStepConductor conductor) { 1171 if (conductor == null) { 1172 return false; 1173 } 1174 Vibration vib = conductor.getVibration(); 1175 return mVibrationSettings.shouldCancelVibrationOnScreenOff( 1176 vib.uid, vib.opPkg, vib.attrs.getUsage(), vib.stats().getCreateUptimeMillis()); 1177 } 1178 1179 @GuardedBy("mLock") onAllVibratorsLocked(Consumer<VibratorController> consumer)1180 private void onAllVibratorsLocked(Consumer<VibratorController> consumer) { 1181 for (int i = 0; i < mVibrators.size(); i++) { 1182 consumer.accept(mVibrators.valueAt(i)); 1183 } 1184 } 1185 1186 @GuardedBy("mLock") transformAllVibratorsLocked(Function<VibratorController, T> fn)1187 private <T> SparseArray<T> transformAllVibratorsLocked(Function<VibratorController, T> fn) { 1188 SparseArray<T> ret = new SparseArray<>(mVibrators.size()); 1189 for (int i = 0; i < mVibrators.size(); i++) { 1190 ret.put(mVibrators.keyAt(i), fn.apply(mVibrators.valueAt(i))); 1191 } 1192 return ret; 1193 } 1194 1195 /** Point of injection for test dependencies */ 1196 @VisibleForTesting 1197 static class Injector { 1198 getNativeWrapper()1199 NativeWrapper getNativeWrapper() { 1200 return new NativeWrapper(); 1201 } 1202 createHandler(Looper looper)1203 Handler createHandler(Looper looper) { 1204 return new Handler(looper); 1205 } 1206 getBatteryStatsService()1207 IBatteryStats getBatteryStatsService() { 1208 return IBatteryStats.Stub.asInterface(ServiceManager.getService( 1209 BatteryStats.SERVICE_NAME)); 1210 } 1211 getFrameworkStatsLogger(Handler handler)1212 VibratorFrameworkStatsLogger getFrameworkStatsLogger(Handler handler) { 1213 return new VibratorFrameworkStatsLogger(handler); 1214 } 1215 createVibratorController(int vibratorId, VibratorController.OnVibrationCompleteListener listener)1216 VibratorController createVibratorController(int vibratorId, 1217 VibratorController.OnVibrationCompleteListener listener) { 1218 return new VibratorController(vibratorId, listener); 1219 } 1220 addService(String name, IBinder service)1221 void addService(String name, IBinder service) { 1222 ServiceManager.addService(name, service); 1223 } 1224 } 1225 1226 /** 1227 * Implementation of {@link VibrationThread.VibratorManagerHooks} that controls synced 1228 * vibrations and reports them when finished. 1229 */ 1230 private final class VibrationThreadCallbacks implements VibrationThread.VibratorManagerHooks { 1231 1232 @Override prepareSyncedVibration(long requiredCapabilities, int[] vibratorIds)1233 public boolean prepareSyncedVibration(long requiredCapabilities, int[] vibratorIds) { 1234 if ((mCapabilities & requiredCapabilities) != requiredCapabilities) { 1235 // This sync step requires capabilities this device doesn't have, skipping sync... 1236 return false; 1237 } 1238 return mNativeWrapper.prepareSynced(vibratorIds); 1239 } 1240 1241 @Override triggerSyncedVibration(long vibrationId)1242 public boolean triggerSyncedVibration(long vibrationId) { 1243 return mNativeWrapper.triggerSynced(vibrationId); 1244 } 1245 1246 @Override cancelSyncedVibration()1247 public void cancelSyncedVibration() { 1248 mNativeWrapper.cancelSynced(); 1249 } 1250 1251 @Override noteVibratorOn(int uid, long duration)1252 public void noteVibratorOn(int uid, long duration) { 1253 try { 1254 if (duration <= 0) { 1255 // Tried to turn vibrator ON and got: 1256 // duration == 0: Unsupported effect/method or zero-amplitude segment. 1257 // duration < 0: Unexpected error triggering the vibrator. 1258 // Skip battery stats and atom metric for VibratorStageChanged to ON. 1259 return; 1260 } 1261 if (duration == Long.MAX_VALUE) { 1262 // Repeating duration has started. Report a fixed duration here, noteVibratorOff 1263 // should be called when this is cancelled. 1264 duration = BATTERY_STATS_REPEATING_VIBRATION_DURATION; 1265 } 1266 mBatteryStatsService.noteVibratorOn(uid, duration); 1267 mFrameworkStatsLogger.writeVibratorStateOnAsync(uid, duration); 1268 } catch (RemoteException e) { 1269 Slog.e(TAG, "Error logging VibratorStateChanged to ON", e); 1270 } 1271 } 1272 1273 @Override noteVibratorOff(int uid)1274 public void noteVibratorOff(int uid) { 1275 try { 1276 mBatteryStatsService.noteVibratorOff(uid); 1277 mFrameworkStatsLogger.writeVibratorStateOffAsync(uid); 1278 } catch (RemoteException e) { 1279 Slog.e(TAG, "Error logging VibratorStateChanged to OFF", e); 1280 } 1281 } 1282 1283 @Override onVibrationCompleted(long vibrationId, Vibration.EndInfo vibrationEndInfo)1284 public void onVibrationCompleted(long vibrationId, Vibration.EndInfo vibrationEndInfo) { 1285 if (DEBUG) { 1286 Slog.d(TAG, "Vibration " + vibrationId + " finished with " + vibrationEndInfo); 1287 } 1288 synchronized (mLock) { 1289 if (mCurrentVibration != null 1290 && mCurrentVibration.getVibration().id == vibrationId) { 1291 reportFinishedVibrationLocked(vibrationEndInfo); 1292 } 1293 } 1294 } 1295 1296 @Override onVibrationThreadReleased(long vibrationId)1297 public void onVibrationThreadReleased(long vibrationId) { 1298 if (DEBUG) { 1299 Slog.d(TAG, "VibrationThread released after finished vibration"); 1300 } 1301 synchronized (mLock) { 1302 if (DEBUG) { 1303 Slog.d(TAG, "Processing VibrationThread released callback"); 1304 } 1305 if (Build.IS_DEBUGGABLE && mCurrentVibration != null 1306 && mCurrentVibration.getVibration().id != vibrationId) { 1307 Slog.wtf(TAG, TextUtils.formatSimple( 1308 "VibrationId mismatch on release. expected=%d, released=%d", 1309 mCurrentVibration.getVibration().id, vibrationId)); 1310 } 1311 if (mCurrentVibration != null) { 1312 // This is when we consider the current vibration complete, so report metrics. 1313 mFrameworkStatsLogger.writeVibrationReportedAsync( 1314 mCurrentVibration.getVibration().getStatsInfo( 1315 /* completionUptimeMillis= */ SystemClock.uptimeMillis())); 1316 mCurrentVibration = null; 1317 } 1318 if (mNextVibration != null) { 1319 VibrationStepConductor nextConductor = mNextVibration; 1320 mNextVibration = null; 1321 Vibration.Status status = startVibrationOnThreadLocked(nextConductor); 1322 if (status != Vibration.Status.RUNNING) { 1323 // Failed to start the vibration, end it and report metrics right away. 1324 endVibrationLocked(nextConductor.getVibration(), 1325 new Vibration.EndInfo(status), /* shouldWriteStats= */ true); 1326 } 1327 } 1328 } 1329 } 1330 } 1331 1332 /** Listener for synced vibration completion callbacks from native. */ 1333 @VisibleForTesting 1334 interface OnSyncedVibrationCompleteListener { 1335 1336 /** Callback triggered when synced vibration is complete. */ onComplete(long vibrationId)1337 void onComplete(long vibrationId); 1338 } 1339 1340 /** 1341 * Implementation of listeners to native vibrators with a weak reference to this service. 1342 */ 1343 private static final class VibrationCompleteListener implements 1344 VibratorController.OnVibrationCompleteListener, OnSyncedVibrationCompleteListener { 1345 private WeakReference<VibratorManagerService> mServiceRef; 1346 VibrationCompleteListener(VibratorManagerService service)1347 VibrationCompleteListener(VibratorManagerService service) { 1348 mServiceRef = new WeakReference<>(service); 1349 } 1350 1351 @Override onComplete(long vibrationId)1352 public void onComplete(long vibrationId) { 1353 VibratorManagerService service = mServiceRef.get(); 1354 if (service != null) { 1355 service.onSyncedVibrationComplete(vibrationId); 1356 } 1357 } 1358 1359 @Override onComplete(int vibratorId, long vibrationId)1360 public void onComplete(int vibratorId, long vibrationId) { 1361 VibratorManagerService service = mServiceRef.get(); 1362 if (service != null) { 1363 service.onVibrationComplete(vibratorId, vibrationId); 1364 } 1365 } 1366 } 1367 1368 /** 1369 * Combination of prekabed vibrations on multiple vibrators, with the same {@link 1370 * VibrationAttributes}, that can be set for always-on effects. 1371 */ 1372 private static final class AlwaysOnVibration { 1373 public final int alwaysOnId; 1374 public final int uid; 1375 public final String opPkg; 1376 public final VibrationAttributes attrs; 1377 public final SparseArray<PrebakedSegment> effects; 1378 AlwaysOnVibration(int alwaysOnId, int uid, String opPkg, VibrationAttributes attrs, SparseArray<PrebakedSegment> effects)1379 AlwaysOnVibration(int alwaysOnId, int uid, String opPkg, VibrationAttributes attrs, 1380 SparseArray<PrebakedSegment> effects) { 1381 this.alwaysOnId = alwaysOnId; 1382 this.uid = uid; 1383 this.opPkg = opPkg; 1384 this.attrs = attrs; 1385 this.effects = effects; 1386 } 1387 } 1388 1389 /** Holder for a {@link ExternalVibration}. */ 1390 private final class ExternalVibrationHolder implements IBinder.DeathRecipient { 1391 1392 public final ExternalVibration externalVibration; 1393 public final VibrationStats stats = new VibrationStats(); 1394 public int scale; 1395 1396 private Vibration.Status mStatus; 1397 ExternalVibrationHolder(ExternalVibration externalVibration)1398 private ExternalVibrationHolder(ExternalVibration externalVibration) { 1399 this.externalVibration = externalVibration; 1400 this.scale = IExternalVibratorService.SCALE_NONE; 1401 mStatus = Vibration.Status.RUNNING; 1402 } 1403 mute()1404 public void mute() { 1405 externalVibration.mute(); 1406 } 1407 linkToDeath()1408 public void linkToDeath() { 1409 externalVibration.linkToDeath(this); 1410 } 1411 unlinkToDeath()1412 public void unlinkToDeath() { 1413 externalVibration.unlinkToDeath(this); 1414 } 1415 isHoldingSameVibration(ExternalVibration externalVibration)1416 public boolean isHoldingSameVibration(ExternalVibration externalVibration) { 1417 return this.externalVibration.equals(externalVibration); 1418 } 1419 end(Vibration.EndInfo info)1420 public void end(Vibration.EndInfo info) { 1421 if (mStatus != Vibration.Status.RUNNING) { 1422 // Already ended, ignore this call 1423 return; 1424 } 1425 mStatus = info.status; 1426 stats.reportEnded(info.endedByUid, info.endedByUsage); 1427 1428 if (stats.hasStarted()) { 1429 // External vibration doesn't have feedback from total time the vibrator was playing 1430 // with non-zero amplitude, so we use the duration between start and end times of 1431 // the vibration as the time the vibrator was ON, since the haptic channels are 1432 // open for this duration and can receive vibration waveform data. 1433 stats.reportVibratorOn(stats.getEndUptimeMillis() - stats.getStartUptimeMillis()); 1434 } 1435 } 1436 binderDied()1437 public void binderDied() { 1438 synchronized (mLock) { 1439 if (mCurrentExternalVibration != null) { 1440 if (DEBUG) { 1441 Slog.d(TAG, "External vibration finished because binder died"); 1442 } 1443 endExternalVibrateLocked( 1444 new Vibration.EndInfo(Vibration.Status.CANCELLED_BINDER_DIED), 1445 /* continueExternalControl= */ false); 1446 } 1447 } 1448 } 1449 getDebugInfo()1450 public Vibration.DebugInfo getDebugInfo() { 1451 return new Vibration.DebugInfo( 1452 mStatus, stats, /* effect= */ null, /* originalEffect= */ null, scale, 1453 externalVibration.getVibrationAttributes(), externalVibration.getUid(), 1454 // TODO(b/243604888): propagating displayID from IExternalVibration instead of 1455 // using INVALID_DISPLAY for all external vibrations. 1456 Display.INVALID_DISPLAY, 1457 externalVibration.getPackage(), /* reason= */ null); 1458 } 1459 getStatsInfo(long completionUptimeMillis)1460 public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) { 1461 return new VibrationStats.StatsInfo( 1462 externalVibration.getUid(), 1463 FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__EXTERNAL, 1464 externalVibration.getVibrationAttributes().getUsage(), mStatus, stats, 1465 completionUptimeMillis); 1466 } 1467 } 1468 1469 /** Wrapper around the static-native methods of {@link VibratorManagerService} for tests. */ 1470 @VisibleForTesting 1471 public static class NativeWrapper { 1472 1473 private long mNativeServicePtr = 0; 1474 1475 /** Returns native pointer to newly created controller and connects with HAL service. */ init(OnSyncedVibrationCompleteListener listener)1476 public void init(OnSyncedVibrationCompleteListener listener) { 1477 mNativeServicePtr = nativeInit(listener); 1478 long finalizerPtr = nativeGetFinalizer(); 1479 1480 if (finalizerPtr != 0) { 1481 NativeAllocationRegistry registry = 1482 NativeAllocationRegistry.createMalloced( 1483 VibratorManagerService.class.getClassLoader(), finalizerPtr); 1484 registry.registerNativeAllocation(this, mNativeServicePtr); 1485 } 1486 } 1487 1488 /** Returns manager capabilities. */ getCapabilities()1489 public long getCapabilities() { 1490 return nativeGetCapabilities(mNativeServicePtr); 1491 } 1492 1493 /** Returns vibrator ids. */ getVibratorIds()1494 public int[] getVibratorIds() { 1495 return nativeGetVibratorIds(mNativeServicePtr); 1496 } 1497 1498 /** Prepare vibrators for triggering vibrations in sync. */ prepareSynced(@onNull int[] vibratorIds)1499 public boolean prepareSynced(@NonNull int[] vibratorIds) { 1500 return nativePrepareSynced(mNativeServicePtr, vibratorIds); 1501 } 1502 1503 /** Trigger prepared synced vibration. */ triggerSynced(long vibrationId)1504 public boolean triggerSynced(long vibrationId) { 1505 return nativeTriggerSynced(mNativeServicePtr, vibrationId); 1506 } 1507 1508 /** Cancel prepared synced vibration. */ cancelSynced()1509 public void cancelSynced() { 1510 nativeCancelSynced(mNativeServicePtr); 1511 } 1512 } 1513 1514 /** Keep records of vibrations played and provide debug information for this service. */ 1515 private static final class VibratorManagerRecords { 1516 private final SparseArray<LinkedList<Vibration.DebugInfo>> mPreviousVibrations = 1517 new SparseArray<>(); 1518 private final LinkedList<Vibration.DebugInfo> mPreviousExternalVibrations = 1519 new LinkedList<>(); 1520 private final int mPreviousVibrationsLimit; 1521 VibratorManagerRecords(int limit)1522 VibratorManagerRecords(int limit) { 1523 mPreviousVibrationsLimit = limit; 1524 } 1525 record(Vibration vib)1526 synchronized void record(Vibration vib) { 1527 int usage = vib.attrs.getUsage(); 1528 if (!mPreviousVibrations.contains(usage)) { 1529 mPreviousVibrations.put(usage, new LinkedList<>()); 1530 } 1531 record(mPreviousVibrations.get(usage), vib.getDebugInfo()); 1532 } 1533 record(ExternalVibrationHolder vib)1534 synchronized void record(ExternalVibrationHolder vib) { 1535 record(mPreviousExternalVibrations, vib.getDebugInfo()); 1536 } 1537 record(LinkedList<Vibration.DebugInfo> records, Vibration.DebugInfo info)1538 synchronized void record(LinkedList<Vibration.DebugInfo> records, 1539 Vibration.DebugInfo info) { 1540 if (records.size() > mPreviousVibrationsLimit) { 1541 records.removeFirst(); 1542 } 1543 records.addLast(info); 1544 } 1545 dumpText(PrintWriter pw)1546 synchronized void dumpText(PrintWriter pw) { 1547 for (int i = 0; i < mPreviousVibrations.size(); i++) { 1548 pw.println(); 1549 pw.print(" Previous vibrations for usage "); 1550 pw.print(VibrationAttributes.usageToString(mPreviousVibrations.keyAt(i))); 1551 pw.println(":"); 1552 for (Vibration.DebugInfo info : mPreviousVibrations.valueAt(i)) { 1553 pw.println(" " + info); 1554 } 1555 } 1556 1557 pw.println(); 1558 pw.println(" Previous external vibrations:"); 1559 for (Vibration.DebugInfo info : mPreviousExternalVibrations) { 1560 pw.println(" " + info); 1561 } 1562 } 1563 dumpProto(ProtoOutputStream proto)1564 synchronized void dumpProto(ProtoOutputStream proto) { 1565 for (int i = 0; i < mPreviousVibrations.size(); i++) { 1566 long fieldId; 1567 switch (mPreviousVibrations.keyAt(i)) { 1568 case VibrationAttributes.USAGE_RINGTONE: 1569 fieldId = VibratorManagerServiceDumpProto.PREVIOUS_RING_VIBRATIONS; 1570 break; 1571 case VibrationAttributes.USAGE_NOTIFICATION: 1572 fieldId = VibratorManagerServiceDumpProto 1573 .PREVIOUS_NOTIFICATION_VIBRATIONS; 1574 break; 1575 case VibrationAttributes.USAGE_ALARM: 1576 fieldId = VibratorManagerServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS; 1577 break; 1578 default: 1579 fieldId = VibratorManagerServiceDumpProto.PREVIOUS_VIBRATIONS; 1580 } 1581 for (Vibration.DebugInfo info : mPreviousVibrations.valueAt(i)) { 1582 info.dumpProto(proto, fieldId); 1583 } 1584 } 1585 1586 for (Vibration.DebugInfo info : mPreviousExternalVibrations) { 1587 info.dumpProto(proto, 1588 VibratorManagerServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS); 1589 } 1590 } 1591 } 1592 1593 /** Clears mNextVibration if set, ending it cleanly */ 1594 @GuardedBy("mLock") clearNextVibrationLocked(Vibration.EndInfo vibrationEndInfo)1595 private void clearNextVibrationLocked(Vibration.EndInfo vibrationEndInfo) { 1596 if (mNextVibration != null) { 1597 // Clearing next vibration before playing it, end it and report metrics right away. 1598 endVibrationLocked(mNextVibration.getVibration(), vibrationEndInfo, 1599 /* shouldWriteStats= */ true); 1600 mNextVibration = null; 1601 } 1602 } 1603 1604 /** 1605 * Ends the external vibration, and clears related service state. 1606 * 1607 * @param vibrationEndInfo the status and related info to end the associated Vibration with 1608 * @param continueExternalControl indicates whether external control will continue. If not, the 1609 * HAL will have external control turned off. 1610 */ 1611 @GuardedBy("mLock") endExternalVibrateLocked(Vibration.EndInfo vibrationEndInfo, boolean continueExternalControl)1612 private void endExternalVibrateLocked(Vibration.EndInfo vibrationEndInfo, 1613 boolean continueExternalControl) { 1614 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "endExternalVibrateLocked"); 1615 try { 1616 if (mCurrentExternalVibration == null) { 1617 return; 1618 } 1619 mCurrentExternalVibration.unlinkToDeath(); 1620 if (!continueExternalControl) { 1621 setExternalControl(false, mCurrentExternalVibration.stats); 1622 } 1623 // The external control was turned off, end it and report metrics right away. 1624 endVibrationAndWriteStatsLocked(mCurrentExternalVibration, vibrationEndInfo); 1625 mCurrentExternalVibration = null; 1626 } finally { 1627 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1628 } 1629 } 1630 1631 /** Implementation of {@link IExternalVibratorService} to be triggered on external control. */ 1632 @VisibleForTesting 1633 final class ExternalVibratorService extends IExternalVibratorService.Stub { 1634 1635 @Override onExternalVibrationStart(ExternalVibration vib)1636 public int onExternalVibrationStart(ExternalVibration vib) { 1637 if (!hasExternalControlCapability()) { 1638 return IExternalVibratorService.SCALE_MUTE; 1639 } 1640 if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE, 1641 vib.getUid(), -1 /*owningUid*/, true /*exported*/) 1642 != PackageManager.PERMISSION_GRANTED) { 1643 Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid() 1644 + " tried to play externally controlled vibration" 1645 + " without VIBRATE permission, ignoring."); 1646 return IExternalVibratorService.SCALE_MUTE; 1647 } 1648 1649 // Create Vibration.Stats as close to the received request as possible, for tracking. 1650 ExternalVibrationHolder vibHolder = new ExternalVibrationHolder(vib); 1651 VibrationAttributes attrs = fixupVibrationAttributes(vib.getVibrationAttributes(), 1652 /* effect= */ null); 1653 if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) { 1654 // Force update of user settings before checking if this vibration effect should 1655 // be ignored or scaled. 1656 mVibrationSettings.update(); 1657 } 1658 1659 boolean alreadyUnderExternalControl = false; 1660 boolean waitForCompletion = false; 1661 synchronized (mLock) { 1662 // TODO(b/243604888): propagating displayID from IExternalVibration instead of 1663 // using INVALID_DISPLAY for all external vibrations. 1664 Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked( 1665 vib.getUid(), Display.INVALID_DISPLAY, vib.getPackage(), attrs); 1666 if (ignoreStatus != null) { 1667 vibHolder.scale = IExternalVibratorService.SCALE_MUTE; 1668 // Failed to start the vibration, end it and report metrics right away. 1669 endVibrationAndWriteStatsLocked(vibHolder, new Vibration.EndInfo(ignoreStatus)); 1670 return vibHolder.scale; 1671 } 1672 if (mCurrentExternalVibration != null 1673 && mCurrentExternalVibration.isHoldingSameVibration(vib)) { 1674 // We are already playing this external vibration, so we can return the same 1675 // scale calculated in the previous call to this method. 1676 return mCurrentExternalVibration.scale; 1677 } 1678 if (mCurrentExternalVibration == null) { 1679 // If we're not under external control right now, then cancel any normal 1680 // vibration that may be playing and ready the vibrator for external control. 1681 if (mCurrentVibration != null) { 1682 vibHolder.stats.reportInterruptedAnotherVibration( 1683 mCurrentVibration.getVibration().attrs.getUsage()); 1684 clearNextVibrationLocked( 1685 new Vibration.EndInfo(Vibration.Status.IGNORED_FOR_EXTERNAL, 1686 vib.getUid(), attrs.getUsage())); 1687 mCurrentVibration.notifyCancelled( 1688 new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED, 1689 vib.getUid(), attrs.getUsage()), 1690 /* immediate= */ true); 1691 waitForCompletion = true; 1692 } 1693 } else { 1694 // At this point we have an externally controlled vibration playing already. 1695 // Since the interface defines that only one externally controlled vibration can 1696 // play at a time, we need to first mute the ongoing vibration and then return 1697 // a scale from this function for the new one, so we can be assured that the 1698 // ongoing will be muted in favor of the new vibration. 1699 // 1700 // Note that this doesn't support multiple concurrent external controls, as we 1701 // would need to mute the old one still if it came from a different controller. 1702 alreadyUnderExternalControl = true; 1703 mCurrentExternalVibration.mute(); 1704 vibHolder.stats.reportInterruptedAnotherVibration( 1705 mCurrentExternalVibration.externalVibration 1706 .getVibrationAttributes().getUsage()); 1707 endExternalVibrateLocked( 1708 new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED, 1709 vib.getUid(), attrs.getUsage()), 1710 /* continueExternalControl= */ true); 1711 } 1712 mCurrentExternalVibration = vibHolder; 1713 vibHolder.linkToDeath(); 1714 vibHolder.scale = mVibrationScaler.getExternalVibrationScale(attrs.getUsage()); 1715 } 1716 1717 if (waitForCompletion) { 1718 if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) { 1719 Slog.e(TAG, "Timed out waiting for vibration to cancel"); 1720 synchronized (mLock) { 1721 // Trigger endExternalVibrateLocked to unlink to death recipient. 1722 endExternalVibrateLocked( 1723 new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_CANCELLING), 1724 /* continueExternalControl= */ false); 1725 } 1726 return IExternalVibratorService.SCALE_MUTE; 1727 } 1728 } 1729 if (!alreadyUnderExternalControl) { 1730 if (DEBUG) { 1731 Slog.d(TAG, "Vibrator going under external control."); 1732 } 1733 setExternalControl(true, vibHolder.stats); 1734 } 1735 if (DEBUG) { 1736 Slog.e(TAG, "Playing external vibration: " + vib); 1737 } 1738 // Vibrator will start receiving data from external channels after this point. 1739 // Report current time as the vibration start time, for debugging. 1740 vibHolder.stats.reportStarted(); 1741 return vibHolder.scale; 1742 } 1743 1744 @Override onExternalVibrationStop(ExternalVibration vib)1745 public void onExternalVibrationStop(ExternalVibration vib) { 1746 synchronized (mLock) { 1747 if (mCurrentExternalVibration != null 1748 && mCurrentExternalVibration.isHoldingSameVibration(vib)) { 1749 if (DEBUG) { 1750 Slog.e(TAG, "Stopping external vibration" + vib); 1751 } 1752 endExternalVibrateLocked( 1753 new Vibration.EndInfo(Vibration.Status.FINISHED), 1754 /* continueExternalControl= */ false); 1755 } 1756 } 1757 } 1758 hasExternalControlCapability()1759 private boolean hasExternalControlCapability() { 1760 for (int i = 0; i < mVibrators.size(); i++) { 1761 if (mVibrators.valueAt(i).hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) { 1762 return true; 1763 } 1764 } 1765 return false; 1766 } 1767 } 1768 1769 /** Provide limited functionality from {@link VibratorManagerService} as shell commands. */ 1770 private final class VibratorManagerShellCommand extends ShellCommand { 1771 public static final String SHELL_PACKAGE_NAME = "com.android.shell"; 1772 1773 private final class CommonOptions { 1774 public boolean force = false; 1775 public String description = "Shell command"; 1776 public boolean background = false; 1777 CommonOptions()1778 CommonOptions() { 1779 String nextArg; 1780 while ((nextArg = peekNextArg()) != null) { 1781 switch (nextArg) { 1782 case "-f": 1783 getNextArgRequired(); // consume "-f" 1784 force = true; 1785 break; 1786 case "-B": 1787 getNextArgRequired(); // consume "-B" 1788 background = true; 1789 break; 1790 case "-d": 1791 getNextArgRequired(); // consume "-d" 1792 description = getNextArgRequired(); 1793 break; 1794 default: 1795 // nextArg is not a common option, finish reading. 1796 return; 1797 } 1798 } 1799 } 1800 } 1801 1802 private final IBinder mShellCallbacksToken; 1803 VibratorManagerShellCommand(IBinder shellCallbacksToken)1804 private VibratorManagerShellCommand(IBinder shellCallbacksToken) { 1805 mShellCallbacksToken = shellCallbacksToken; 1806 } 1807 1808 @Override onCommand(String cmd)1809 public int onCommand(String cmd) { 1810 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onCommand " + cmd); 1811 try { 1812 if ("list".equals(cmd)) { 1813 return runListVibrators(); 1814 } 1815 if ("synced".equals(cmd)) { 1816 return runMono(); 1817 } 1818 if ("combined".equals(cmd)) { 1819 return runStereo(); 1820 } 1821 if ("sequential".equals(cmd)) { 1822 return runSequential(); 1823 } 1824 if ("cancel".equals(cmd)) { 1825 return runCancel(); 1826 } 1827 return handleDefaultCommands(cmd); 1828 } finally { 1829 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1830 } 1831 } 1832 runListVibrators()1833 private int runListVibrators() { 1834 try (PrintWriter pw = getOutPrintWriter();) { 1835 if (mVibratorIds.length == 0) { 1836 pw.println("No vibrator found"); 1837 } else { 1838 for (int id : mVibratorIds) { 1839 pw.println(id); 1840 } 1841 } 1842 pw.println(""); 1843 return 0; 1844 } 1845 } 1846 1847 /** 1848 * Runs a CombinedVibration using the configured common options and attributes. 1849 */ runVibrate(CommonOptions commonOptions, CombinedVibration combined)1850 private void runVibrate(CommonOptions commonOptions, CombinedVibration combined) { 1851 VibrationAttributes attrs = createVibrationAttributes(commonOptions); 1852 // If running in the background, bind to death of the server binder rather than the 1853 // client, and the cancel command likewise uses the server binder reference to 1854 // only cancel background vibrations. 1855 IBinder deathBinder = commonOptions.background ? VibratorManagerService.this 1856 : mShellCallbacksToken; 1857 Vibration vib = vibrateInternal(Binder.getCallingUid(), Display.DEFAULT_DISPLAY, 1858 SHELL_PACKAGE_NAME, combined, attrs, commonOptions.description, deathBinder); 1859 if (vib != null && !commonOptions.background) { 1860 try { 1861 vib.waitForEnd(); 1862 } catch (InterruptedException e) { 1863 } 1864 } 1865 } 1866 runMono()1867 private int runMono() { 1868 runVibrate(new CommonOptions(), CombinedVibration.createParallel(nextEffect())); 1869 return 0; 1870 } 1871 runStereo()1872 private int runStereo() { 1873 CommonOptions commonOptions = new CommonOptions(); 1874 CombinedVibration.ParallelCombination combination = 1875 CombinedVibration.startParallel(); 1876 while ("-v".equals(getNextOption())) { 1877 int vibratorId = Integer.parseInt(getNextArgRequired()); 1878 combination.addVibrator(vibratorId, nextEffect()); 1879 } 1880 runVibrate(commonOptions, combination.combine()); 1881 return 0; 1882 } 1883 runSequential()1884 private int runSequential() { 1885 CommonOptions commonOptions = new CommonOptions(); 1886 CombinedVibration.SequentialCombination combination = 1887 CombinedVibration.startSequential(); 1888 while ("-v".equals(getNextOption())) { 1889 int vibratorId = Integer.parseInt(getNextArgRequired()); 1890 combination.addNext(vibratorId, nextEffect()); 1891 } 1892 runVibrate(commonOptions, combination.combine()); 1893 return 0; 1894 } 1895 runCancel()1896 private int runCancel() { 1897 // Cancel is only needed if the vibration was run in the background, otherwise it's 1898 // terminated by the shell command ending. In these cases, the token was that of the 1899 // service rather than the client. 1900 cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, VibratorManagerService.this); 1901 return 0; 1902 } 1903 nextEffect()1904 private VibrationEffect nextEffect() { 1905 VibrationEffect.Composition composition = VibrationEffect.startComposition(); 1906 String nextArg; 1907 1908 while ((nextArg = peekNextArg()) != null) { 1909 if ("oneshot".equals(nextArg)) { 1910 addOneShotToComposition(composition); 1911 } else if ("waveform".equals(nextArg)) { 1912 addWaveformToComposition(composition); 1913 } else if ("prebaked".equals(nextArg)) { 1914 addPrebakedToComposition(composition); 1915 } else if ("primitives".equals(nextArg)) { 1916 addPrimitivesToComposition(composition); 1917 } else { 1918 // nextArg is not an effect, finish reading. 1919 break; 1920 } 1921 } 1922 1923 return composition.compose(); 1924 } 1925 addOneShotToComposition(VibrationEffect.Composition composition)1926 private void addOneShotToComposition(VibrationEffect.Composition composition) { 1927 boolean hasAmplitude = false; 1928 int delay = 0; 1929 1930 getNextArgRequired(); // consume "oneshot" 1931 String nextOption; 1932 while ((nextOption = getNextOption()) != null) { 1933 if ("-a".equals(nextOption)) { 1934 hasAmplitude = true; 1935 } else if ("-w".equals(nextOption)) { 1936 delay = Integer.parseInt(getNextArgRequired()); 1937 } 1938 } 1939 1940 long duration = Long.parseLong(getNextArgRequired()); 1941 int amplitude = hasAmplitude ? Integer.parseInt(getNextArgRequired()) 1942 : VibrationEffect.DEFAULT_AMPLITUDE; 1943 composition.addOffDuration(Duration.ofMillis(delay)); 1944 composition.addEffect(VibrationEffect.createOneShot(duration, amplitude)); 1945 } 1946 addWaveformToComposition(VibrationEffect.Composition composition)1947 private void addWaveformToComposition(VibrationEffect.Composition composition) { 1948 boolean hasAmplitudes = false; 1949 boolean hasFrequencies = false; 1950 boolean isContinuous = false; 1951 int repeat = -1; 1952 int delay = 0; 1953 1954 getNextArgRequired(); // consume "waveform" 1955 String nextOption; 1956 while ((nextOption = getNextOption()) != null) { 1957 if ("-a".equals(nextOption)) { 1958 hasAmplitudes = true; 1959 } else if ("-r".equals(nextOption)) { 1960 repeat = Integer.parseInt(getNextArgRequired()); 1961 } else if ("-w".equals(nextOption)) { 1962 delay = Integer.parseInt(getNextArgRequired()); 1963 } else if ("-f".equals(nextOption)) { 1964 hasFrequencies = true; 1965 } else if ("-c".equals(nextOption)) { 1966 isContinuous = true; 1967 } 1968 } 1969 List<Integer> durations = new ArrayList<>(); 1970 List<Float> amplitudes = new ArrayList<>(); 1971 List<Float> frequencies = new ArrayList<>(); 1972 1973 float nextAmplitude = 0; 1974 String nextArg; 1975 while ((nextArg = peekNextArg()) != null) { 1976 try { 1977 durations.add(Integer.parseInt(nextArg)); 1978 getNextArgRequired(); // consume the duration 1979 } catch (NumberFormatException e) { 1980 // nextArg is not a duration, finish reading. 1981 break; 1982 } 1983 if (hasAmplitudes) { 1984 amplitudes.add( 1985 Float.parseFloat(getNextArgRequired()) / VibrationEffect.MAX_AMPLITUDE); 1986 } else { 1987 amplitudes.add(nextAmplitude); 1988 nextAmplitude = 1 - nextAmplitude; 1989 } 1990 if (hasFrequencies) { 1991 frequencies.add(Float.parseFloat(getNextArgRequired())); 1992 } 1993 } 1994 1995 // Add delay before the waveform. 1996 composition.addOffDuration(Duration.ofMillis(delay)); 1997 1998 VibrationEffect.WaveformBuilder waveform = VibrationEffect.startWaveform(); 1999 for (int i = 0; i < durations.size(); i++) { 2000 Duration transitionDuration = isContinuous 2001 ? Duration.ofMillis(durations.get(i)) 2002 : Duration.ZERO; 2003 Duration sustainDuration = isContinuous 2004 ? Duration.ZERO 2005 : Duration.ofMillis(durations.get(i)); 2006 2007 if (hasFrequencies) { 2008 waveform.addTransition(transitionDuration, targetAmplitude(amplitudes.get(i)), 2009 targetFrequency(frequencies.get(i))); 2010 } else { 2011 waveform.addTransition(transitionDuration, targetAmplitude(amplitudes.get(i))); 2012 } 2013 if (!sustainDuration.isZero()) { 2014 // Add sustain only takes positive durations. Skip this since we already 2015 // did a transition to the desired values (even when duration is zero). 2016 waveform.addSustain(sustainDuration); 2017 } 2018 2019 if ((i > 0) && (i == repeat)) { 2020 // Add segment that is not repeated to the composition and reset builder. 2021 composition.addEffect(waveform.build()); 2022 2023 if (hasFrequencies) { 2024 waveform = VibrationEffect.startWaveform(targetAmplitude(amplitudes.get(i)), 2025 targetFrequency(frequencies.get(i))); 2026 } else { 2027 waveform = VibrationEffect.startWaveform( 2028 targetAmplitude(amplitudes.get(i))); 2029 } 2030 } 2031 } 2032 if (repeat < 0) { 2033 composition.addEffect(waveform.build()); 2034 } else { 2035 // The waveform was already split at the repeat index, just repeat what remains. 2036 composition.repeatEffectIndefinitely(waveform.build()); 2037 } 2038 } 2039 addPrebakedToComposition(VibrationEffect.Composition composition)2040 private void addPrebakedToComposition(VibrationEffect.Composition composition) { 2041 boolean shouldFallback = false; 2042 int delay = 0; 2043 2044 getNextArgRequired(); // consume "prebaked" 2045 String nextOption; 2046 while ((nextOption = getNextOption()) != null) { 2047 if ("-b".equals(nextOption)) { 2048 shouldFallback = true; 2049 } else if ("-w".equals(nextOption)) { 2050 delay = Integer.parseInt(getNextArgRequired()); 2051 } 2052 } 2053 2054 int effectId = Integer.parseInt(getNextArgRequired()); 2055 composition.addOffDuration(Duration.ofMillis(delay)); 2056 composition.addEffect(VibrationEffect.get(effectId, shouldFallback)); 2057 } 2058 addPrimitivesToComposition(VibrationEffect.Composition composition)2059 private void addPrimitivesToComposition(VibrationEffect.Composition composition) { 2060 getNextArgRequired(); // consume "primitives" 2061 String nextArg; 2062 while ((nextArg = peekNextArg()) != null) { 2063 int delay = 0; 2064 if ("-w".equals(nextArg)) { 2065 getNextArgRequired(); // consume "-w" 2066 delay = Integer.parseInt(getNextArgRequired()); 2067 nextArg = peekNextArg(); 2068 } 2069 try { 2070 composition.addPrimitive(Integer.parseInt(nextArg), /* scale= */ 1, delay); 2071 getNextArgRequired(); // consume the primitive id 2072 } catch (NumberFormatException | NullPointerException e) { 2073 // nextArg is not describing a primitive, leave it to be consumed by outer loops 2074 break; 2075 } 2076 } 2077 } 2078 createVibrationAttributes(CommonOptions commonOptions)2079 private VibrationAttributes createVibrationAttributes(CommonOptions commonOptions) { 2080 final int flags = 2081 commonOptions.force ? VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY : 0; 2082 return new VibrationAttributes.Builder() 2083 .setFlags(flags) 2084 // Used to apply Settings.System.HAPTIC_FEEDBACK_INTENSITY to scale effects. 2085 .setUsage(VibrationAttributes.USAGE_TOUCH) 2086 .build(); 2087 } 2088 2089 @Override onHelp()2090 public void onHelp() { 2091 try (PrintWriter pw = getOutPrintWriter();) { 2092 pw.println("Vibrator Manager commands:"); 2093 pw.println(" help"); 2094 pw.println(" Prints this help text."); 2095 pw.println(""); 2096 pw.println(" list"); 2097 pw.println(" Prints the id of device vibrators. This does not include any "); 2098 pw.println(" connected input device."); 2099 pw.println(" synced [options] <effect>..."); 2100 pw.println(" Vibrates effect on all vibrators in sync."); 2101 pw.println(" combined [options] (-v <vibrator-id> <effect>...)..."); 2102 pw.println(" Vibrates different effects on each vibrator in sync."); 2103 pw.println(" sequential [options] (-v <vibrator-id> <effect>...)..."); 2104 pw.println(" Vibrates different effects on each vibrator in sequence."); 2105 pw.println(" cancel"); 2106 pw.println(" Cancels any active vibration"); 2107 pw.println(""); 2108 pw.println("Effect commands:"); 2109 pw.println(" oneshot [-w delay] [-a] <duration> [<amplitude>]"); 2110 pw.println(" Vibrates for duration milliseconds; ignored when device is on "); 2111 pw.println(" DND (Do Not Disturb) mode; touch feedback strength user setting "); 2112 pw.println(" will be used to scale amplitude."); 2113 pw.println(" If -w is provided, the effect will be played after the specified"); 2114 pw.println(" wait time in milliseconds."); 2115 pw.println(" If -a is provided, the command accepts a second argument for "); 2116 pw.println(" amplitude, in a scale of 1-255."); 2117 pw.print(" waveform [-w delay] [-r index] [-a] [-f] [-c] "); 2118 pw.println("(<duration> [<amplitude>] [<frequency>])..."); 2119 pw.println(" Vibrates for durations and amplitudes in list; ignored when "); 2120 pw.println(" device is on DND (Do Not Disturb) mode; touch feedback strength "); 2121 pw.println(" user setting will be used to scale amplitude."); 2122 pw.println(" If -w is provided, the effect will be played after the specified"); 2123 pw.println(" wait time in milliseconds."); 2124 pw.println(" If -r is provided, the waveform loops back to the specified"); 2125 pw.println(" index (e.g. 0 loops from the beginning)"); 2126 pw.println(" If -a is provided, the command expects amplitude to follow each"); 2127 pw.println(" duration; otherwise, it accepts durations only and alternates"); 2128 pw.println(" off/on"); 2129 pw.println(" If -f is provided, the command expects frequency to follow each"); 2130 pw.println(" amplitude or duration; otherwise, it uses resonant frequency"); 2131 pw.println(" If -c is provided, the waveform is continuous and will ramp"); 2132 pw.println(" between values; otherwise each entry is a fixed step."); 2133 pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255;"); 2134 pw.println(" frequency is an absolute value in hertz;"); 2135 pw.println(" prebaked [-w delay] [-b] <effect-id>"); 2136 pw.println(" Vibrates with prebaked effect; ignored when device is on DND "); 2137 pw.println(" (Do Not Disturb) mode; touch feedback strength user setting "); 2138 pw.println(" will be used to scale amplitude."); 2139 pw.println(" If -w is provided, the effect will be played after the specified"); 2140 pw.println(" wait time in milliseconds."); 2141 pw.println(" If -b is provided, the prebaked fallback effect will be played if"); 2142 pw.println(" the device doesn't support the given effect-id."); 2143 pw.println(" primitives ([-w delay] <primitive-id>)..."); 2144 pw.println(" Vibrates with a composed effect; ignored when device is on DND "); 2145 pw.println(" (Do Not Disturb) mode; touch feedback strength user setting "); 2146 pw.println(" will be used to scale primitive intensities."); 2147 pw.println(" If -w is provided, the next primitive will be played after the "); 2148 pw.println(" specified wait time in milliseconds."); 2149 pw.println(""); 2150 pw.println("Common Options:"); 2151 pw.println(" -f"); 2152 pw.println(" Force. Ignore Do Not Disturb setting."); 2153 pw.println(" -B"); 2154 pw.println(" Run in the background; without this option the shell cmd will"); 2155 pw.println(" block until the vibration has completed."); 2156 pw.println(" -d <description>"); 2157 pw.println(" Add description to the vibration."); 2158 pw.println(""); 2159 } 2160 } 2161 } 2162 } 2163