diff options
| author | 2020-08-24 16:33:13 +0000 | |
|---|---|---|
| committer | 2020-08-24 16:33:13 +0000 | |
| commit | d39f47f38d64b6893ae2fd9a01eef604a081eadc (patch) | |
| tree | 0f34577fd4c8e904626161813e370dd89b6c1f62 | |
| parent | 4c2e287219d0345ab81a066f91f535ad53e6d653 (diff) | |
| parent | 122f12d09eff3545afb4b3f02bb68e3033d6e99e (diff) | |
Merge "Use vibration id as callback reference in VibratorService"
3 files changed, 222 insertions, 227 deletions
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 96d973ec5272..687af107590a 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -85,6 +85,7 @@ import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; public class VibratorService extends IVibratorService.Stub implements InputManager.InputDeviceListener { @@ -114,6 +115,9 @@ public class VibratorService extends IVibratorService.Stub private static final VibrationAttributes DEFAULT_ATTRIBUTES = new VibrationAttributes.Builder().build(); + // Used to generate globally unique vibration ids. + private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback + // A mapping from the intensity adjustment to the scaling to apply, where the intensity // adjustment is defined as the delta between the default intensity level and the user selected // intensity level. It's important that we apply the scaling on the delta between the two so @@ -171,34 +175,34 @@ public class VibratorService extends IVibratorService.Stub private int mRingIntensity; private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>(); - static native long vibratorInit(); + static native long vibratorInit(OnCompleteListener listener); static native long vibratorGetFinalizer(); - static native boolean vibratorExists(long controllerPtr); + static native boolean vibratorExists(long nativeServicePtr); - static native void vibratorOn(long controllerPtr, long milliseconds, Vibration vibration); + static native void vibratorOn(long nativeServicePtr, long milliseconds, long vibrationId); - static native void vibratorOff(long controllerPtr); + static native void vibratorOff(long nativeServicePtr); - static native void vibratorSetAmplitude(long controllerPtr, int amplitude); + static native void vibratorSetAmplitude(long nativeServicePtr, int amplitude); - static native int[] vibratorGetSupportedEffects(long controllerPtr); + static native int[] vibratorGetSupportedEffects(long nativeServicePtr); - static native int[] vibratorGetSupportedPrimitives(long controllerPtr); + static native int[] vibratorGetSupportedPrimitives(long nativeServicePtr); static native long vibratorPerformEffect( - long controllerPtr, long effect, long strength, Vibration vibration); + long nativeServicePtr, long effect, long strength, long vibrationId); - static native void vibratorPerformComposedEffect(long controllerPtr, - VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration); + static native void vibratorPerformComposedEffect(long nativeServicePtr, + VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId); - static native void vibratorSetExternalControl(long controllerPtr, boolean enabled); + static native void vibratorSetExternalControl(long nativeServicePtr, boolean enabled); - static native long vibratorGetCapabilities(long controllerPtr); - static native void vibratorAlwaysOnEnable(long controllerPtr, long id, long effect, + static native long vibratorGetCapabilities(long nativeServicePtr); + static native void vibratorAlwaysOnEnable(long nativeServicePtr, long id, long effect, long strength); - static native void vibratorAlwaysOnDisable(long controllerPtr, long id); + static native void vibratorAlwaysOnDisable(long nativeServicePtr, long id); private final IUidObserver mUidObserver = new IUidObserver.Stub() { @Override public void onUidStateChanged(int uid, int procState, long procStateSeq, @@ -220,12 +224,19 @@ public class VibratorService extends IVibratorService.Stub } }; + /** Listener for vibration completion callbacks from native. */ + public interface OnCompleteListener { + + /** Callback triggered when vibration is complete, identified by {@link Vibration#id}. */ + void onComplete(long vibrationId); + } + /** * Holder for a vibration to be played. This class can be shared with native methods for * hardware callback support. */ - @VisibleForTesting - public final class Vibration implements IBinder.DeathRecipient { + private final class Vibration implements IBinder.DeathRecipient { + public final IBinder token; // Start time in CLOCK_BOOTTIME base. public final long startTime; @@ -234,6 +245,7 @@ public class VibratorService extends IVibratorService.Stub // not to be affected by discontinuities created by RTC adjustments. public final long startTimeDebug; public final VibrationAttributes attrs; + public final long id; public final int uid; public final String opPkg; public final String reason; @@ -248,6 +260,7 @@ public class VibratorService extends IVibratorService.Stub VibrationAttributes attrs, int uid, String opPkg, String reason) { this.token = token; this.effect = effect; + this.id = mNextVibrationId.getAndIncrement(); this.startTime = SystemClock.elapsedRealtime(); this.startTimeDebug = System.currentTimeMillis(); this.attrs = attrs; @@ -268,19 +281,6 @@ public class VibratorService extends IVibratorService.Stub } } - /** Callback for when vibration is complete, to be called by native. */ - @VisibleForTesting - public void onComplete() { - synchronized (mLock) { - if (this == mCurrentVibration) { - if (DEBUG) { - Slog.d(TAG, "Vibration finished by callback, cleaning up"); - } - doCancelVibrateLocked(); - } - } - } - public boolean hasTimeoutLongerThan(long millis) { final long duration = effect.getDuration(); return duration >= 0 && duration > millis; @@ -385,14 +385,14 @@ public class VibratorService extends IVibratorService.Stub mNativeWrapper = injector.getNativeWrapper(); mH = injector.createHandler(Looper.myLooper()); - long controllerPtr = mNativeWrapper.vibratorInit(); + long nativeServicePtr = mNativeWrapper.vibratorInit(this::onVibrationComplete); long finalizerPtr = mNativeWrapper.vibratorGetFinalizer(); if (finalizerPtr != 0) { NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced( VibratorService.class.getClassLoader(), finalizerPtr); - registry.registerNativeAllocation(this, controllerPtr); + registry.registerNativeAllocation(this, nativeServicePtr); } // Reset the hardware to a default state, in case this is a runtime @@ -549,6 +549,19 @@ public class VibratorService extends IVibratorService.Stub } } + /** Callback for when vibration is complete, to be called by native. */ + @VisibleForTesting + public void onVibrationComplete(long vibrationId) { + synchronized (mLock) { + if (mCurrentVibration != null && mCurrentVibration.id == vibrationId) { + if (DEBUG) { + Slog.d(TAG, "Vibration finished by callback, cleaning up"); + } + doCancelVibrateLocked(); + } + } + } + @Override // Binder call public boolean hasVibrator() { return doVibratorExists(); @@ -1266,18 +1279,18 @@ public class VibratorService extends IVibratorService.Stub return mNativeWrapper.vibratorExists(); } - /** Vibrates with native callback trigger for {@link Vibration#onComplete()}. */ + /** Vibrates with native callback trigger for {@link #onVibrationComplete(long)}. */ private void doVibratorOn(long millis, int amplitude, Vibration vib) { - doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib); + doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib.id); } /** Vibrates without native callback. */ private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) { - doVibratorOn(millis, amplitude, uid, attrs, /* vib= */ null); + doVibratorOn(millis, amplitude, uid, attrs, /* vibrationId= */ 0); } private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs, - @Nullable Vibration vib) { + long vibrationId) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn"); try { synchronized (mInputDeviceVibrators) { @@ -1299,7 +1312,7 @@ public class VibratorService extends IVibratorService.Stub // Note: ordering is important here! Many haptic drivers will reset their // amplitude when enabled, so we always have to enable first, then set the // amplitude. - mNativeWrapper.vibratorOn(millis, vib); + mNativeWrapper.vibratorOn(millis, vibrationId); doVibratorSetAmplitude(amplitude); } } @@ -1348,7 +1361,7 @@ public class VibratorService extends IVibratorService.Stub // Input devices don't support prebaked effect, so skip trying it with them. if (!usingInputDeviceVibrators) { long duration = mNativeWrapper.vibratorPerformEffect( - prebaked.getId(), prebaked.getEffectStrength(), vib); + prebaked.getId(), prebaked.getEffectStrength(), vib.id); if (duration > 0) { noteVibratorOnLocked(vib.uid, duration); return; @@ -1395,7 +1408,7 @@ public class VibratorService extends IVibratorService.Stub PrimitiveEffect[] primitiveEffects = composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]); - mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib); + mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib.id); // Composed effects don't actually give us an estimated duration, so we just guess here. noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length); @@ -1726,20 +1739,20 @@ public class VibratorService extends IVibratorService.Stub @VisibleForTesting public static class NativeWrapper { - private long mNativeControllerPtr = 0; + private long mNativeServicePtr = 0; /** Checks if vibrator exists on device. */ public boolean vibratorExists() { - return VibratorService.vibratorExists(mNativeControllerPtr); + return VibratorService.vibratorExists(mNativeServicePtr); } /** * Returns native pointer to newly created controller and initializes connection to vibrator * HAL service. */ - public long vibratorInit() { - mNativeControllerPtr = VibratorService.vibratorInit(); - return mNativeControllerPtr; + public long vibratorInit(OnCompleteListener listener) { + mNativeServicePtr = VibratorService.vibratorInit(listener); + return mNativeServicePtr; } /** Returns pointer to native finalizer function to be called by GC. */ @@ -1748,60 +1761,61 @@ public class VibratorService extends IVibratorService.Stub } /** Turns vibrator on for given time. */ - public void vibratorOn(long milliseconds, @Nullable Vibration vibration) { - VibratorService.vibratorOn(mNativeControllerPtr, milliseconds, vibration); + public void vibratorOn(long milliseconds, long vibrationId) { + VibratorService.vibratorOn(mNativeServicePtr, milliseconds, vibrationId); } /** Turns vibrator off. */ public void vibratorOff() { - VibratorService.vibratorOff(mNativeControllerPtr); + VibratorService.vibratorOff(mNativeServicePtr); } /** Sets the amplitude for the vibrator to run. */ public void vibratorSetAmplitude(int amplitude) { - VibratorService.vibratorSetAmplitude(mNativeControllerPtr, amplitude); + VibratorService.vibratorSetAmplitude(mNativeServicePtr, amplitude); } /** Returns all predefined effects supported by the device vibrator. */ public int[] vibratorGetSupportedEffects() { - return VibratorService.vibratorGetSupportedEffects(mNativeControllerPtr); + return VibratorService.vibratorGetSupportedEffects(mNativeServicePtr); } /** Returns all compose primitives supported by the device vibrator. */ public int[] vibratorGetSupportedPrimitives() { - return VibratorService.vibratorGetSupportedPrimitives(mNativeControllerPtr); + return VibratorService.vibratorGetSupportedPrimitives(mNativeServicePtr); } /** Turns vibrator on to perform one of the supported effects. */ - public long vibratorPerformEffect(long effect, long strength, Vibration vibration) { + public long vibratorPerformEffect(long effect, long strength, long vibrationId) { return VibratorService.vibratorPerformEffect( - mNativeControllerPtr, effect, strength, vibration); + mNativeServicePtr, effect, strength, vibrationId); } /** Turns vibrator on to perform one of the supported composed effects. */ public void vibratorPerformComposedEffect( - VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration) { - VibratorService.vibratorPerformComposedEffect(mNativeControllerPtr, effect, vibration); + VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) { + VibratorService.vibratorPerformComposedEffect(mNativeServicePtr, effect, + vibrationId); } /** Enabled the device vibrator to be controlled by another service. */ public void vibratorSetExternalControl(boolean enabled) { - VibratorService.vibratorSetExternalControl(mNativeControllerPtr, enabled); + VibratorService.vibratorSetExternalControl(mNativeServicePtr, enabled); } /** Returns all capabilities of the device vibrator. */ public long vibratorGetCapabilities() { - return VibratorService.vibratorGetCapabilities(mNativeControllerPtr); + return VibratorService.vibratorGetCapabilities(mNativeServicePtr); } /** Enable always-on vibration with given id and effect. */ public void vibratorAlwaysOnEnable(long id, long effect, long strength) { - VibratorService.vibratorAlwaysOnEnable(mNativeControllerPtr, id, effect, strength); + VibratorService.vibratorAlwaysOnEnable(mNativeServicePtr, id, effect, strength); } /** Disable always-on vibration for given id. */ public void vibratorAlwaysOnDisable(long id) { - VibratorService.vibratorAlwaysOnDisable(mNativeControllerPtr, id); + VibratorService.vibratorAlwaysOnDisable(mNativeServicePtr, id); } } diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index b3f3a5e1ff72..9aca84849fc6 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -40,14 +40,12 @@ namespace aidl = android::hardware::vibrator; namespace android { static JavaVM* sJvm = nullptr; - static jmethodID sMethodIdOnComplete; - static struct { jfieldID id; jfieldID scale; jfieldID delay; -} gPrimitiveClassInfo; +} sPrimitiveClassInfo; static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) == static_cast<uint8_t>(aidl::EffectStrength::LIGHT)); @@ -77,100 +75,117 @@ static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) == static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) == static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK)); -static inline void callVibrationOnComplete(jobject vibration) { - if (vibration == nullptr) { - return; +class NativeVibratorService { +public: + NativeVibratorService(JNIEnv* env, jobject callbackListener) + : mController(std::make_unique<vibrator::HalController>()), + mCallbackListener(env->NewGlobalRef(callbackListener)) { + LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr, + "Unable to create global reference to vibration callback handler"); } - auto jniEnv = GetOrAttachJNIEnvironment(sJvm); - jniEnv->CallVoidMethod(vibration, sMethodIdOnComplete); - jniEnv->DeleteGlobalRef(vibration); -} + + ~NativeVibratorService() { + auto jniEnv = GetOrAttachJNIEnvironment(sJvm); + jniEnv->DeleteGlobalRef(mCallbackListener); + } + + vibrator::HalController* controller() const { return mController.get(); } + + std::function<void()> createCallback(jlong vibrationId) { + return [vibrationId, this]() { + auto jniEnv = GetOrAttachJNIEnvironment(sJvm); + jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, vibrationId); + }; + } + +private: + const std::unique_ptr<vibrator::HalController> mController; + const jobject mCallbackListener; +}; static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) { aidl::CompositeEffect effect; effect.primitive = static_cast<aidl::CompositePrimitive>( - env->GetIntField(primitive, gPrimitiveClassInfo.id)); - effect.scale = static_cast<float>(env->GetFloatField(primitive, gPrimitiveClassInfo.scale)); - effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, gPrimitiveClassInfo.delay)); + env->GetIntField(primitive, sPrimitiveClassInfo.id)); + effect.scale = static_cast<float>(env->GetFloatField(primitive, sPrimitiveClassInfo.scale)); + effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, sPrimitiveClassInfo.delay)); return effect; } -static void destroyVibratorController(void* rawVibratorController) { - vibrator::HalController* vibratorController = - reinterpret_cast<vibrator::HalController*>(rawVibratorController); - if (vibratorController) { - delete vibratorController; +static void destroyNativeService(void* servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service) { + delete service; } } -static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) { - std::unique_ptr<vibrator::HalController> controller = - std::make_unique<vibrator::HalController>(); - controller->init(); - return reinterpret_cast<jlong>(controller.release()); +static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jobject callbackListener) { + std::unique_ptr<NativeVibratorService> service = + std::make_unique<NativeVibratorService>(env, callbackListener); + service->controller()->init(); + return reinterpret_cast<jlong>(service.release()); } static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) { - return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyVibratorController)); + return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService)); } -static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorExists failed because controller was not initialized"); +static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorExists failed because native service was not initialized"); return JNI_FALSE; } - return controller->ping().isOk() ? JNI_TRUE : JNI_FALSE; + return service->controller()->ping().isOk() ? JNI_TRUE : JNI_FALSE; } -static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong timeoutMs, - jobject vibration) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorOn failed because controller was not initialized"); +static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong timeoutMs, + jlong vibrationId) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorOn failed because native service was not initialized"); return; } - jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration); - auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); }; - controller->on(std::chrono::milliseconds(timeoutMs), callback); + auto callback = service->createCallback(vibrationId); + service->controller()->on(std::chrono::milliseconds(timeoutMs), callback); } -static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorOff failed because controller was not initialized"); +static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorOff failed because native service was not initialized"); return; } - controller->off(); + service->controller()->off(); } -static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, +static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jint amplitude) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorSetAmplitude failed because controller was not initialized"); + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorSetAmplitude failed because native service was not initialized"); return; } - controller->setAmplitude(static_cast<int32_t>(amplitude)); + service->controller()->setAmplitude(static_cast<int32_t>(amplitude)); } -static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, +static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jboolean enabled) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorSetExternalControl failed because controller was not initialized"); + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorSetExternalControl failed because native service was not initialized"); return; } - controller->setExternalControl(enabled); + service->controller()->setExternalControl(enabled); } -static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorGetSupportedEffects failed because controller was not initialized"); +static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorGetSupportedEffects failed because native service was not initialized"); return nullptr; } - auto result = controller->getSupportedEffects(); + auto result = service->controller()->getSupportedEffects(); if (!result.isOk()) { return nullptr; } @@ -181,14 +196,13 @@ static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jl return effects; } -static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, - jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorGetSupportedPrimitives failed because controller was not initialized"); +static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorGetSupportedPrimitives failed because native service was not initialized"); return nullptr; } - auto result = controller->getSupportedPrimitives(); + auto result = service->controller()->getSupportedPrimitives(); if (!result.isOk()) { return nullptr; } @@ -199,26 +213,25 @@ static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, return primitives; } -static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, - jlong effect, jlong strength, jobject vibration) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorPerformEffect failed because controller was not initialized"); +static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong effect, + jlong strength, jlong vibrationId) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorPerformEffect failed because native service was not initialized"); return -1; } aidl::Effect effectType = static_cast<aidl::Effect>(effect); aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength); - jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration); - auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); }; - auto result = controller->performEffect(effectType, effectStrength, callback); + auto callback = service->createCallback(vibrationId); + auto result = service->controller()->performEffect(effectType, effectStrength, callback); return result.isOk() ? result.value().count() : -1; } -static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, - jobjectArray composition, jobject vibration) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorPerformComposedEffect failed because controller was not initialized"); +static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr, + jobjectArray composition, jlong vibrationId) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorPerformComposedEffect failed because native service was not initialized"); return; } size_t size = env->GetArrayLength(composition); @@ -227,54 +240,52 @@ static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong jobject element = env->GetObjectArrayElement(composition, i); effects.push_back(effectFromJavaPrimitive(env, element)); } - jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration); - auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); }; - controller->performComposedEffect(effects, callback); + auto callback = service->createCallback(vibrationId); + service->controller()->performComposedEffect(effects, callback); } -static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorGetCapabilities failed because controller was not initialized"); +static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorGetCapabilities failed because native service was not initialized"); return 0; } - auto result = controller->getCapabilities(); + auto result = service->controller()->getCapabilities(); return result.isOk() ? static_cast<jlong>(result.value()) : 0; } -static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong id, +static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id, jlong effect, jlong strength) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorAlwaysOnEnable failed because controller was not initialized"); + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorAlwaysOnEnable failed because native service was not initialized"); return; } - controller->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect), - static_cast<aidl::EffectStrength>(strength)); + service->controller()->alwaysOnEnable(static_cast<int32_t>(id), + static_cast<aidl::Effect>(effect), + static_cast<aidl::EffectStrength>(strength)); } -static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, - jlong id) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorAlwaysOnDisable failed because controller was not initialized"); +static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorAlwaysOnDisable failed because native service was not initialized"); return; } - controller->alwaysOnDisable(static_cast<int32_t>(id)); + service->controller()->alwaysOnDisable(static_cast<int32_t>(id)); } static const JNINativeMethod method_table[] = { - {"vibratorInit", "()J", (void*)vibratorInit}, + {"vibratorInit", "(Lcom/android/server/VibratorService$OnCompleteListener;)J", + (void*)vibratorInit}, {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer}, {"vibratorExists", "(J)Z", (void*)vibratorExists}, - {"vibratorOn", "(JJLcom/android/server/VibratorService$Vibration;)V", (void*)vibratorOn}, + {"vibratorOn", "(JJJ)V", (void*)vibratorOn}, {"vibratorOff", "(J)V", (void*)vibratorOff}, {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude}, - {"vibratorPerformEffect", "(JJJLcom/android/server/VibratorService$Vibration;)J", - (void*)vibratorPerformEffect}, + {"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect}, {"vibratorPerformComposedEffect", - "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/" - "VibratorService$Vibration;)V", + "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)V", (void*)vibratorPerformComposedEffect}, {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects}, {"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives}, @@ -284,18 +295,17 @@ static const JNINativeMethod method_table[] = { {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable}, }; -int register_android_server_VibratorService(JavaVM* vm, JNIEnv* env) { - sJvm = vm; - sMethodIdOnComplete = - GetMethodIDOrDie(env, - FindClassOrDie(env, "com/android/server/VibratorService$Vibration"), - "onComplete", "()V"); +int register_android_server_VibratorService(JavaVM* jvm, JNIEnv* env) { + sJvm = jvm; + jclass listenerClass = + FindClassOrDie(env, "com/android/server/VibratorService$OnCompleteListener"); + sMethodIdOnComplete = GetMethodIDOrDie(env, listenerClass, "onComplete", "(J)V"); jclass primitiveClass = FindClassOrDie(env, "android/os/VibrationEffect$Composition$PrimitiveEffect"); - gPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I"); - gPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F"); - gPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I"); + sPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I"); + sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F"); + sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I"); return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table, NELEM(method_table)); diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java index b7a36f2eaed2..8d4f2aa69d68 100644 --- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java @@ -20,12 +20,13 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.AdditionalMatchers.gt; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.intThat; -import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; @@ -167,7 +168,7 @@ public class VibratorServiceTest { @Test public void createService_initializesNativeService() { createService(); - verify(mNativeWrapperMock).vibratorInit(); + verify(mNativeWrapperMock).vibratorInit(notNull()); verify(mNativeWrapperMock).vibratorOff(); } @@ -294,7 +295,7 @@ public class VibratorServiceTest { assertTrue(service.isVibrating()); verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class)); + verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L)); verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128)); } @@ -307,7 +308,7 @@ public class VibratorServiceTest { assertTrue(service.isVibrating()); verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class)); + verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L)); verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt()); } @@ -321,10 +322,8 @@ public class VibratorServiceTest { vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorPerformEffect( - eq((long) VibrationEffect.EFFECT_CLICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), - any(VibratorService.Vibration.class)); + verify(mNativeWrapperMock).vibratorPerformEffect(eq((long) VibrationEffect.EFFECT_CLICK), + eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), gt(0L)); } @Test @@ -343,7 +342,7 @@ public class VibratorServiceTest { verify(mNativeWrapperMock).vibratorOff(); verify(mNativeWrapperMock).vibratorPerformComposedEffect( - primitivesCaptor.capture(), any(VibratorService.Vibration.class)); + primitivesCaptor.capture(), gt(0L)); // Check all primitive effect fields are passed down to the HAL. assertEquals(1, primitivesCaptor.getValue().length); @@ -368,7 +367,7 @@ public class VibratorServiceTest { // Wait for VibrateThread to turn vibrator ON with total timing and no callback. Thread.sleep(5); - verify(mNativeWrapperMock).vibratorOn(eq(30L), isNull()); + verify(mNativeWrapperMock).vibratorOn(eq(30L), eq(0L)); // First amplitude set right away. verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100)); @@ -384,11 +383,11 @@ public class VibratorServiceTest { @Test public void vibrate_withOneShotAndNativeCallbackTriggered_finishesVibration() { + VibratorService service = createService(); doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(1)).onComplete(); + service.onVibrationComplete(invocation.getArgument(1)); return null; - }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class)); - VibratorService service = createService(); + }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong()); Mockito.clearInvocations(mNativeWrapperMock); vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)); @@ -396,7 +395,7 @@ public class VibratorServiceTest { InOrder inOrderVerifier = inOrder(mNativeWrapperMock); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L), - any(VibratorService.Vibration.class)); + gt(0L)); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @@ -404,12 +403,11 @@ public class VibratorServiceTest { public void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() { when(mNativeWrapperMock.vibratorGetSupportedEffects()) .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK}); + VibratorService service = createService(); doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(2)).onComplete(); + service.onVibrationComplete(invocation.getArgument(2)); return 10_000L; // 10s - }).when(mNativeWrapperMock).vibratorPerformEffect( - anyLong(), anyLong(), any(VibratorService.Vibration.class)); - VibratorService service = createService(); + }).when(mNativeWrapperMock).vibratorPerformEffect(anyLong(), anyLong(), anyLong()); Mockito.clearInvocations(mNativeWrapperMock); vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); @@ -419,7 +417,7 @@ public class VibratorServiceTest { inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_CLICK), eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), - any(VibratorService.Vibration.class)); + gt(0L)); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @@ -436,44 +434,19 @@ public class VibratorServiceTest { Thread.sleep(15); InOrder inOrderVerifier = inOrder(mNativeWrapperMock); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); - inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), isNull()); - inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), isNull()); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), eq(0L)); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), eq(0L)); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @Test public void vibrate_withComposedAndNativeCallbackTriggered_finishesVibration() { mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); - doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(1)).onComplete(); - return null; - }).when(mNativeWrapperMock).vibratorPerformComposedEffect( - any(), any(VibratorService.Vibration.class)); VibratorService service = createService(); - Mockito.clearInvocations(mNativeWrapperMock); - - VibrationEffect effect = VibrationEffect.startComposition() - .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10) - .compose(); - vibrate(service, effect); - - InOrder inOrderVerifier = inOrder(mNativeWrapperMock); - inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); - inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect( - any(VibrationEffect.Composition.PrimitiveEffect[].class), - any(VibratorService.Vibration.class)); - inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); - } - - @Test - public void vibrate_whenBinderDies_cancelsVibration() { - mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(1)).binderDied(); + service.onVibrationComplete(invocation.getArgument(1)); return null; - }).when(mNativeWrapperMock).vibratorPerformComposedEffect( - any(), any(VibratorService.Vibration.class)); - VibratorService service = createService(); + }).when(mNativeWrapperMock).vibratorPerformComposedEffect(any(), anyLong()); Mockito.clearInvocations(mNativeWrapperMock); VibrationEffect effect = VibrationEffect.startComposition() @@ -484,8 +457,7 @@ public class VibratorServiceTest { InOrder inOrderVerifier = inOrder(mNativeWrapperMock); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect( - any(VibrationEffect.Composition.PrimitiveEffect[].class), - any(VibratorService.Vibration.class)); + any(VibrationEffect.Composition.PrimitiveEffect[].class), gt(0L)); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @@ -513,12 +485,11 @@ public class VibratorServiceTest { @Test public void registerVibratorStateListener_callbacksAreTriggered() throws Exception { + VibratorService service = createService(); doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(1)).onComplete(); + service.onVibrationComplete(invocation.getArgument(1)); return null; - }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class)); - VibratorService service = createService(); - + }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong()); service.registerVibratorStateListener(mVibratorStateListenerMock); verify(mVibratorStateListenerMock).onVibrating(false); Mockito.clearInvocations(mVibratorStateListenerMock); @@ -569,15 +540,15 @@ public class VibratorServiceTest { verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_CLICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any()); + eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), anyLong()); verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_TICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any()); + eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), anyLong()); verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any()); + eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), anyLong()); verify(mNativeWrapperMock, never()).vibratorPerformEffect( - eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any()); + eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), anyLong()); } @Test @@ -644,7 +615,7 @@ public class VibratorServiceTest { // Ringtone vibration is off, so only the other 3 are propagated to native. verify(mNativeWrapperMock, times(3)).vibratorPerformComposedEffect( - primitivesCaptor.capture(), any()); + primitivesCaptor.capture(), anyLong()); List<VibrationEffect.Composition.PrimitiveEffect[]> values = primitivesCaptor.getAllValues(); |