1 /*
2 * Copyright 2021 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 #include "EvsServiceContext.h"
18 #ifdef __TEST__
19 #include "MockEvsServiceFactory.h"
20 #endif
21 #include <android-base/logging.h>
22 #include <nativehelper/JNIHelp.h>
23
24 #include <jni.h>
25
26 namespace {
27
28 using ::android::automotive::evs::EvsServiceContext;
29 #ifdef __TEST__
30 using ::android::automotive::evs::MockEvsServiceFactory;
31 using ::android::automotive::evs::MockLinkUnlinkToDeath;
32 #endif
33
34 // EvsHalWrapperImpl class
35 constexpr const char kCarEvsServiceClassName[] = "com/android/car/evs/EvsHalWrapperImpl";
36
37 /*
38 * Connects to the Extended View System service
39 */
connectToHalServiceIfNecessary(JNIEnv * env,jobject thiz,jlong handle)40 jboolean connectToHalServiceIfNecessary(JNIEnv* env, jobject thiz, jlong handle) {
41 EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
42 if (!ctxt) {
43 LOG(ERROR) << "The service context is invalid.";
44 return JNI_FALSE;
45 }
46
47 if (ctxt->isAvailable()) {
48 LOG(DEBUG) << "Service is connected already.";
49 return JNI_TRUE;
50 }
51
52 LOG(DEBUG) << "Connecting to EVS service";
53
54 // Initializes a new service context with a death handler
55 if (!ctxt->initialize(env, thiz)) {
56 LOG(ERROR) << "Failed to initialize a service context";
57 return JNI_FALSE;
58 }
59
60 return JNI_TRUE;
61 }
62
63 /*
64 * Disconnects from the Extended View System service
65 */
disconnectFromHalService(JNIEnv *,jobject,jlong handle)66 void disconnectFromHalService(JNIEnv*, jobject, jlong handle) {
67 EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
68 if (ctxt == nullptr || !ctxt->isAvailable()) {
69 LOG(DEBUG) << "Ignores a disconnecting service request with an invalid handle.";
70 return;
71 }
72
73 // We simply delete a service handle.
74 ctxt->deinitialize();
75 }
76
77 /*
78 * Returns a consumed frame buffer to EVS service
79 */
returnFrameBuffer(JNIEnv *,jobject,jlong handle,jint bufferId)80 void returnFrameBuffer(JNIEnv* /*env*/, jobject /*thiz*/, jlong handle, jint bufferId) {
81 EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
82 if (!ctxt) {
83 LOG(ERROR) << __FUNCTION__ << ": EVS service context is not available.";
84 return;
85 }
86
87 ctxt->doneWithFrame(bufferId);
88 }
89
90 /*
91 * Open the target camera device for the service
92 */
openCamera(JNIEnv * env,jobject,jlong handle,jstring cameraId)93 jboolean openCamera(JNIEnv* env, jobject /*thiz*/, jlong handle, jstring cameraId) {
94 EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
95 if (!ctxt) {
96 LOG(ERROR) << __FUNCTION__ << ": EVS service context is not available.";
97 return JNI_FALSE;
98 }
99
100 // Attempts to open the target camera device
101 const char* id = env->GetStringUTFChars(cameraId, NULL);
102 if (!id || !ctxt->openCamera(id)) {
103 LOG(ERROR) << "Failed to open a camera device";
104 return JNI_FALSE;
105 }
106
107 env->ReleaseStringUTFChars(cameraId, id);
108 return JNI_TRUE;
109 }
110
111 /*
112 * Close the target camera device
113 */
closeCamera(JNIEnv *,jobject,jlong handle)114 void closeCamera(JNIEnv* /*env*/, jobject /*thiz*/, jlong handle) {
115 EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
116 if (!ctxt) {
117 LOG(WARNING) << __FUNCTION__ << ": EVS service context is not available.";
118 }
119
120 ctxt->closeCamera();
121 }
122
123 /*
124 * Request to start a video stream
125 */
startVideoStream(JNIEnv *,jobject,jlong handle)126 jboolean startVideoStream(JNIEnv* /*env*/, jobject /*thiz*/, jlong handle) {
127 EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
128 if (!ctxt) {
129 LOG(ERROR) << __FUNCTION__ << ": EVS service context is not available.";
130 return JNI_FALSE;
131 }
132
133 return ctxt->startVideoStream() ? JNI_TRUE : JNI_FALSE;
134 }
135
136 /*
137 * Request to stop a video stream
138 */
stopVideoStream(JNIEnv *,jobject,jlong handle)139 void stopVideoStream(JNIEnv* /*env*/, jobject /*thiz*/, jlong handle) {
140 EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
141 if (!ctxt) {
142 LOG(WARNING) << __FUNCTION__ << ": EVS service context is not available.";
143 return;
144 }
145
146 ctxt->stopVideoStream();
147 }
148
149 /*
150 * Static method to create the service context
151 */
createServiceHandle(JNIEnv * env,jclass clazz)152 jlong createServiceHandle(JNIEnv* env, jclass clazz) {
153 JavaVM* vm = nullptr;
154 env->GetJavaVM(&vm);
155 if (vm == nullptr) {
156 jniThrowException(env, "java/lang/IllegalStateException",
157 "Can't initialize the EvsServiceContext because the JavaVM is invalid");
158 }
159
160 return reinterpret_cast<jlong>(EvsServiceContext::create(vm, clazz));
161 }
162
createServiceHandleForTest(JNIEnv * env,jclass clazz)163 jlong createServiceHandleForTest([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) {
164 #ifdef __TEST__
165 JavaVM* vm = nullptr;
166 env->GetJavaVM(&vm);
167 if (vm == nullptr) {
168 jniThrowException(env, "java/lang/IllegalStateException",
169 "Can't initialize the EvsServiceContext because the JavaVM is invalid");
170 }
171
172 return reinterpret_cast<jlong>(
173 EvsServiceContext::create(vm, clazz, std::make_unique<MockEvsServiceFactory>(),
174 std::make_unique<MockLinkUnlinkToDeath>()));
175 #else
176 return 0L;
177 #endif
178 }
179
triggerBinderDied(JNIEnv * env,jobject thiz,jlong handle)180 void triggerBinderDied([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject thiz,
181 [[maybe_unused]] jlong handle) {
182 #ifdef __TEST__
183 EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
184 if (!ctxt) {
185 LOG(WARNING) << __FUNCTION__ << ": EVS service context is not available.";
186 return;
187 }
188
189 ctxt->triggerBinderDied();
190 #endif
191 }
192
193 /*
194 * Static method to destroy the service context
195 */
destroyServiceHandle(JNIEnv *,jclass,jlong handle)196 void destroyServiceHandle(JNIEnv* /*env*/, jclass /*clazz*/, jlong handle) {
197 delete reinterpret_cast<EvsServiceContext*>(handle);
198 }
199
200 } // namespace
201
202 namespace android {
203
initializeCarEvsService(JavaVM * vm)204 jint initializeCarEvsService(JavaVM* vm) {
205 JNIEnv* env;
206 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
207 LOG(ERROR) << __FUNCTION__ << ": Failed to get the environment.";
208 return JNI_ERR;
209 }
210
211 // Registers native methods
212 static const JNINativeMethod methods[] = {
213 {"nativeConnectToHalServiceIfNecessary", "(J)Z",
214 reinterpret_cast<void*>(connectToHalServiceIfNecessary)},
215 {"nativeDisconnectFromHalService", "(J)V",
216 reinterpret_cast<void*>(disconnectFromHalService)},
217 {"nativeOpenCamera", "(JLjava/lang/String;)Z", reinterpret_cast<void*>(openCamera)},
218 {"nativeCloseCamera", "(J)V", reinterpret_cast<void*>(closeCamera)},
219 {"nativeRequestToStartVideoStream", "(J)Z", reinterpret_cast<void*>(startVideoStream)},
220 {"nativeRequestToStopVideoStream", "(J)V", reinterpret_cast<void*>(stopVideoStream)},
221 {"nativeDoneWithFrame", "(JI)V", reinterpret_cast<void*>(returnFrameBuffer)},
222 {"nativeTriggerBinderDied", "(J)V", reinterpret_cast<void*>(triggerBinderDied)},
223 {"nativeCreateServiceHandle", "()J", reinterpret_cast<void*>(createServiceHandle)},
224 {"nativeCreateServiceHandleForTest", "()J",
225 reinterpret_cast<void*>(createServiceHandleForTest)},
226 {"nativeDestroyServiceHandle", "(J)V", reinterpret_cast<void*>(destroyServiceHandle)},
227 };
228 jniRegisterNativeMethods(env, kCarEvsServiceClassName, methods, NELEM(methods));
229
230 return JNI_VERSION_1_6;
231 }
232
233 } // namespace android
234