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 #include "NoOpEvsDisplay.h"
19
20 #include <aidl/android/hardware/automotive/evs/EvsResult.h>
21 #include <aidl/android/hardware/common/NativeHandle.h>
22 #include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
23 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
24 #include <android-base/logging.h>
25 #include <android-base/scopeguard.h>
26 #include <android/binder_ibinder.h>
27 #include <android/binder_manager.h>
28 #include <android/hardware_buffer_jni.h> // for AHardwareBuffer_toHardwareBuffer
29 #include <cutils/native_handle.h>
30 #include <nativehelper/JNIHelp.h>
31 #include <vndk/hardware_buffer.h> // for AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE
32
33 namespace {
34
35 using ::aidl::android::hardware::automotive::evs::BufferDesc;
36 using ::aidl::android::hardware::automotive::evs::CameraDesc;
37 using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
38 using ::aidl::android::hardware::automotive::evs::EvsResult;
39 using ::aidl::android::hardware::automotive::evs::IEvsCamera;
40 using ::aidl::android::hardware::automotive::evs::IEvsEnumerator;
41 using ::aidl::android::hardware::automotive::evs::Stream;
42 using ::aidl::android::hardware::automotive::evs::StreamType;
43 using ::aidl::android::hardware::common::NativeHandle;
44 using ::aidl::android::hardware::graphics::common::HardwareBuffer;
45 using AidlPixelFormat = ::aidl::android::hardware::graphics::common::PixelFormat;
46
47 // "default" is reserved for the latest version of EVS manager.
48 constexpr const char kEvsManagerServiceName[] =
49 "android.hardware.automotive.evs.IEvsEnumerator/default";
50
getMethodIDOrDie(JNIEnv * env,jclass clazz,const char * name,const char * signature)51 jmethodID getMethodIDOrDie(JNIEnv* env, jclass clazz, const char* name, const char* signature) {
52 jmethodID res = env->GetMethodID(clazz, name, signature);
53 if (res == nullptr) {
54 LOG(FATAL) << "Unable to find method " << name << " with signature = " << signature;
55 }
56
57 return res;
58 }
59
selectStreamConfiguration(const std::vector<Stream> & list)60 Stream selectStreamConfiguration(const std::vector<Stream>& list) {
61 for (const auto& cfg : list) {
62 // TODO(b/223905367): this logic simply selects the first output stream
63 // configuration that generates RGBA8888 data stream.
64 if (cfg.streamType == StreamType::OUTPUT && cfg.format == AidlPixelFormat::RGBA_8888) {
65 LOG(INFO) << "Selected stream configuration: width = " << cfg.width
66 << ", height = " << cfg.height
67 << ", format = " << static_cast<int>(cfg.format);
68 return std::move(cfg);
69 }
70 }
71
72 return {};
73 }
74
makeFromAidl(const NativeHandle & handle)75 native_handle_t* makeFromAidl(const NativeHandle& handle) {
76 // Create native_handle_t from
77 // ::aidl::android::hardware::common::NativeHandle. See also
78 // ::android::makeFromAidl() and native_handle_create().
79 const auto numFds = handle.fds.size();
80 const auto numInts = handle.ints.size();
81
82 if (numFds < 0 || numInts < 0 || numFds > NATIVE_HANDLE_MAX_FDS ||
83 numInts > NATIVE_HANDLE_MAX_INTS) {
84 return nullptr;
85 }
86
87 const auto mallocSize = sizeof(native_handle_t) + (sizeof(int) * (numFds + numInts));
88 native_handle_t* h = static_cast<native_handle_t*>(malloc(mallocSize));
89 if (h == nullptr) {
90 return nullptr;
91 }
92
93 h->version = sizeof(native_handle_t);
94 h->numFds = numFds;
95 h->numInts = numInts;
96 for (auto i = 0; i < handle.fds.size(); ++i) {
97 h->data[i] = handle.fds[i].get();
98 }
99 memcpy(h->data + handle.fds.size(), handle.ints.data(), handle.ints.size() * sizeof(int));
100
101 return h;
102 }
103
104 } // namespace
105
106 namespace android::automotive::evs {
107
init()108 bool ProdServiceFactory::init() {
109 bool isDeclared = ::AServiceManager_isDeclared(mServiceName.c_str());
110 if (!isDeclared) {
111 LOG(ERROR) << mServiceName << " is not available.";
112 return false;
113 }
114
115 AIBinder* binder = ::AServiceManager_checkService(mServiceName.c_str());
116 if (binder == nullptr) {
117 LOG(ERROR) << "IEvsEnumerator is not ready yet.";
118 return false;
119 }
120
121 mService = IEvsEnumerator::fromBinder(::ndk::SpAIBinder(binder));
122 return true;
123 }
124
linkToDeath(AIBinder * binder,AIBinder_DeathRecipient * recipient,void * cookie)125 binder_status_t ProdLinkUnlinkToDeath::linkToDeath(AIBinder* binder,
126 AIBinder_DeathRecipient* recipient,
127 void* cookie) {
128 mCookie = cookie;
129 mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(recipient);
130 return AIBinder_linkToDeath(binder, recipient, cookie);
131 }
132
unlinkToDeath(AIBinder * binder)133 binder_status_t ProdLinkUnlinkToDeath::unlinkToDeath(AIBinder* binder) {
134 return AIBinder_unlinkToDeath(binder, mDeathRecipient.release(), mCookie);
135 }
136
getCookie()137 void* ProdLinkUnlinkToDeath::getCookie() {
138 return mCookie;
139 }
140
EvsServiceContext(JavaVM * vm,JNIEnv * env,jclass clazz,std::unique_ptr<IEvsServiceFactory> serviceFactory,std::unique_ptr<LinkUnlinkToDeathBase> linkUnlinkImpl)141 EvsServiceContext::EvsServiceContext(JavaVM* vm, JNIEnv* env, jclass clazz,
142 std::unique_ptr<IEvsServiceFactory> serviceFactory,
143 std::unique_ptr<LinkUnlinkToDeathBase> linkUnlinkImpl) :
144 mServiceFactory(std::move(serviceFactory)),
145 mLinkUnlinkImpl(std::move(linkUnlinkImpl)),
146 mVm(vm),
147 mCallbackThread(vm),
148 mCarEvsServiceObj(nullptr) {
149 // Registers post-native handlers
150 mDeathHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeDeathHandler", "()V");
151 mEventHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeEventHandler", "(I)V");
152 mFrameHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeFrameHandler",
153 "(ILandroid/hardware/HardwareBuffer;)V");
154 }
155
create(JavaVM * vm,jclass clazz)156 EvsServiceContext* EvsServiceContext::create(JavaVM* vm, jclass clazz) {
157 return EvsServiceContext::create(vm, clazz,
158 std::make_unique<ProdServiceFactory>(kEvsManagerServiceName),
159 std::make_unique<ProdLinkUnlinkToDeath>());
160 }
161
create(JavaVM * vm,jclass clazz,std::unique_ptr<IEvsServiceFactory> serviceFactory,std::unique_ptr<LinkUnlinkToDeathBase> linkUnlinkImpl)162 EvsServiceContext* EvsServiceContext::create(
163 JavaVM* vm, jclass clazz, std::unique_ptr<IEvsServiceFactory> serviceFactory,
164 std::unique_ptr<LinkUnlinkToDeathBase> linkUnlinkImpl) {
165 JNIEnv* env = nullptr;
166 vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);
167 if (env == nullptr || !serviceFactory) {
168 jniThrowException(env, "java/lang/IllegalArgumentException",
169 "Failed to get JNIEnv from a given VM instance or a given service "
170 "factory is invalid.");
171 return nullptr;
172 }
173
174 return new EvsServiceContext(vm, env, clazz, std::move(serviceFactory),
175 std::move(linkUnlinkImpl));
176 }
177
~EvsServiceContext()178 EvsServiceContext::~EvsServiceContext() {
179 // Releases the resources
180 deinitialize();
181
182 // Stops the callback thread
183 mCallbackThread.stop();
184
185 // Deletes a global reference to the CarEvsService object
186 JNIEnv* env = nullptr;
187 if (mVm != nullptr) {
188 mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);
189 if (env != nullptr) {
190 env->DeleteGlobalRef(mCarEvsServiceObj);
191 }
192 }
193 }
194
initialize(JNIEnv * env,jobject thiz)195 bool EvsServiceContext::initialize(JNIEnv* env, jobject thiz) {
196 if (isAvailable()) {
197 LOG(DEBUG) << "This service context is initialized already.";
198 return true;
199 }
200
201 std::lock_guard lock(mLock);
202 if (!mServiceFactory || !mServiceFactory->init()) {
203 LOG(ERROR) << "Failed to connect to EVS service.";
204 return false;
205 }
206
207 auto deathRecipient = ::AIBinder_DeathRecipient_new(EvsServiceContext::onEvsServiceBinderDied);
208 auto status = ::ndk::ScopedAStatus::fromStatus(
209 mLinkUnlinkImpl->linkToDeath(mServiceFactory->getService()->asBinder().get(),
210 deathRecipient, this));
211 if (!status.isOk()) {
212 LOG(WARNING) << "Failed to register a death recipient; continuing anyway: "
213 << status.getDescription();
214 }
215
216 if (!mCarEvsServiceObj) {
217 mCarEvsServiceObj = env->NewGlobalRef(thiz);
218 }
219
220 // Reset a stored camera id and a display handle
221 mCameraIdInUse.clear();
222 mDisplay = nullptr;
223
224 // Fetch a list of available camera devices
225 status = mServiceFactory->getService()->getCameraList(&mCameraList);
226 if (!status.isOk()) {
227 LOG(ERROR) << "Failed to load a camera list, error = " << status.getServiceSpecificError();
228 return false;
229 } else if (mCameraList.size() < 1) {
230 LOG(ERROR) << "No camera device is available";
231 return false;
232 }
233
234 LOG(INFO) << mCameraList.size() << " camera devices are listed.";
235
236 return true;
237 }
238
deinitialize()239 void EvsServiceContext::deinitialize() {
240 std::lock_guard<std::mutex> lock(mLock);
241
242 mCamera = nullptr;
243 mStreamHandler = nullptr;
244 mServiceFactory.reset();
245 mLinkUnlinkImpl.reset();
246 }
247
openCamera(const char * id)248 bool EvsServiceContext::openCamera(const char* id) {
249 CameraDesc desc;
250 IEvsEnumerator* pService;
251 std::shared_ptr<IEvsCamera> cameraToClose;
252 {
253 std::lock_guard lock(mLock);
254 if (!isAvailableLocked()) {
255 LOG(ERROR) << "Has not connected to EVS service yet.";
256 return false;
257 }
258
259 if (isCameraOpenedLocked()) {
260 if (mCameraIdInUse == id) {
261 LOG(DEBUG) << "Camera " << id << " is has opened already.";
262 return true;
263 }
264
265 cameraToClose = mCamera;
266 LOG(INFO) << "Current camera will be closed.";
267 }
268
269 auto it = std::find_if(mCameraList.begin(), mCameraList.end(),
270 [target = std::string(id)](const CameraDesc& desc) {
271 return target == desc.id;
272 });
273 if (it == mCameraList.end()) {
274 // Refresh a list of available cameras and try again.
275 if (!mServiceFactory->getService()->getCameraList(&mCameraList).isOk()) {
276 LOG(ERROR) << "Failed to update a camera list.";
277 return false;
278 }
279
280 it = std::find_if(mCameraList.begin(), mCameraList.end(),
281 [target = std::string(id)](const CameraDesc& desc) {
282 return target == desc.id;
283 });
284 if (it == mCameraList.end()) {
285 LOG(ERROR) << id << " is not available";
286 return false;
287 }
288 }
289
290 cameraToClose = mCamera;
291 desc = *it;
292 pService = mServiceFactory->getService();
293 if (pService == nullptr) {
294 LOG(ERROR) << "IEvsEnumerator is not available.";
295 return false;
296 }
297 }
298
299 // Close a current camera device.
300 if (cameraToClose && !pService->closeCamera(cameraToClose).isOk()) {
301 LOG(WARNING) << "Failed to close a current camera device";
302 }
303
304 std::vector<Stream> availableStreams;
305 pService->getStreamList(desc, &availableStreams);
306
307 Stream streamConfig = selectStreamConfiguration(availableStreams);
308 std::shared_ptr<IEvsCamera> camObj;
309 if (!pService->openCamera(id, streamConfig, &camObj).isOk() ||
310 !camObj) {
311 LOG(ERROR) << "Failed to open a camera " << id;
312 return false;
313 }
314
315 std::shared_ptr<StreamHandler> streamHandler =
316 ::ndk::SharedRefBase::make<StreamHandler>(camObj, this,
317 EvsServiceContext::kMaxNumFramesInFlight);
318 if (!streamHandler) {
319 LOG(ERROR) << "Failed to initialize a stream streamHandler.";
320 if (!pService->closeCamera(camObj).isOk()) {
321 LOG(ERROR) << "Failed to close a temporary camera device";
322 }
323 return false;
324 }
325
326 {
327 std::lock_guard lock(mLock);
328 mCamera = std::move(camObj);
329 mStreamHandler = std::move(streamHandler);
330 mCameraIdInUse = id;
331 }
332
333 return true;
334 }
335
closeCamera()336 void EvsServiceContext::closeCamera() {
337 std::lock_guard lock(mLock);
338 if (!isAvailableLocked() || !isCameraOpenedLocked()) {
339 LOG(DEBUG) << "Not connected to the Extended View System service or no camera has opened "
340 "yet; a request to close a camera is ignored.";
341 return;
342 }
343
344 if (!mServiceFactory->getService()->closeCamera(mCamera).isOk()) {
345 LOG(WARNING) << "Failed to close a current camera device.";
346 }
347
348 // Reset a camera reference and id in use.
349 mCamera.reset();
350 mCameraIdInUse.clear();
351 }
352
startVideoStream()353 bool EvsServiceContext::startVideoStream() {
354 std::lock_guard lock(mLock);
355 if (!isAvailableLocked() || !isCameraOpenedLocked()) {
356 LOG(ERROR)
357 << "Not connected to the Extended View System service or no camera has opened yet.";
358 return JNI_FALSE;
359 }
360
361 return mStreamHandler->startStream();
362 }
363
stopVideoStream()364 void EvsServiceContext::stopVideoStream() {
365 std::lock_guard lock(mLock);
366 if (!isAvailableLocked() || !isCameraOpenedLocked()) {
367 LOG(DEBUG) << "Not connected to the Extended View System service or no camera has opened "
368 "yet; a request to stop a video steram is ignored.";
369 return;
370 }
371
372 mStreamHandler->blockingStopStream();
373 }
374
acquireCameraAndDisplayLocked()375 void EvsServiceContext::acquireCameraAndDisplayLocked() {
376 if (!mCamera) {
377 LOG(DEBUG) << "A target camera is not available.";
378 return;
379 }
380
381 // Acquires the display ownership. Because EVS awards this to the single
382 // client, no other clients can use EvsDisplay as long as CarEvsManager
383 // alives.
384 ::ndk::ScopedAStatus status =
385 mServiceFactory->getService()->openDisplay(EvsServiceContext::kExclusiveMainDisplayId,
386 &mDisplay);
387 if (!status.isOk() || !mDisplay) {
388 LOG(WARNING) << "Failed to acquire the display ownership. "
389 << "CarEvsManager may not be able to render "
390 << "the contents on the screen.";
391
392 // We hold a no-op IEvsDisplay object to avoid attempting to open a
393 // display repeatedly.
394 mDisplay = ndk::SharedRefBase::make<NoOpEvsDisplay>();
395 return;
396 }
397
398 // Attempts to become a primary owner
399 status = mCamera->forcePrimaryClient(mDisplay);
400 if (!status.isOk() ||
401 static_cast<EvsResult>(status.getServiceSpecificError()) != EvsResult::OK) {
402 LOG(WARNING) << "Failed to own a camera device: " << status.getMessage();
403 }
404 }
405
doneWithFrame(int bufferId)406 void EvsServiceContext::doneWithFrame(int bufferId) {
407 std::lock_guard<std::mutex> lock(mLock);
408 if (!mStreamHandler) {
409 LOG(DEBUG) << "A stream handler is not available.";
410 return;
411 }
412
413 auto it = mBufferRecords.find(bufferId);
414 if (it == mBufferRecords.end()) {
415 LOG(WARNING) << "Unknown buffer is requested to return.";
416 return;
417 }
418
419 mBufferRecords.erase(it);
420
421 // If this is the first frame since current video stream started, we'd claim
422 // the exclusive ownership of the camera and the display and keep for the rest
423 // of the lifespan.
424 if (!mDisplay) {
425 acquireCameraAndDisplayLocked();
426 }
427 mStreamHandler->doneWithFrame(bufferId);
428 }
429
430 /*
431 * Forwards EVS stream events to the client. This method will run in the
432 * context of EvsCallbackThread.
433 */
onNewEvent(const EvsEventDesc & event)434 void EvsServiceContext::onNewEvent(const EvsEventDesc& event) {
435 mCallbackThread.enqueue([event, this](JNIEnv* env) {
436 // Gives an event callback
437 env->CallVoidMethod(mCarEvsServiceObj, mEventHandlerMethodId,
438 static_cast<jint>(event.aType));
439 });
440 }
441
442 /*
443 * Forwards EVS frames to the client. This method will run in the context of
444 * EvsCallbackThread.
445 */
onNewFrame(const BufferDesc & bufferDesc)446 bool EvsServiceContext::onNewFrame(const BufferDesc& bufferDesc) {
447 // Create AHardwareBuffer from ::aidl::android::hardware::automotive::evs::BufferDesc
448 native_handle_t* nativeHandle = makeFromAidl(bufferDesc.buffer.handle);
449 const auto handleGuard = ::android::base::make_scope_guard([nativeHandle] {
450 // We only need to free an allocated memory because a source buffer is
451 // owned by EVS HAL implementation.
452 free(nativeHandle);
453 });
454
455 if (nativeHandle == nullptr ||
456 !std::all_of(nativeHandle->data + 0, nativeHandle->data + nativeHandle->numFds,
457 [](int fd) { return fd >= 0; })) {
458 LOG(ERROR) << " android::makeFromAidl returned an invalid native handle";
459 return false;
460 }
461
462 const AHardwareBuffer_Desc desc{
463 .width = static_cast<uint32_t>(bufferDesc.buffer.description.width),
464 .height = static_cast<uint32_t>(bufferDesc.buffer.description.height),
465 .layers = static_cast<uint32_t>(bufferDesc.buffer.description.layers),
466 .format = static_cast<uint32_t>(bufferDesc.buffer.description.format),
467 .usage = static_cast<uint64_t>(bufferDesc.buffer.description.usage),
468 .stride = static_cast<uint32_t>(bufferDesc.buffer.description.stride),
469 };
470
471 AHardwareBuffer* ahwb = nullptr;
472 const auto status =
473 AHardwareBuffer_createFromHandle(&desc, nativeHandle,
474 AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
475 &ahwb);
476 if (status != android::NO_ERROR) {
477 LOG(ERROR) << "Failed to create a raw hardware buffer from a native handle, "
478 << "status = " << statusToString(status);
479 std::lock_guard lock(mLock);
480 mStreamHandler->doneWithFrame(bufferDesc.bufferId);
481 return false;
482 }
483
484 mCallbackThread.enqueue([ahwb, bufferId = bufferDesc.bufferId, this](JNIEnv* env) {
485 jobject hwBuffer;
486 {
487 std::lock_guard lock(mLock);
488 mBufferRecords.insert(bufferId);
489
490 // Forward AHardwareBuffer to the client
491 hwBuffer = AHardwareBuffer_toHardwareBuffer(env, ahwb);
492 if (!hwBuffer) {
493 LOG(WARNING) << "Failed to create HardwareBuffer from AHardwareBuffer.";
494 mStreamHandler->doneWithFrame(bufferId);
495 AHardwareBuffer_release(ahwb);
496 return;
497 }
498 }
499
500 env->CallVoidMethod(mCarEvsServiceObj, mFrameHandlerMethodId, bufferId, hwBuffer);
501 env->DeleteLocalRef(hwBuffer);
502
503 // We're done
504 AHardwareBuffer_release(ahwb);
505 });
506
507 return true;
508 }
509
510 /*
511 * Handles an unexpected death of EVS service. This method will run in the
512 * context of EvsCallbackThread.
513 */
onEvsServiceDiedImpl()514 void EvsServiceContext::onEvsServiceDiedImpl() {
515 mCallbackThread.enqueue([this](JNIEnv* env) {
516 // Drops invalidated service handles. We will re-initialize them when
517 // we try to reconnect. The buffer record would be cleared safely
518 // because all buffer references get invalidated upon the death of the
519 // native EVS service.
520 {
521 std::lock_guard<std::mutex> lock(mLock);
522 mCamera = nullptr;
523 mStreamHandler = nullptr;
524 mBufferRecords.clear();
525 mCameraIdInUse.clear();
526 mLinkUnlinkImpl->unlinkToDeath(mServiceFactory->getService()->asBinder().get());
527 mServiceFactory->clear();
528 }
529
530 LOG(ERROR) << "The native EVS service has died.";
531 // EVS service has died but CarEvsManager instance still alives.
532 // Only a service handle needs to be destroyed; this will be
533 // re-created when CarEvsManager successfully connects to EVS service
534 // when it comes back.
535 env->CallVoidMethod(mCarEvsServiceObj, mDeathHandlerMethodId);
536 });
537 }
538
onEvsServiceBinderDied(void * cookie)539 void EvsServiceContext::onEvsServiceBinderDied(void* cookie) {
540 auto thiz = static_cast<EvsServiceContext*>(cookie);
541 if (!thiz) {
542 LOG(WARNING) << "A death of the EVS service is detected but ignored "
543 << "because of the invalid service context.";
544 return;
545 }
546
547 thiz->onEvsServiceDiedImpl();
548 }
549
triggerBinderDied()550 void EvsServiceContext::triggerBinderDied() {
551 #ifdef __TEST__
552 EvsServiceContext::onEvsServiceBinderDied(mLinkUnlinkImpl->getCookie());
553 #endif
554 }
555
556 } // namespace android::automotive::evs
557