From 834b65d81329181f493599fd76c700a9cd156133 Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Fri, 19 Mar 2021 21:07:14 +0000 Subject: [PATCH] Move VibrationInfo initialization to cpp Remove all individual vibrator info getter from the VibratorController native wrapper and add a single getInfo that returns a complete instance of VibratorInfo. This is in preparation for adding all required fields for frequency control. Bug: 167947076 Test: VibratorControllerTest Change-Id: Ie436f19006bdf5a7fe4dbff1b1edc72a9441239f --- .../server/vibrator/VibratorController.java | 43 +---- ...oid_server_vibrator_VibratorController.cpp | 163 ++++++++++-------- .../FakeVibratorControllerProvider.java | 35 +--- .../vibrator/VibratorControllerTest.java | 23 +-- 4 files changed, 119 insertions(+), 145 deletions(-) diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java index dfdd86358347f..7cb3140ecb1a3 100644 --- a/services/core/java/com/android/server/vibrator/VibratorController.java +++ b/services/core/java/com/android/server/vibrator/VibratorController.java @@ -30,6 +30,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import libcore.util.NativeAllocationRegistry; @@ -65,13 +66,9 @@ final class VibratorController { NativeWrapper nativeWrapper) { mNativeWrapper = nativeWrapper; mNativeWrapper.init(vibratorId, listener); - - // TODO(b/167947076): load supported ones from HAL once API introduced - VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping( - Float.NaN, nativeWrapper.getResonantFrequency(), Float.NaN, Float.NaN, null); - mVibratorInfo = new VibratorInfo(vibratorId, nativeWrapper.getCapabilities(), - nativeWrapper.getSupportedEffects(), nativeWrapper.getSupportedPrimitives(), - nativeWrapper.getQFactor(), frequencyMapping); + mVibratorInfo = mNativeWrapper.getInfo(); + Preconditions.checkNotNull(mVibratorInfo, "Failed to retrieve data for vibrator %d", + vibratorId); } /** Register state listener for this vibrator. */ @@ -338,19 +335,15 @@ final class VibratorController { private static native long on(long nativePtr, long milliseconds, long vibrationId); private static native void off(long nativePtr); private static native void setAmplitude(long nativePtr, float amplitude); - private static native int[] getSupportedEffects(long nativePtr); - private static native int[] getSupportedPrimitives(long nativePtr); private static native long performEffect(long nativePtr, long effect, long strength, long vibrationId); private static native long performComposedEffect(long nativePtr, PrimitiveSegment[] effect, long vibrationId); private static native void setExternalControl(long nativePtr, boolean enabled); - private static native long getCapabilities(long nativePtr); private static native void alwaysOnEnable(long nativePtr, long id, long effect, long strength); private static native void alwaysOnDisable(long nativePtr, long id); - private static native float getResonantFrequency(long nativePtr); - private static native float getQFactor(long nativePtr); + private static native VibratorInfo getInfo(long nativePtr); private long mNativePtr = 0; @@ -387,16 +380,6 @@ final class VibratorController { setAmplitude(mNativePtr, amplitude); } - /** Returns all predefined effects supported by the device vibrator. */ - public int[] getSupportedEffects() { - return getSupportedEffects(mNativePtr); - } - - /** Returns all compose primitives supported by the device vibrator. */ - public int[] getSupportedPrimitives() { - return getSupportedPrimitives(mNativePtr); - } - /** Turns vibrator on to perform one of the supported effects. */ public long perform(long effect, long strength, long vibrationId) { return performEffect(mNativePtr, effect, strength, vibrationId); @@ -412,11 +395,6 @@ final class VibratorController { setExternalControl(mNativePtr, enabled); } - /** Returns all capabilities of the device vibrator. */ - public long getCapabilities() { - return getCapabilities(mNativePtr); - } - /** Enable always-on vibration with given id and effect. */ public void alwaysOnEnable(long id, long effect, long strength) { alwaysOnEnable(mNativePtr, id, effect, strength); @@ -427,14 +405,9 @@ final class VibratorController { alwaysOnDisable(mNativePtr, id); } - /** Gets the vibrator's resonant frequency (F0) */ - public float getResonantFrequency() { - return getResonantFrequency(mNativePtr); - } - - /** Gets the vibrator's Q factor */ - public float getQFactor() { - return getQFactor(mNativePtr); + /** Return device vibrator metadata. */ + public VibratorInfo getInfo() { + return getInfo(mNativePtr); } } } diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp index caec703a4c673..11fd8ffb8e9b6 100644 --- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp +++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp @@ -39,6 +39,10 @@ namespace android { static JavaVM* sJvm = nullptr; static jmethodID sMethodIdOnComplete; +static jclass sFrequencyMappingClass; +static jmethodID sFrequencyMappingCtor; +static jclass sVibratorInfoClass; +static jmethodID sVibratorInfoCtor; static struct { jfieldID id; jfieldID scale; @@ -97,7 +101,17 @@ public: jniEnv->DeleteGlobalRef(mCallbackListener); } - vibrator::HalController* hal() const { return mHal.get(); } + int32_t getVibratorId() const { return mVibratorId; } + + vibrator::Info getVibratorInfo() { return mHal->getInfo(); } + + void initHal() { mHal->init(); } + + template + vibrator::HalResult halCall(const vibrator::HalFunction>& fn, + const char* functionName) { + return mHal->doWithRetry(fn, functionName); + } std::function createCallback(jlong vibrationId) { return [vibrationId, this]() { @@ -133,7 +147,7 @@ static jlong vibratorNativeInit(JNIEnv* env, jclass /* clazz */, jint vibratorId jobject callbackListener) { std::unique_ptr wrapper = std::make_unique(env, vibratorId, callbackListener); - wrapper->hal()->init(); + wrapper->initHal(); return reinterpret_cast(wrapper.release()); } @@ -147,7 +161,8 @@ static jboolean vibratorIsAvailable(JNIEnv* env, jclass /* clazz */, jlong ptr) ALOGE("vibratorIsAvailable failed because native wrapper was not initialized"); return JNI_FALSE; } - return wrapper->hal()->ping().isOk() ? JNI_TRUE : JNI_FALSE; + auto pingFn = [](std::shared_ptr hal) { return hal->ping(); }; + return wrapper->halCall(pingFn, "ping").isOk() ? JNI_TRUE : JNI_FALSE; } static jlong vibratorOn(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong timeoutMs, @@ -158,7 +173,10 @@ static jlong vibratorOn(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong timeou return -1; } auto callback = wrapper->createCallback(vibrationId); - auto result = wrapper->hal()->on(std::chrono::milliseconds(timeoutMs), callback); + auto onFn = [&](std::shared_ptr hal) { + return hal->on(std::chrono::milliseconds(timeoutMs), callback); + }; + auto result = wrapper->halCall(onFn, "on"); return result.isOk() ? timeoutMs : (result.isUnsupported() ? 0 : -1); } @@ -168,7 +186,8 @@ static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong ptr) { ALOGE("vibratorOff failed because native wrapper was not initialized"); return; } - wrapper->hal()->off(); + auto offFn = [](std::shared_ptr hal) { return hal->off(); }; + wrapper->halCall(offFn, "off"); } static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong ptr, jfloat amplitude) { @@ -177,7 +196,10 @@ static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong ptr, jfl ALOGE("vibratorSetAmplitude failed because native wrapper was not initialized"); return; } - wrapper->hal()->setAmplitude(static_cast(amplitude)); + auto setAmplitudeFn = [&](std::shared_ptr hal) { + return hal->setAmplitude(static_cast(amplitude)); + }; + wrapper->halCall(setAmplitudeFn, "setAmplitude"); } static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong ptr, @@ -187,41 +209,10 @@ static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong pt ALOGE("vibratorSetExternalControl failed because native wrapper was not initialized"); return; } - wrapper->hal()->setExternalControl(enabled); -} - -static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong ptr) { - VibratorControllerWrapper* wrapper = reinterpret_cast(ptr); - if (wrapper == nullptr) { - ALOGE("vibratorGetSupportedEffects failed because native wrapper was not initialized"); - return nullptr; - } - auto result = wrapper->hal()->getSupportedEffects(); - if (!result.isOk()) { - return nullptr; - } - std::vector supportedEffects = result.value(); - jintArray effects = env->NewIntArray(supportedEffects.size()); - env->SetIntArrayRegion(effects, 0, supportedEffects.size(), - reinterpret_cast(supportedEffects.data())); - return effects; -} - -static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, jlong ptr) { - VibratorControllerWrapper* wrapper = reinterpret_cast(ptr); - if (wrapper == nullptr) { - ALOGE("vibratorGetSupportedPrimitives failed because native wrapper was not initialized"); - return nullptr; - } - auto result = wrapper->hal()->getSupportedPrimitives(); - if (!result.isOk()) { - return nullptr; - } - std::vector supportedPrimitives = result.value(); - jintArray primitives = env->NewIntArray(supportedPrimitives.size()); - env->SetIntArrayRegion(primitives, 0, supportedPrimitives.size(), - reinterpret_cast(supportedPrimitives.data())); - return primitives; + auto setExternalControlFn = [&](std::shared_ptr hal) { + return hal->setExternalControl(enabled); + }; + wrapper->halCall(setExternalControlFn, "setExternalControl"); } static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong effect, @@ -234,7 +225,10 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong ptr, j aidl::Effect effectType = static_cast(effect); aidl::EffectStrength effectStrength = static_cast(strength); auto callback = wrapper->createCallback(vibrationId); - auto result = wrapper->hal()->performEffect(effectType, effectStrength, callback); + auto performEffectFn = [&](std::shared_ptr hal) { + return hal->performEffect(effectType, effectStrength, callback); + }; + auto result = wrapper->halCall(performEffectFn, "performEffect"); return result.isOk() ? result.value().count() : (result.isUnsupported() ? 0 : -1); } @@ -252,20 +246,14 @@ static jlong vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlon effects.push_back(effectFromJavaPrimitive(env, element)); } auto callback = wrapper->createCallback(vibrationId); - auto result = wrapper->hal()->performComposedEffect(effects, callback); + auto performComposedEffectFn = [&](std::shared_ptr hal) { + return hal->performComposedEffect(effects, callback); + }; + auto result = wrapper->halCall(performComposedEffectFn, + "performComposedEffect"); return result.isOk() ? result.value().count() : (result.isUnsupported() ? 0 : -1); } -static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong ptr) { - VibratorControllerWrapper* wrapper = reinterpret_cast(ptr); - if (wrapper == nullptr) { - ALOGE("vibratorGetCapabilities failed because native wrapper was not initialized"); - return 0; - } - auto result = wrapper->hal()->getCapabilities(); - return result.isOk() ? static_cast(result.value()) : 0; -} - static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong id, jlong effect, jlong strength) { VibratorControllerWrapper* wrapper = reinterpret_cast(ptr); @@ -273,8 +261,11 @@ static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong ptr, j ALOGE("vibratorAlwaysOnEnable failed because native wrapper was not initialized"); return; } - wrapper->hal()->alwaysOnEnable(static_cast(id), static_cast(effect), + auto alwaysOnEnableFn = [&](std::shared_ptr hal) { + return hal->alwaysOnEnable(static_cast(id), static_cast(effect), static_cast(strength)); + }; + wrapper->halCall(alwaysOnEnableFn, "alwaysOnEnable"); } static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong id) { @@ -283,27 +274,48 @@ static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr, ALOGE("vibratorAlwaysOnDisable failed because native wrapper was not initialized"); return; } - wrapper->hal()->alwaysOnDisable(static_cast(id)); + auto alwaysOnDisableFn = [&](std::shared_ptr hal) { + return hal->alwaysOnDisable(static_cast(id)); + }; + wrapper->halCall(alwaysOnDisableFn, "alwaysOnDisable"); } -static float vibratorGetResonantFrequency(JNIEnv* env, jclass /* clazz */, jlong ptr) { +static jobject vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr) { VibratorControllerWrapper* wrapper = reinterpret_cast(ptr); if (wrapper == nullptr) { - ALOGE("vibratorGetResonantFrequency failed because native wrapper was not initialized"); - return NAN; + ALOGE("vibratorGetInfo failed because native wrapper was not initialized"); + return nullptr; } - auto result = wrapper->hal()->getResonantFrequency(); - return result.isOk() ? static_cast(result.value()) : NAN; -} + vibrator::Info info = wrapper->getVibratorInfo(); -static float vibratorGetQFactor(JNIEnv* env, jclass /* clazz */, jlong ptr) { - VibratorControllerWrapper* wrapper = reinterpret_cast(ptr); - if (wrapper == nullptr) { - ALOGE("vibratorGetQFactor failed because native wrapper was not initialized"); - return NAN; + jlong capabilities = + static_cast(info.capabilities.valueOr(vibrator::Capabilities::NONE)); + jfloat resonantFrequency = static_cast(info.resonantFrequency.valueOr(NAN)); + jfloat qFactor = static_cast(info.qFactor.valueOr(NAN)); + jintArray supportedEffects = nullptr; + jintArray supportedPrimitives = nullptr; + + if (info.supportedEffects.isOk()) { + std::vector effects = info.supportedEffects.value(); + supportedEffects = env->NewIntArray(effects.size()); + env->SetIntArrayRegion(supportedEffects, 0, effects.size(), + reinterpret_cast(effects.data())); } - auto result = wrapper->hal()->getQFactor(); - return result.isOk() ? static_cast(result.value()) : NAN; + if (info.supportedPrimitives.isOk()) { + std::vector primitives = info.supportedPrimitives.value(); + supportedPrimitives = env->NewIntArray(primitives.size()); + env->SetIntArrayRegion(supportedPrimitives, 0, primitives.size(), + reinterpret_cast(primitives.data())); + } + + jobject frequencyMapping = + env->NewObject(sFrequencyMappingClass, sFrequencyMappingCtor, NAN /* minFrequencyHz*/, + resonantFrequency, NAN /* frequencyResolutionHz*/, + NAN /* suggestedSafeRangeHz */, nullptr /* maxAmplitudes */); + + return env->NewObject(sVibratorInfoClass, sVibratorInfoCtor, wrapper->getVibratorId(), + capabilities, supportedEffects, supportedPrimitives, qFactor, + frequencyMapping); } static const JNINativeMethod method_table[] = { @@ -318,14 +330,10 @@ static const JNINativeMethod method_table[] = { {"performEffect", "(JJJJ)J", (void*)vibratorPerformEffect}, {"performComposedEffect", "(J[Landroid/os/vibrator/PrimitiveSegment;J)J", (void*)vibratorPerformComposedEffect}, - {"getSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects}, - {"getSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives}, {"setExternalControl", "(JZ)V", (void*)vibratorSetExternalControl}, - {"getCapabilities", "(J)J", (void*)vibratorGetCapabilities}, {"alwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable}, {"alwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable}, - {"getResonantFrequency", "(J)F", (void*)vibratorGetResonantFrequency}, - {"getQFactor", "(J)F", (void*)vibratorGetQFactor}, + {"getInfo", "(J)Landroid/os/VibratorInfo;", (void*)vibratorGetInfo}, }; int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env) { @@ -340,6 +348,15 @@ int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "mScale", "F"); sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "mDelay", "I"); + jclass frequencyMappingClass = FindClassOrDie(env, "android/os/VibratorInfo$FrequencyMapping"); + sFrequencyMappingClass = (jclass)env->NewGlobalRef(frequencyMappingClass); + sFrequencyMappingCtor = GetMethodIDOrDie(env, sFrequencyMappingClass, "", "(FFFF[F)V"); + + jclass vibratorInfoClass = FindClassOrDie(env, "android/os/VibratorInfo"); + sVibratorInfoClass = (jclass)env->NewGlobalRef(vibratorInfoClass); + sVibratorInfoCtor = GetMethodIDOrDie(env, sVibratorInfoClass, "", + "(IJ[I[IFLandroid/os/VibratorInfo$FrequencyMapping;)V"); + return jniRegisterNativeMethods(env, "com/android/server/vibrator/VibratorController$NativeWrapper", method_table, NELEM(method_table)); diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java index f7e7688a71f4e..aefd2175d00e3 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java @@ -20,6 +20,7 @@ import android.annotation.Nullable; import android.os.Handler; import android.os.Looper; import android.os.VibrationEffect; +import android.os.VibratorInfo; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.StepSegment; @@ -38,7 +39,6 @@ import java.util.Map; * interactions. */ final class FakeVibratorControllerProvider { - private static final int EFFECT_DURATION = 20; private final Map mEnabledAlwaysOnEffects = new HashMap<>(); @@ -92,26 +92,6 @@ final class FakeVibratorControllerProvider { applyLatency(); } - @Override - public int[] getSupportedEffects() { - return mSupportedEffects; - } - - @Override - public int[] getSupportedPrimitives() { - return mSupportedPrimitives; - } - - @Override - public float getResonantFrequency() { - return mResonantFrequency; - } - - @Override - public float getQFactor() { - return mQFactor; - } - @Override public long perform(long effect, long strength, long vibrationId) { if (mSupportedEffects == null @@ -140,11 +120,6 @@ final class FakeVibratorControllerProvider { public void setExternalControl(boolean enabled) { } - @Override - public long getCapabilities() { - return mCapabilities; - } - @Override public void alwaysOnEnable(long id, long effect, long strength) { PrebakedSegment prebaked = new PrebakedSegment((int) effect, false, (int) strength); @@ -156,6 +131,14 @@ final class FakeVibratorControllerProvider { mEnabledAlwaysOnEffects.remove(id); } + @Override + public VibratorInfo getInfo() { + VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping( + Float.NaN, mResonantFrequency, Float.NaN, Float.NaN, null); + return new VibratorInfo(vibratorId, mCapabilities, mSupportedEffects, + mSupportedPrimitives, mQFactor, frequencyMapping); + } + private void applyLatency() { try { if (mLatency > 0) { diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java index 52a9783121d5c..dd5da5a6f41ab 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java @@ -38,6 +38,7 @@ import android.hardware.vibrator.IVibrator; import android.os.IBinder; import android.os.IVibratorStateListener; import android.os.VibrationEffect; +import android.os.VibratorInfo; import android.os.test.TestLooper; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; @@ -66,6 +67,7 @@ import org.mockito.junit.MockitoRule; */ @Presubmit public class VibratorControllerTest { + private static final int VIBRATOR_ID = 0; @Rule public MockitoRule rule = MockitoJUnit.rule(); @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); @@ -86,23 +88,18 @@ public class VibratorControllerTest { ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); when(mContextSpy.getContentResolver()).thenReturn(contentResolver); when(mVibratorStateListenerMock.asBinder()).thenReturn(mVibratorStateListenerBinderMock); + mockVibratorCapabilities(0); } private VibratorController createController() { - return new VibratorController(/* vibratorId= */ 0, mOnCompleteListenerMock, - mNativeWrapperMock); - } - - private VibratorController createController(int vibratorId) { - return new VibratorController(vibratorId, mOnCompleteListenerMock, mNativeWrapperMock); + return new VibratorController(VIBRATOR_ID, mOnCompleteListenerMock, mNativeWrapperMock); } @Test public void createController_initializesNativeWrapper() { - int vibratorId = 13; - VibratorController controller = createController(vibratorId); - assertEquals(vibratorId, controller.getVibratorInfo().getId()); - verify(mNativeWrapperMock).init(eq(vibratorId), notNull()); + VibratorController controller = createController(); + assertEquals(VIBRATOR_ID, controller.getVibratorInfo().getId()); + verify(mNativeWrapperMock).init(eq(VIBRATOR_ID), notNull()); } @Test @@ -292,7 +289,11 @@ public class VibratorControllerTest { } private void mockVibratorCapabilities(int capabilities) { - when(mNativeWrapperMock.getCapabilities()).thenReturn((long) capabilities); + VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping( + Float.NaN, Float.NaN, Float.NaN, Float.NaN, null); + when(mNativeWrapperMock.getInfo()).thenReturn( + new VibratorInfo(VIBRATOR_ID, capabilities, null, null, Float.NaN, + frequencyMapping)); } private PrebakedSegment createPrebaked(int effectId, int effectStrength) {