Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4efe50f4 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Imlement vibration with callback in HalNativeHandler" into main

parents dccd267f 96af93af
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.vibrator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.vibrator.IVibrationSession;
import android.hardware.vibrator.IVibrator;
import android.hardware.vibrator.IVibratorManager;

/** Handles interactions with vibrator HAL services through native. */
@@ -48,4 +49,14 @@ interface HalNativeHandler {
     */
    @Nullable
    IVibrationSession startSessionWithCallback(long sessionId, int[] vibratorIds);

    /**
     * Call {@link IVibrator#on} on single vibrator using vibration id for callbacks from HAL.
     *
     * <p>This should only be called if HAL has {@link IVibrator#CAP_ON_CALLBACK}. The HAL might
     * fail the request otherwise.
     *
     * @return true if successful, false otherwise.
     */
    boolean vibrateWithCallback(int vibratorId, long vibrationId, long stepId, int durationMs);
}
+11 −0
Original line number Diff line number Diff line
@@ -252,6 +252,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
    private static native IBinder nativeStartSessionWithCallback(long nativePtr, long sessionId,
            int[] vibratorIds);

    /** Calls {@link IVibrator#on} with callback. */
    private static native boolean nativeVibratorOnWithCallback(long nativePtr, int vibratorId,
            long vibrationId, long stepId, int durationMs);

    // TODO(b/409002423): remove native methods below once remove_hidl_support flag removed
    static native long nativeInit(HalVibratorManager.Callbacks callback);

@@ -2371,6 +2375,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            }
            return android.hardware.vibrator.IVibrationSession.Stub.asInterface(token);
        }

        @Override
        public boolean vibrateWithCallback(int vibratorId, long vibrationId, long stepId,
                int durationMs) {
            return nativeVibratorOnWithCallback(mNativePtr, vibratorId, vibrationId, stepId,
                    durationMs);
        }
    }

    /** Keep records of vibrations played and provide debug information for this service. */
