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