Merge "Fix binderProxy crashes due to excessive vibration params requests" into main
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index f4e2a7e..62b3682 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -64,3 +64,13 @@
purpose: PURPOSE_FEATURE
}
}
+
+flag {
+ namespace: "haptics"
+ name: "throttle_vibration_params_requests"
+ description: "Control the frequency of vibration params requests to prevent overloading the vendor service"
+ bug: "355320860"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorControlService.java b/services/core/java/com/android/server/vibrator/VibratorControlService.java
index 4da6585..de5e662 100644
--- a/services/core/java/com/android/server/vibrator/VibratorControlService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorControlService.java
@@ -41,6 +41,7 @@
import android.os.SystemClock;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
+import android.os.vibrator.Flags;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.Slog;
@@ -265,9 +266,15 @@
return null;
}
+ if (Flags.throttleVibrationParamsRequests() && mVibrationParamRequest != null
+ && mVibrationParamRequest.usage == usage) {
+ // Reuse existing future for ongoing request with same usage.
+ return mVibrationParamRequest.future;
+ }
+
try {
endOngoingRequestVibrationParamsLocked(/* wasCancelled= */ true);
- mVibrationParamRequest = new VibrationParamRequest(uid);
+ mVibrationParamRequest = new VibrationParamRequest(uid, usage);
vibratorController.requestVibrationParams(vibrationType, timeoutInMillis,
mVibrationParamRequest.token);
return mVibrationParamRequest.future;
@@ -533,10 +540,12 @@
public final CompletableFuture<Void> future = new CompletableFuture<>();
public final IBinder token = new Binder();
public final int uid;
+ public final @VibrationAttributes.Usage int usage;
public final long uptimeMs;
- VibrationParamRequest(int uid) {
+ VibrationParamRequest(int uid, @VibrationAttributes.Usage int usage) {
this.uid = uid;
+ this.usage = usage;
uptimeMs = SystemClock.uptimeMillis();
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
index 8ca8623..c496bbb 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
@@ -45,6 +45,11 @@
import android.os.IBinder;
import android.os.Process;
import android.os.test.TestLooper;
+import android.os.vibrator.Flags;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
@@ -63,7 +68,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
public class VibratorControlServiceTest {
@@ -71,6 +75,8 @@
@Rule
public MockitoRule rule = MockitoJUnit.rule();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock private VibrationScaler mMockVibrationScaler;
@Mock private PackageManagerInternal mPackageManagerInternalMock;
@@ -98,6 +104,7 @@
mVibratorControlService = new VibratorControlService(
InstrumentationRegistry.getContext(), new VibratorControllerHolder(),
mMockVibrationScaler, mVibrationSettings, mStatsLoggerMock, mLock);
+ mFakeVibratorController.setVibratorControlService(mVibratorControlService);
}
@Test
@@ -280,10 +287,10 @@
CompletableFuture<Void> future =
mVibratorControlService.triggerVibrationParamsRequest(UID, USAGE_RINGTONE,
timeoutInMillis);
- try {
- future.orTimeout(timeoutInMillis, TimeUnit.MILLISECONDS).get();
- } catch (Throwable ignored) {
- }
+ mTestLooper.dispatchAll();
+
+ assertThat(future).isNotNull();
+ assertThat(future.isDone()).isTrue();
assertThat(mFakeVibratorController.didRequestVibrationParams).isTrue();
assertThat(mFakeVibratorController.requestVibrationType).isEqualTo(
ScaleParam.TYPE_RINGTONE);
@@ -315,6 +322,46 @@
}
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_THROTTLE_VIBRATION_PARAMS_REQUESTS)
+ public void testRequestVibrationParams_withOngoingRequestAndSameUsage_returnOngoingFuture() {
+ int timeoutInMillis = 10;
+ mVibratorControlService.registerVibratorController(mFakeVibratorController);
+ CompletableFuture<Void> future =
+ mVibratorControlService.triggerVibrationParamsRequest(UID, USAGE_RINGTONE,
+ timeoutInMillis);
+ CompletableFuture<Void> future2 =
+ mVibratorControlService.triggerVibrationParamsRequest(UID, USAGE_RINGTONE,
+ timeoutInMillis);
+ mTestLooper.dispatchAll();
+
+ assertThat(future).isNotNull();
+ assertThat(future).isEqualTo(future2);
+ assertThat(future.isDone()).isTrue();
+ assertThat(mFakeVibratorController.requestVibrationParamsCounter).isEqualTo(1);
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_THROTTLE_VIBRATION_PARAMS_REQUESTS)
+ public void testRequestVibrationParams_withOngoingRequestAndSameUsage_returnNewFuture() {
+ int timeoutInMillis = 10;
+ mVibratorControlService.registerVibratorController(mFakeVibratorController);
+ CompletableFuture<Void> future =
+ mVibratorControlService.triggerVibrationParamsRequest(UID, USAGE_RINGTONE,
+ timeoutInMillis);
+ CompletableFuture<Void> future2 =
+ mVibratorControlService.triggerVibrationParamsRequest(UID, USAGE_RINGTONE,
+ timeoutInMillis);
+ mTestLooper.dispatchAll();
+
+ assertThat(future).isNotNull();
+ assertThat(future2).isNotNull();
+ assertThat(future).isNotEqualTo(future2);
+ assertThat(future.isDone()).isTrue();
+ assertThat(future2.isDone()).isTrue();
+ assertThat(mFakeVibratorController.requestVibrationParamsCounter).isEqualTo(2);
+ }
+
private static int buildVibrationTypesMask(int... types) {
int typesMask = 0;
for (int type : types) {
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
index 0cd88ef..c0e1407 100644
--- a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
@@ -39,6 +39,7 @@
public boolean didRequestVibrationParams = false;
public int requestVibrationType = VibrationAttributes.USAGE_UNKNOWN;
public long requestTimeoutInMillis = 0;
+ public int requestVibrationParamsCounter = 0;
public FakeVibratorController(Looper looper) {
mHandler = new Handler(looper);
@@ -58,6 +59,7 @@
didRequestVibrationParams = true;
requestVibrationType = vibrationType;
requestTimeoutInMillis = timeoutInMillis;
+ requestVibrationParamsCounter++;
mHandler.post(() -> {
if (mVibratorControlService != null) {
mVibratorControlService.onRequestVibrationParamsComplete(token, mRequestResult);