1 /*
2  * Copyright (C) 2020 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 #define LOG_TAG "VibratorManagerService"
18 
19 #include <nativehelper/JNIHelp.h>
20 #include "android_runtime/AndroidRuntime.h"
21 #include "core_jni_helpers.h"
22 #include "jni.h"
23 
24 #include <utils/Log.h>
25 #include <utils/misc.h>
26 
27 #include <vibratorservice/VibratorManagerHalController.h>
28 
29 #include "com_android_server_vibrator_VibratorManagerService.h"
30 
31 namespace android {
32 
33 static JavaVM* sJvm = nullptr;
34 static jmethodID sMethodIdOnComplete;
35 static std::mutex gManagerMutex;
36 static vibrator::ManagerHalController* gManager GUARDED_BY(gManagerMutex) = nullptr;
37 
38 class NativeVibratorManagerService {
39 public:
NativeVibratorManagerService(JNIEnv * env,jobject callbackListener)40     NativeVibratorManagerService(JNIEnv* env, jobject callbackListener)
41           : mHal(std::make_unique<vibrator::ManagerHalController>()),
42             mCallbackListener(env->NewGlobalRef(callbackListener)) {
43         LOG_ALWAYS_FATAL_IF(mHal == nullptr, "Unable to find reference to vibrator manager hal");
44         LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
45                             "Unable to create global reference to vibration callback handler");
46     }
47 
~NativeVibratorManagerService()48     ~NativeVibratorManagerService() {
49         auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
50         jniEnv->DeleteGlobalRef(mCallbackListener);
51     }
52 
hal() const53     vibrator::ManagerHalController* hal() const { return mHal.get(); }
54 
createCallback(jlong vibrationId)55     std::function<void()> createCallback(jlong vibrationId) {
56         return [vibrationId, this]() {
57             auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
58             jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, vibrationId);
59         };
60     }
61 
62 private:
63     const std::unique_ptr<vibrator::ManagerHalController> mHal;
64     const jobject mCallbackListener;
65 };
66 
android_server_vibrator_VibratorManagerService_getManager()67 vibrator::ManagerHalController* android_server_vibrator_VibratorManagerService_getManager() {
68     std::lock_guard<std::mutex> lock(gManagerMutex);
69     return gManager;
70 }
71 
destroyNativeService(void * ptr)72 static void destroyNativeService(void* ptr) {
73     NativeVibratorManagerService* service = reinterpret_cast<NativeVibratorManagerService*>(ptr);
74     if (service) {
75         std::lock_guard<std::mutex> lock(gManagerMutex);
76         gManager = nullptr;
77         delete service;
78     }
79 }
80 
nativeInit(JNIEnv * env,jclass,jobject callbackListener)81 static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject callbackListener) {
82     std::unique_ptr<NativeVibratorManagerService> service =
83             std::make_unique<NativeVibratorManagerService>(env, callbackListener);
84     {
85         std::lock_guard<std::mutex> lock(gManagerMutex);
86         gManager = service->hal();
87     }
88     return reinterpret_cast<jlong>(service.release());
89 }
90 
nativeGetFinalizer(JNIEnv *,jclass)91 static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
92     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
93 }
94 
nativeGetCapabilities(JNIEnv * env,jclass,jlong servicePtr)95 static jlong nativeGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
96     NativeVibratorManagerService* service =
97             reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
98     if (service == nullptr) {
99         ALOGE("nativeGetCapabilities failed because native service was not initialized");
100         return 0;
101     }
102     auto result = service->hal()->getCapabilities();
103     return result.isOk() ? static_cast<jlong>(result.value()) : 0;
104 }
105 
nativeGetVibratorIds(JNIEnv * env,jclass,jlong servicePtr)106 static jintArray nativeGetVibratorIds(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
107     NativeVibratorManagerService* service =
108             reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
109     if (service == nullptr) {
110         ALOGE("nativeGetVibratorIds failed because native service was not initialized");
111         return nullptr;
112     }
113     auto result = service->hal()->getVibratorIds();
114     if (!result.isOk()) {
115         return nullptr;
116     }
117     std::vector<int32_t> vibratorIds = result.value();
118     jintArray ids = env->NewIntArray(vibratorIds.size());
119     env->SetIntArrayRegion(ids, 0, vibratorIds.size(), reinterpret_cast<jint*>(vibratorIds.data()));
120     return ids;
121 }
122 
nativePrepareSynced(JNIEnv * env,jclass,jlong servicePtr,jintArray vibratorIds)123 static jboolean nativePrepareSynced(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
124                                     jintArray vibratorIds) {
125     NativeVibratorManagerService* service =
126             reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
127     if (service == nullptr) {
128         ALOGE("nativePrepareSynced failed because native service was not initialized");
129         return JNI_FALSE;
130     }
131     jsize size = env->GetArrayLength(vibratorIds);
132     std::vector<int32_t> ids(size);
133     env->GetIntArrayRegion(vibratorIds, 0, size, reinterpret_cast<jint*>(ids.data()));
134     return service->hal()->prepareSynced(ids).isOk() ? JNI_TRUE : JNI_FALSE;
135 }
136 
nativeTriggerSynced(JNIEnv * env,jclass,jlong servicePtr,jlong vibrationId)137 static jboolean nativeTriggerSynced(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
138                                     jlong vibrationId) {
139     NativeVibratorManagerService* service =
140             reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
141     if (service == nullptr) {
142         ALOGE("nativeTriggerSynced failed because native service was not initialized");
143         return JNI_FALSE;
144     }
145     auto callback = service->createCallback(vibrationId);
146     return service->hal()->triggerSynced(callback).isOk() ? JNI_TRUE : JNI_FALSE;
147 }
148 
nativeCancelSynced(JNIEnv * env,jclass,jlong servicePtr)149 static void nativeCancelSynced(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
150     NativeVibratorManagerService* service =
151             reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
152     if (service == nullptr) {
153         ALOGE("nativeCancelSynced failed because native service was not initialized");
154         return;
155     }
156     service->hal()->cancelSynced();
157 }
158 
159 inline static constexpr auto sNativeInitMethodSignature =
160         "(Lcom/android/server/vibrator/VibratorManagerService$OnSyncedVibrationCompleteListener;)J";
161 
162 static const JNINativeMethod method_table[] = {
163         {"nativeInit", sNativeInitMethodSignature, (void*)nativeInit},
164         {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer},
165         {"nativeGetCapabilities", "(J)J", (void*)nativeGetCapabilities},
166         {"nativeGetVibratorIds", "(J)[I", (void*)nativeGetVibratorIds},
167         {"nativePrepareSynced", "(J[I)Z", (void*)nativePrepareSynced},
168         {"nativeTriggerSynced", "(JJ)Z", (void*)nativeTriggerSynced},
169         {"nativeCancelSynced", "(J)V", (void*)nativeCancelSynced},
170 };
171 
register_android_server_vibrator_VibratorManagerService(JavaVM * jvm,JNIEnv * env)172 int register_android_server_vibrator_VibratorManagerService(JavaVM* jvm, JNIEnv* env) {
173     sJvm = jvm;
174     auto listenerClassName =
175             "com/android/server/vibrator/VibratorManagerService$OnSyncedVibrationCompleteListener";
176     jclass listenerClass = FindClassOrDie(env, listenerClassName);
177     sMethodIdOnComplete = GetMethodIDOrDie(env, listenerClass, "onComplete", "(J)V");
178 
179     return jniRegisterNativeMethods(env, "com/android/server/vibrator/VibratorManagerService",
180                                     method_table, NELEM(method_table));
181 }
182 
183 }; // namespace android
184