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