+41 −4
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.hardware.vibrator.FrequencyAccelerationMapEntry;
import android.hardware.vibrator.IVibrator;
import android.os.Binder;
import android.os.Handler;
import android.os.IVibratorStateListener;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -56,20 +57,27 @@ class VintfHalVibrator {
        private final Object mLock = new Object();
        private final int mVibratorId;
        private final VintfSupplier<IVibrator> mHalSupplier;
        private final Handler mHandler;
        private final HalNativeHandler mNativeHandler;

        @GuardedBy("mLock")
        private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
                new RemoteCallbackList<>();

        private Callbacks mCallbacks;

        // Vibrator state variables that are updated from synchronized blocks but can be read
        // anytime for a snippet of the current known vibrator state/info.
        private volatile VibratorInfo mVibratorInfo;
        private volatile State mCurrentState;
        private volatile float mCurrentAmplitude;

        DefaultHalVibrator(int vibratorId, VintfSupplier<IVibrator> supplier) {
        DefaultHalVibrator(int vibratorId, VintfSupplier<IVibrator> supplier, Handler handler,
                HalNativeHandler nativeHandler) {
            mVibratorId = vibratorId;
            mHalSupplier = supplier;
            mHandler = handler;
            mNativeHandler = nativeHandler;
            mVibratorInfo = new VibratorInfo.Builder(vibratorId).build();
            mCurrentState = State.IDLE;
            mCurrentAmplitude = 0;
@@ -79,6 +87,7 @@ class VintfHalVibrator {
        public void init(@NonNull Callbacks callbacks) {
            Trace.traceBegin(TRACE_TAG_VIBRATOR, "DefaultHalVibrator#init");
            try {
                mCallbacks = callbacks;
                int capabilities = getValue(IVibrator::getCapabilities,
                        "Error loading capabilities during init").orElse(0);

@@ -170,7 +179,9 @@ class VintfHalVibrator {
                    boolean result = VintfUtils.runNoThrow(mHalSupplier,
                            hal -> hal.setExternalControl(enabled),
                            e -> logError("Error setting external control to " + enabled, e));
                    if (result) {
                        updateStateAndNotifyListenersLocked(newState);
                    }
                    return result;
                }
            } finally {
@@ -234,8 +245,30 @@ class VintfHalVibrator {
        public long on(long vibrationId, long stepId, long milliseconds) {
            Trace.traceBegin(TRACE_TAG_VIBRATOR, "DefaultHalVibrator#on");
            try {
                // TODO(b/422944962): implement
                return 0;
                synchronized (mLock) {
                    boolean result;
                    if (mVibratorInfo.hasCapability(IVibrator.CAP_ON_CALLBACK)) {
                        // Delegate vibrate with callback to native, to avoid creating a new
                        // callback instance for each call, overloading the GC.
                        result = mNativeHandler.vibrateWithCallback(mVibratorId, vibrationId,
                                stepId, (int) milliseconds);
                    } else {
                        // Vibrate callback not supported, avoid unnecessary JNI round trip and
                        // simulate HAL callback here using a Handler.
                        result = VintfUtils.runNoThrow(mHalSupplier,
                                hal -> hal.on((int) milliseconds, null),
                                e -> logError("Error turning on for " + milliseconds + "ms", e));
                        if (result) {
                            mHandler.postDelayed(newVibrationCallback(vibrationId, stepId),
                                    milliseconds);
                        }
                    }
                    if (result) {
                        updateStateAndNotifyListenersLocked(State.VIBRATING);
                    }
                    // IVibrator.on API should never be unsupported.
                    return result ? milliseconds : -1;
                }
            } finally {
                Trace.traceEnd(TRACE_TAG_VIBRATOR);
            }
@@ -366,6 +399,10 @@ class VintfHalVibrator {
            }
        }

        private Runnable newVibrationCallback(long vibrationId, long stepId) {
            return () -> mCallbacks.onVibrationStepComplete(mVibratorId, vibrationId, stepId);
        }

        private VibratorInfo loadVibratorInfo(int vibratorId) {
            VibratorInfo.Builder builder = new VibratorInfo.Builder(vibratorId);
            int capabilities = getValue(IVibrator::getCapabilities, "Error loading capabilities")
+126 −7
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@

namespace android {

using BnVibratorCallback = aidl::android::hardware::vibrator::BnVibratorCallback;
using IVibrator = aidl::android::hardware::vibrator::IVibrator;
using IVibratorManager = aidl::android::hardware::vibrator::IVibratorManager;
using IVibrationSession = aidl::android::hardware::vibrator::IVibrationSession;
using VibrationSessionConfig = aidl::android::hardware::vibrator::VibrationSessionConfig;
@@ -41,11 +43,68 @@ using VibrationSessionConfig = aidl::android::hardware::vibrator::VibrationSessi
static JavaVM* sJvm = nullptr;
static jmethodID sMethodIdOnSyncedVibrationComplete;
static jmethodID sMethodIdOnVibrationSessionComplete;
static jmethodID sMethodIdOnVibrationComplete;

// TODO(b/409002423): remove this once remove_hidl_support flag removed
static std::mutex gManagerMutex;
static vibrator::ManagerHalController* gManager GUARDED_BY(gManagerMutex) = nullptr;

// IVibratorCallback implementation for HalVibrator.Callbacks.
class VibrationCallback : public BnVibratorCallback {
public:
    VibrationCallback(jweak callback, jint vibratorId, jlong vibrationId, jlong stepId)
          : mCallbackRef(callback),
            mVibratorId(vibratorId),
            mVibrationId(vibrationId),
            mStepId(stepId) {}
    virtual ~VibrationCallback() = default;

    ndk::ScopedAStatus onComplete() override {
        auto env = GetOrAttachJNIEnvironment(sJvm);
        if (env->IsSameObject(mCallbackRef, NULL)) {
            ALOGE("Null reference to vibrator service callbacks");
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
        }
        env->CallVoidMethod(mCallbackRef, sMethodIdOnVibrationComplete, mVibratorId, mVibrationId,
                            mStepId);
        return ndk::ScopedAStatus::ok();
    }

private:
    const jweak mCallbackRef;
    const jint mVibratorId;
    const jlong mVibrationId;
    const jlong mStepId;
};

// Provides IVibrator instances loaded from IVibratorManager.
class ManagedVibratorProvider : public HalProvider<IVibrator> {
public:
    ManagedVibratorProvider(std::shared_ptr<HalProvider<IVibratorManager>> managerProvider,
                            int32_t vibratorId)
          : mManagerProvider(std::move(managerProvider)), mVibratorId(vibratorId) {}
    virtual ~ManagedVibratorProvider() = default;

private:
    std::shared_ptr<HalProvider<IVibratorManager>> mManagerProvider;
    const int32_t mVibratorId;

    std::shared_ptr<IVibrator> loadHal() override {
        auto managerHal = mManagerProvider->getHal();
        if (managerHal == nullptr) {
            ALOGE("%s: Error loading manager HAL to get vibrator id=%d", __func__, mVibratorId);
            return nullptr;
        }
        std::shared_ptr<IVibrator> hal;
        auto status = managerHal->getVibrator(mVibratorId, &hal);
        if (!status.isOk() || hal == nullptr) {
            ALOGE("%s: Error on getVibrator(%d): %s", __func__, mVibratorId, status.getMessage());
            return nullptr;
        }
        return hal;
    }
};

class NativeVibratorManagerService {
public:
    // TODO(b/409002423): remove this once remove_hidl_support flag removed
@@ -53,20 +112,23 @@ public:
          : mHal(std::make_unique<vibrator::ManagerHalController>()),
            mCallbackListener(env->NewGlobalRef(callbackListener)),
            mManagerCallbacks(nullptr),
            mVibratorCallbacks(nullptr),
            mManagerHalProvider(nullptr) {
        LOG_ALWAYS_FATAL_IF(mHal == nullptr, "Unable to find reference to vibrator manager hal");
        LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
                            "Unable to create global reference to vibration callback handler");
    }

    NativeVibratorManagerService(JNIEnv* env, jobject managerCallbacks,
                                 jobject /* vibratorCallbacks */)
    NativeVibratorManagerService(JNIEnv* env, jobject managerCallbacks, jobject vibratorCallbacks)
          : mHal(nullptr),
            mCallbackListener(nullptr),
            mManagerCallbacks(env->NewWeakGlobalRef(managerCallbacks)),
            mVibratorCallbacks(env->NewWeakGlobalRef(vibratorCallbacks)),
            mManagerHalProvider(defaultProviderForDeclaredService<IVibratorManager>()) {
        LOG_ALWAYS_FATAL_IF(mManagerCallbacks == nullptr,
                            "Unable to create global reference to vibrator manager callbacks");
        LOG_ALWAYS_FATAL_IF(mVibratorCallbacks == nullptr,
                            "Unable to create global reference to vibrator callbacks");
    }

    ~NativeVibratorManagerService() {
@@ -77,16 +139,35 @@ public:
        if (mManagerCallbacks) {
            jniEnv->DeleteWeakGlobalRef(mManagerCallbacks);
        }
        if (mVibratorCallbacks) {
            jniEnv->DeleteWeakGlobalRef(mVibratorCallbacks);
        }
    }

    jweak managerCallbacks() {
        return mManagerCallbacks;
    }

    jweak vibratorCallbacks() {
        return mVibratorCallbacks;
    }

    std::shared_ptr<IVibratorManager> managerHal() {
        return mManagerHalProvider ? mManagerHalProvider->getHal() : nullptr;
    }

    std::shared_ptr<IVibrator> vibratorHal(int32_t vibratorId) {
        if (mVibratorHalProviders.find(vibratorId) == mVibratorHalProviders.end()) {
            mVibratorHalProviders[vibratorId] = mManagerHalProvider
                    ? std::make_unique<ManagedVibratorProvider>(mManagerHalProvider, vibratorId)
                    : defaultProviderForDeclaredService<IVibrator>();
        }
        if (mVibratorHalProviders[vibratorId] == nullptr) {
            return nullptr;
        }
        return mVibratorHalProviders[vibratorId]->getHal();
    }

    // TODO(b/409002423): remove functions below once remove_hidl_support flag removed
    vibrator::ManagerHalController* hal() const { return mHal.get(); }

@@ -157,7 +238,9 @@ private:
    const jobject mCallbackListener;

    const jweak mManagerCallbacks;
    std::unique_ptr<HalProvider<IVibratorManager>> mManagerHalProvider;
    const jweak mVibratorCallbacks;
    std::shared_ptr<HalProvider<IVibratorManager>> mManagerHalProvider;
    std::unordered_map<int32_t, std::unique_ptr<HalProvider<IVibrator>>> mVibratorHalProviders;
};

// TODO(b/409002423): remove this once remove_hidl_support flag removed
@@ -186,6 +269,18 @@ static std::shared_ptr<IVibratorManager> loadManagerHal(NativeVibratorManagerSer
    return hal;
}

static std::shared_ptr<IVibrator> loadVibratorHal(NativeVibratorManagerService* service,
                                                  int32_t vibratorId, const char* logLabel) {
    if (service == nullptr) {
        return nullptr;
    }
    auto hal = service->vibratorHal(vibratorId);
    if (hal == nullptr) {
        ALOGE("%s: vibrator HAL not available for vibrator id %d", logLabel, vibratorId);
    }
    return hal;
}

static void destroyNativeService(void* ptr) {
    ALOGD("%s", __func__);
    auto service = reinterpret_cast<NativeVibratorManagerService*>(ptr);
@@ -264,6 +359,25 @@ static jobject nativeStartSessionWithCallback(JNIEnv* env, jclass /* clazz */, j
    return AIBinder_toJavaBinder(env, session->asBinder().get());
}

static jboolean nativeVibratorOnWithCallback(JNIEnv* env, jclass /* clazz */, jlong ptr,
                                             jint vibratorId, jlong vibrationId, jlong stepId,
                                             jint durationMs) {
    ALOGD("%s", __func__);
    auto service = toNativeService(ptr, __func__);
    auto hal = loadVibratorHal(service, static_cast<int32_t>(vibratorId), __func__);
    if (service == nullptr || hal == nullptr) {
        return JNI_FALSE;
    }
    auto callback = ndk::SharedRefBase::make<VibrationCallback>(service->vibratorCallbacks(),
                                                                vibratorId, vibrationId, stepId);
    auto status = hal->on(static_cast<int32_t>(durationMs), callback);
    if (!status.isOk()) {
        ALOGE("%s: %s", __func__, status.getMessage());
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

// TODO(b/409002423): remove functions below once remove_hidl_support flag removed

static jlong nativeGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
@@ -391,16 +505,21 @@ static const JNINativeMethod method_table[] = {
        {"nativeTriggerSyncedWithCallback", "(JJ)Z", (void*)nativeTriggerSyncedWithCallback},
        {"nativeStartSessionWithCallback", "(JJ[I)Landroid/os/IBinder;",
         (void*)nativeStartSessionWithCallback},
        {"nativeVibratorOnWithCallback", "(JIJJI)Z", (void*)nativeVibratorOnWithCallback},
};

int register_android_server_vibrator_VibratorManagerService(JavaVM* jvm, JNIEnv* env) {
    sJvm = jvm;
    auto listenerClassName = "com/android/server/vibrator/HalVibratorManager$Callbacks";
    jclass listenerClass = FindClassOrDie(env, listenerClassName);
    jclass managerCallbacksClass =
            FindClassOrDie(env, "com/android/server/vibrator/HalVibratorManager$Callbacks");
    jclass vibratorCallbacksClass =
            FindClassOrDie(env, "com/android/server/vibrator/HalVibrator$Callbacks");
    sMethodIdOnSyncedVibrationComplete =
            GetMethodIDOrDie(env, listenerClass, "onSyncedVibrationComplete", "(J)V");
            GetMethodIDOrDie(env, managerCallbacksClass, "onSyncedVibrationComplete", "(J)V");
    sMethodIdOnVibrationSessionComplete =
            GetMethodIDOrDie(env, listenerClass, "onVibrationSessionComplete", "(J)V");
            GetMethodIDOrDie(env, managerCallbacksClass, "onVibrationSessionComplete", "(J)V");
    sMethodIdOnVibrationComplete =
            GetMethodIDOrDie(env, vibratorCallbacksClass, "onVibrationStepComplete", "(IJJ)V");
    return jniRegisterNativeMethods(env, "com/android/server/vibrator/VibratorManagerService",
                                    method_table, NELEM(method_table));
}
+25 −4
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#define _ANDROID_SERVER_VIBRATOR_MANAGER_SERVICE_H

#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
#include <aidl/android/hardware/vibrator/IVibrator.h>
#include <aidl/android/hardware/vibrator/IVibratorManager.h>
#include <android-base/thread_annotations.h>
#include <android/binder_manager.h>
#include <utils/Log.h>
@@ -34,7 +36,7 @@ namespace android {
// TODO(b/409002423): remove this once remove_hidl_support flag removed
extern vibrator::ManagerHalController* android_server_vibrator_VibratorManagerService_getManager();

// Base IVibratorCallback implementation using JNI to send callback ID to vibrator service.
// IVibratorCallback implementation using JNI to send callback ID to vibrator service.
class VibratorCallback : public aidl::android::hardware::vibrator::BnVibratorCallback {
public:
    VibratorCallback(JavaVM* jvm, jweak callback, jmethodID methodId, jlong callbackId)
@@ -83,8 +85,7 @@ public:
        if (mHal) {
            return mHal;
        }
        auto serviceName = std::string(I::descriptor) + "/default";
        mHal = I::fromBinder(ndk::SpAIBinder(AServiceManager_checkService(serviceName.c_str())));
        mHal = loadHal();
        if (mHal == nullptr) {
            ALOGE("%s: Error connecting to HAL", __func__);
            return mHal;
@@ -143,13 +144,33 @@ private:
        }
        mDeathRecipientCv.notify_all();
    }

    virtual std::shared_ptr<I> loadHal() = 0;
};

// Provides default service declared on the device, using link-to-death to reload dead objects.
template <typename I>
class DefaultProvider : public HalProvider<I> {
public:
    DefaultProvider() = default;
    virtual ~DefaultProvider() = default;

private:
    std::shared_ptr<I> loadHal() override {
        auto halName = std::string(I::descriptor) + "/default";
        auto hal = I::fromBinder(ndk::SpAIBinder(AServiceManager_checkService(halName.c_str())));
        if (hal == nullptr) {
            ALOGE("%s: Error connecting to %s", halName.c_str(), __func__);
        }
        return hal;
    }
};

// Returns a new provider for the default HAL service declared on the device, null if not declared.
template <typename I>
std::unique_ptr<HalProvider<I>> defaultProviderForDeclaredService() {
    if (AServiceManager_isDeclared((std::string(I::descriptor) + "/default").c_str())) {
        return std::make_unique<HalProvider<I>>();
        return std::make_unique<DefaultProvider<I>>();
    }
    return nullptr;
}
Loading