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 "com_android_server_vibrator_VibratorManagerService.h"
20
21 #include <nativehelper/JNIHelp.h>
22 #include <utils/Log.h>
23 #include <utils/misc.h>
24 #include <vibratorservice/VibratorManagerHalController.h>
25
26 #include <unordered_map>
27
28 #include "android_runtime/AndroidRuntime.h"
29 #include "core_jni_helpers.h"
30 #include "jni.h"
31
32 namespace android {
33
34 static JavaVM* sJvm = nullptr;
35 static jmethodID sMethodIdOnSyncedVibrationComplete;
36 static jmethodID sMethodIdOnVibrationSessionComplete;
37 static std::mutex gManagerMutex;
38 static vibrator::ManagerHalController* gManager GUARDED_BY(gManagerMutex) = nullptr;
39
40 class NativeVibratorManagerService {
41 public:
42 using IVibrationSession = aidl::android::hardware::vibrator::IVibrationSession;
43 using VibrationSessionConfig = aidl::android::hardware::vibrator::VibrationSessionConfig;
44
NativeVibratorManagerService(JNIEnv * env,jobject callbackListener)45 NativeVibratorManagerService(JNIEnv* env, jobject callbackListener)
46 : mHal(std::make_unique<vibrator::ManagerHalController>()),
47 mCallbackListener(env->NewGlobalRef(callbackListener)) {
48 LOG_ALWAYS_FATAL_IF(mHal == nullptr, "Unable to find reference to vibrator manager hal");
49 LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
50 "Unable to create global reference to vibration callback handler");
51 }
52
~NativeVibratorManagerService()53 ~NativeVibratorManagerService() {
54 auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
55 jniEnv->DeleteGlobalRef(mCallbackListener);
56 }
57
hal() const58 vibrator::ManagerHalController* hal() const { return mHal.get(); }
59
createSyncedVibrationCallback(jlong vibrationId)60 std::function<void()> createSyncedVibrationCallback(jlong vibrationId) {
61 return [vibrationId, this]() {
62 auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
63 jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnSyncedVibrationComplete,
64 vibrationId);
65 };
66 }
67
createVibrationSessionCallback(jlong sessionId)68 std::function<void()> createVibrationSessionCallback(jlong sessionId) {
69 return [sessionId, this]() {
70 auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
71 jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnVibrationSessionComplete,
72 sessionId);
73 std::lock_guard<std::mutex> lock(mSessionMutex);
74 auto it = mSessions.find(sessionId);
75 if (it != mSessions.end()) {
76 mSessions.erase(it);
77 }
78 };
79 }
80
startSession(jlong sessionId,const std::vector<int32_t> & vibratorIds)81 bool startSession(jlong sessionId, const std::vector<int32_t>& vibratorIds) {
82 VibrationSessionConfig config;
83 auto callback = createVibrationSessionCallback(sessionId);
84 auto result = hal()->startSession(vibratorIds, config, callback);
85 if (!result.isOk()) {
86 return false;
87 }
88
89 std::lock_guard<std::mutex> lock(mSessionMutex);
90 mSessions[sessionId] = std::move(result.value());
91 return true;
92 }
93
closeSession(jlong sessionId)94 void closeSession(jlong sessionId) {
95 std::lock_guard<std::mutex> lock(mSessionMutex);
96 auto it = mSessions.find(sessionId);
97 if (it != mSessions.end()) {
98 it->second->close();
99 // Keep session, it can still be aborted.
100 }
101 }
102
abortSession(jlong sessionId)103 void abortSession(jlong sessionId) {
104 std::lock_guard<std::mutex> lock(mSessionMutex);
105 auto it = mSessions.find(sessionId);
106 if (it != mSessions.end()) {
107 it->second->abort();
108 mSessions.erase(it);
109 }
110 }
111
clearSessions()112 void clearSessions() {
113 hal()->clearSessions();
114 std::lock_guard<std::mutex> lock(mSessionMutex);
115 mSessions.clear();
116 }
117
118 private:
119 std::mutex mSessionMutex;
120 const std::unique_ptr<vibrator::ManagerHalController> mHal;
121 std::unordered_map<jlong, std::shared_ptr<IVibrationSession>> mSessions
122 GUARDED_BY(mSessionMutex);
123 const jobject mCallbackListener;
124 };
125
android_server_vibrator_VibratorManagerService_getManager()126 vibrator::ManagerHalController* android_server_vibrator_VibratorManagerService_getManager() {
127 std::lock_guard<std::mutex> lock(gManagerMutex);
128 return gManager;
129 }
130
destroyNativeService(void * ptr)131 static void destroyNativeService(void* ptr) {
132 NativeVibratorManagerService* service = reinterpret_cast<NativeVibratorManagerService*>(ptr);
133 if (service) {
134 std::lock_guard<std::mutex> lock(gManagerMutex);
135 gManager = nullptr;
136 delete service;
137 }
138 }
139
nativeInit(JNIEnv * env,jclass,jobject callbackListener)140 static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject callbackListener) {
141 std::unique_ptr<NativeVibratorManagerService> service =
142 std::make_unique<NativeVibratorManagerService>(env, callbackListener);
143 {
144 std::lock_guard<std::mutex> lock(gManagerMutex);
145 gManager = service->hal();
146 }
147 return reinterpret_cast<jlong>(service.release());
148 }
149
nativeGetFinalizer(JNIEnv *,jclass)150 static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
151 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
152 }
153
nativeGetCapabilities(JNIEnv * env,jclass,jlong servicePtr)154 static jlong nativeGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
155 NativeVibratorManagerService* service =
156 reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
157 if (service == nullptr) {
158 ALOGE("nativeGetCapabilities failed because native service was not initialized");
159 return 0;
160 }
161 auto result = service->hal()->getCapabilities();
162 return result.isOk() ? static_cast<jlong>(result.value()) : 0;
163 }
164
nativeGetVibratorIds(JNIEnv * env,jclass,jlong servicePtr)165 static jintArray nativeGetVibratorIds(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
166 NativeVibratorManagerService* service =
167 reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
168 if (service == nullptr) {
169 ALOGE("nativeGetVibratorIds failed because native service was not initialized");
170 return nullptr;
171 }
172 auto result = service->hal()->getVibratorIds();
173 if (!result.isOk()) {
174 return nullptr;
175 }
176 std::vector<int32_t> vibratorIds = result.value();
177 jintArray ids = env->NewIntArray(vibratorIds.size());
178 env->SetIntArrayRegion(ids, 0, vibratorIds.size(), reinterpret_cast<jint*>(vibratorIds.data()));
179 return ids;
180 }
181
nativePrepareSynced(JNIEnv * env,jclass,jlong servicePtr,jintArray vibratorIds)182 static jboolean nativePrepareSynced(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
183 jintArray vibratorIds) {
184 NativeVibratorManagerService* service =
185 reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
186 if (service == nullptr) {
187 ALOGE("nativePrepareSynced failed because native service was not initialized");
188 return JNI_FALSE;
189 }
190 jsize size = env->GetArrayLength(vibratorIds);
191 std::vector<int32_t> ids(size);
192 env->GetIntArrayRegion(vibratorIds, 0, size, reinterpret_cast<jint*>(ids.data()));
193 return service->hal()->prepareSynced(ids).isOk() ? JNI_TRUE : JNI_FALSE;
194 }
195
nativeTriggerSynced(JNIEnv * env,jclass,jlong servicePtr,jlong vibrationId)196 static jboolean nativeTriggerSynced(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
197 jlong vibrationId) {
198 NativeVibratorManagerService* service =
199 reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
200 if (service == nullptr) {
201 ALOGE("nativeTriggerSynced failed because native service was not initialized");
202 return JNI_FALSE;
203 }
204 auto callback = service->createSyncedVibrationCallback(vibrationId);
205 return service->hal()->triggerSynced(callback).isOk() ? JNI_TRUE : JNI_FALSE;
206 }
207
nativeCancelSynced(JNIEnv * env,jclass,jlong servicePtr)208 static void nativeCancelSynced(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
209 NativeVibratorManagerService* service =
210 reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
211 if (service == nullptr) {
212 ALOGE("nativeCancelSynced failed because native service was not initialized");
213 return;
214 }
215 service->hal()->cancelSynced();
216 }
217
nativeStartSession(JNIEnv * env,jclass,jlong servicePtr,jlong sessionId,jintArray vibratorIds)218 static jboolean nativeStartSession(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
219 jlong sessionId, jintArray vibratorIds) {
220 NativeVibratorManagerService* service =
221 reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
222 if (service == nullptr) {
223 ALOGE("nativeStartSession failed because native service was not initialized");
224 return JNI_FALSE;
225 }
226 jsize size = env->GetArrayLength(vibratorIds);
227 std::vector<int32_t> ids(size);
228 env->GetIntArrayRegion(vibratorIds, 0, size, reinterpret_cast<jint*>(ids.data()));
229 return service->startSession(sessionId, ids) ? JNI_TRUE : JNI_FALSE;
230 }
231
nativeEndSession(JNIEnv * env,jclass,jlong servicePtr,jlong sessionId,jboolean shouldAbort)232 static void nativeEndSession(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong sessionId,
233 jboolean shouldAbort) {
234 NativeVibratorManagerService* service =
235 reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
236 if (service == nullptr) {
237 ALOGE("nativeEndSession failed because native service was not initialized");
238 return;
239 }
240 if (shouldAbort) {
241 service->abortSession(sessionId);
242 } else {
243 service->closeSession(sessionId);
244 }
245 }
246
nativeClearSessions(JNIEnv * env,jclass,jlong servicePtr)247 static void nativeClearSessions(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
248 NativeVibratorManagerService* service =
249 reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
250 if (service == nullptr) {
251 ALOGE("nativeClearSessions failed because native service was not initialized");
252 return;
253 }
254 service->clearSessions();
255 }
256
257 inline static constexpr auto sNativeInitMethodSignature =
258 "(Lcom/android/server/vibrator/VibratorManagerService$VibratorManagerNativeCallbacks;)J";
259
260 static const JNINativeMethod method_table[] = {
261 {"nativeInit", sNativeInitMethodSignature, (void*)nativeInit},
nativeGetFinalizer()262 {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer},
nativeGetCapabilities(J)263 {"nativeGetCapabilities", "(J)J", (void*)nativeGetCapabilities},
nativeGetVibratorIds(J)264 {"nativeGetVibratorIds", "(J)[I", (void*)nativeGetVibratorIds},
nativePrepareSynced(J[I)265 {"nativePrepareSynced", "(J[I)Z", (void*)nativePrepareSynced},
nativeTriggerSynced(JJ)266 {"nativeTriggerSynced", "(JJ)Z", (void*)nativeTriggerSynced},
nativeCancelSynced(J)267 {"nativeCancelSynced", "(J)V", (void*)nativeCancelSynced},
nativeStartSession(JJ[I)268 {"nativeStartSession", "(JJ[I)Z", (void*)nativeStartSession},
nativeEndSession(JJZ)269 {"nativeEndSession", "(JJZ)V", (void*)nativeEndSession},
nativeClearSessions(J)270 {"nativeClearSessions", "(J)V", (void*)nativeClearSessions},
271 };
272
register_android_server_vibrator_VibratorManagerService(JavaVM * jvm,JNIEnv * env)273 int register_android_server_vibrator_VibratorManagerService(JavaVM* jvm, JNIEnv* env) {
274 sJvm = jvm;
275 auto listenerClassName =
276 "com/android/server/vibrator/VibratorManagerService$VibratorManagerNativeCallbacks";
277 jclass listenerClass = FindClassOrDie(env, listenerClassName);
278 sMethodIdOnSyncedVibrationComplete =
279 GetMethodIDOrDie(env, listenerClass, "onSyncedVibrationComplete", "(J)V");
280 sMethodIdOnVibrationSessionComplete =
281 GetMethodIDOrDie(env, listenerClass, "onVibrationSessionComplete", "(J)V");
282 return jniRegisterNativeMethods(env, "com/android/server/vibrator/VibratorManagerService",
283 method_table, NELEM(method_table));
284 }
285
286 }; // namespace android
287