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
19 #include <android-base/logging.h>
20 #include <android/hardware_buffer.h>
21 #include <android_runtime/android_hardware_HardwareBuffer.h>
22 #include <nativehelper/JNIHelp.h>
23 #include <vndk/hardware_buffer.h>
24
25 using android::hardware::automotive::evs::V1_0::EvsResult;
26 using namespace android::hardware::automotive::evs::V1_1;
27
28 namespace {
29
getMethodIDOrDie(JNIEnv * env,jclass clazz,const char * name,const char * signature)30 jmethodID getMethodIDOrDie(JNIEnv* env, jclass clazz, const char* name, const char* signature) {
31 jmethodID res = env->GetMethodID(clazz, name, signature);
32 LOG_ALWAYS_FATAL_IF(res == nullptr, "Unable to find method %s with signature %s", name,
33 signature);
34
35 return res;
36 }
37
38 } // namespace
39
40 namespace android {
41 namespace automotive {
42 namespace evs {
43
44 // "default" is reserved for the latest version of EVS manager.
45 const char* EvsServiceContext::kServiceName = "default";
46
EvsServiceContext(JavaVM * vm,jclass clazz)47 EvsServiceContext::EvsServiceContext(JavaVM* vm, jclass clazz) :
48 mVm(vm), mCallbackThread(vm), mCarEvsServiceObj(nullptr) {
49 JNIEnv* env = nullptr;
50 vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);
51 if (env != nullptr) {
52 // Registers post-native handlers
53 mDeathHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeDeathHandler", "()V");
54 mEventHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeEventHandler", "(I)V");
55 mFrameHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeFrameHandler",
56 "(ILandroid/hardware/HardwareBuffer;)V");
57 } else {
58 jniThrowException(env, "java/lang/IllegalArgumentException",
59 "Failed to get JNIEnv from a given VM instance.");
60 }
61 }
62
~EvsServiceContext()63 EvsServiceContext::~EvsServiceContext() {
64 {
65 std::lock_guard<std::mutex> lock(mLock);
66 if (mService != nullptr) {
67 mService->unlinkToDeath(mDeathRecipient);
68 }
69 mService = nullptr;
70 mCamera = nullptr;
71 mStreamHandler = nullptr;
72 }
73
74 // Stops the callback thread
75 mCallbackThread.stop();
76
77 // Deletes a global reference to the CarEvsService object
78 JNIEnv* env = nullptr;
79 if (mVm != nullptr) {
80 mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);
81 if (env != nullptr) {
82 env->DeleteGlobalRef(mCarEvsServiceObj);
83 }
84 }
85 }
86
initialize(JNIEnv * env,jobject thiz)87 bool EvsServiceContext::initialize(JNIEnv* env, jobject thiz) {
88 sp<IEvsEnumerator> service = IEvsEnumerator::tryGetService(EvsServiceContext::kServiceName);
89 if (!service) {
90 // TODO(b/177923058): it may be desired to retry a few times if the
91 // connection fails.
92 LOG(ERROR) << "Failed to connect to EVS service.";
93 return false;
94 }
95
96 sp<EvsDeathRecipient> deathRecipient = new EvsDeathRecipient(service, this);
97 auto ret = service->linkToDeath(deathRecipient, /*cookie=*/0);
98 if (!ret.isOk() || ret == false) {
99 LOG(ERROR) << "Failed to register a death recipient; the service may die.";
100 return false;
101 }
102
103 {
104 std::lock_guard<std::mutex> lock(mLock);
105 mService = service;
106 mDeathRecipient = deathRecipient;
107 if (!mCarEvsServiceObj) {
108 mCarEvsServiceObj = env->NewGlobalRef(thiz);
109 }
110 }
111
112 return true;
113 }
114
openCamera(const char * id)115 bool EvsServiceContext::openCamera(const char* id) {
116 if (!isAvailable()) {
117 LOG(ERROR) << "Has not connected to EVS service yet.";
118 return false;
119 }
120
121 if (isCameraOpened()) {
122 if (!strcmp(id, mCameraIdInUse)) {
123 LOG(DEBUG) << "Camera " << id << " is has opened already.";
124 return true;
125 } else {
126 // Close a current camera device.
127 mService->closeCamera(mCamera);
128 }
129 }
130
131 sp<IEvsCamera> camera = IEvsCamera::castFrom(mService->openCamera(id));
132 if (!camera) {
133 LOG(ERROR) << "Failed to open a camera " << id;
134 return false;
135 }
136
137 sp<StreamHandler> streamHandler =
138 new StreamHandler(camera, this, EvsServiceContext::kMaxNumFramesInFlight);
139 if (!streamHandler) {
140 LOG(ERROR) << "Failed to initialize a stream streamHandler.";
141 return false;
142 }
143
144 {
145 std::lock_guard<std::mutex> lock(mLock);
146 mCamera = camera;
147 mStreamHandler = streamHandler;
148 mCameraIdInUse = id;
149 }
150
151 return true;
152 }
153
closeCamera()154 void EvsServiceContext::closeCamera() {
155 if (!isCameraOpened()) {
156 LOG(DEBUG) << "Camera has not opened yet.";
157 return;
158 }
159
160 mService->closeCamera(mCamera);
161 }
162
startVideoStream()163 bool EvsServiceContext::startVideoStream() {
164 if (!isCameraOpened()) {
165 LOG(ERROR) << "Camera has not opened yet.";
166 return JNI_FALSE;
167 }
168
169 return mStreamHandler->startStream();
170 }
171
stopVideoStream()172 void EvsServiceContext::stopVideoStream() {
173 if (!isCameraOpened()) {
174 LOG(DEBUG) << "Camera has not opened; a request to stop a video steram is ignored.";
175 return;
176 }
177
178 if (!mStreamHandler->asyncStopStream()) {
179 LOG(WARNING) << "Failed to stop a video stream. EVS service may die.";
180 }
181 }
182
acquireCameraAndDisplay()183 void EvsServiceContext::acquireCameraAndDisplay() {
184 // Acquires the display ownership. Because EVS awards this to the single
185 // client, no other clients can use EvsDisplay as long as CarEvsManager
186 // alives.
187 mDisplay = mService->openDisplay_1_1(EvsServiceContext::kExclusiveMainDisplayId);
188 if (!mDisplay) {
189 LOG(WARNING) << "Failed to acquire the display ownership. "
190 << "CarEvsManager may not be able to render "
191 << "the contents on the screen.";
192 return;
193 }
194
195 // Attempts to become a primary owner
196 auto ret = mCamera->forceMaster(mDisplay);
197 if (!ret.isOk() || ret != EvsResult::OK) {
198 LOG(WARNING) << "Failed to own a camera device.";
199 }
200 }
201
doneWithFrame(int bufferId)202 void EvsServiceContext::doneWithFrame(int bufferId) {
203 BufferDesc bufferToReturn;
204 {
205 std::lock_guard<std::mutex> lock(mLock);
206 auto it = mBufferRecords.find(bufferId);
207 if (it == mBufferRecords.end()) {
208 LOG(WARNING) << "Unknown buffer is requested to return.";
209 return;
210 }
211
212 bufferToReturn = it->second;
213 mBufferRecords.erase(it);
214 }
215 mStreamHandler->doneWithFrame(bufferToReturn);
216
217 // If this is the first frame since current video stream started, we'd claim
218 // the exclusive ownership of the camera and the display and keep for the rest
219 // of the lifespan.
220 std::call_once(mDisplayAcquired, &EvsServiceContext::acquireCameraAndDisplay, this);
221 }
222
223 /*
224 * Forwards EVS stream events to the client. This method will run in the
225 * context of EvsCallbackThread.
226 */
onNewEvent(EvsEventDesc event)227 void EvsServiceContext::onNewEvent(EvsEventDesc event) {
228 mCallbackThread.enqueue([event, this](JNIEnv* env) {
229 // Gives an event callback
230 env->CallVoidMethod(mCarEvsServiceObj, mEventHandlerMethodId,
231 static_cast<jint>(event.aType));
232 });
233 }
234
235 /*
236 * Forwards EVS frames to the client. This method will run in the context of
237 * EvsCallbackThread.
238 */
onNewFrame(BufferDesc bufferDesc)239 void EvsServiceContext::onNewFrame(BufferDesc bufferDesc) {
240 mCallbackThread.enqueue([bufferDesc, this](JNIEnv* env) {
241 const auto createFromAHardwareBuffer =
242 android::android_hardware_HardwareBuffer_createFromAHardwareBuffer;
243
244 // Clones a AHardwareBuffer
245 AHardwareBuffer_Desc const* desc =
246 reinterpret_cast<AHardwareBuffer_Desc const*>(&bufferDesc.buffer.description);
247
248 AHardwareBuffer* rawBuffer;
249 auto status =
250 AHardwareBuffer_createFromHandle(desc, bufferDesc.buffer.nativeHandle,
251 AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
252 &rawBuffer);
253 if (status != android::NO_ERROR) {
254 LOG(ERROR) << "Failed to create a raw hardware buffer from a native handle.";
255 mStreamHandler->doneWithFrame(bufferDesc);
256 } else {
257 {
258 std::lock_guard<std::mutex> lock(mLock);
259 mBufferRecords.try_emplace(bufferDesc.bufferId, bufferDesc);
260 }
261
262 // Calls back
263 jobject hwBuffer = createFromAHardwareBuffer(env, rawBuffer);
264 if (!hwBuffer) {
265 LOG(WARNING) << "Failed to create HardwareBuffer from AHardwareBuffer.";
266 mStreamHandler->doneWithFrame(bufferDesc);
267 } else {
268 env->CallVoidMethod(mCarEvsServiceObj, mFrameHandlerMethodId, bufferDesc.bufferId,
269 hwBuffer);
270 }
271 env->DeleteLocalRef(hwBuffer);
272 AHardwareBuffer_release(rawBuffer);
273 }
274 });
275 }
276
277 /*
278 * Handles an unexpected death of EVS service. This method will run in the
279 * context of EvsCallbackThread.
280 */
onServiceDied(const wp<hidl::base::V1_0::IBase> & who)281 void EvsServiceContext::onServiceDied(const wp<hidl::base::V1_0::IBase>& who) {
282 mCallbackThread.enqueue([who, this](JNIEnv* env) {
283 if (!isEqual(who)) {
284 // We're not interested in this death notification.
285 return;
286 }
287
288 // Drops invalidated service handles. We will re-initialize them when
289 // we try to reconnect. The buffer record would be cleared safely
290 // because all buffer references get invalidated upon the death of the
291 // native EVS service.
292 {
293 std::lock_guard<std::mutex> lock(mLock);
294 mCamera = nullptr;
295 mService = nullptr;
296 mStreamHandler = nullptr;
297 mBufferRecords.clear();
298 }
299
300 LOG(ERROR) << "The native EVS service has died.";
301 // EVS service has died but CarEvsManager instance still alives.
302 // Only a service handle needs to be destroyed; this will be
303 // re-created when CarEvsManager successfully connects to EVS service
304 // when it comes back.
305 env->CallVoidMethod(mCarEvsServiceObj, mDeathHandlerMethodId);
306 });
307 }
308
309 } // namespace evs
310 } // namespace automotive
311 } // namespace android
312