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             LOG(ERROR) << id << " is not available";
275             return false;
276         }
277 
278         cameraToClose = mCamera;
279         desc = *it;
280         pService = mServiceFactory->getService();
281         if (pService == nullptr) {
282             LOG(ERROR) << "IEvsEnumerator is not available.";
283             return false;
284         }
285     }
286 
287     // Close a current camera device.
288     if (cameraToClose && !pService->closeCamera(cameraToClose).isOk()) {
289         LOG(WARNING) << "Failed to close a current camera device";
290     }
291 
292     std::vector<Stream> availableStreams;
293     pService->getStreamList(desc, &availableStreams);
294 
295     Stream streamConfig = selectStreamConfiguration(availableStreams);
296     std::shared_ptr<IEvsCamera> camObj;
297     if (!pService->openCamera(id, streamConfig, &camObj).isOk() ||
298         !camObj) {
299         LOG(ERROR) << "Failed to open a camera " << id;
300         return false;
301     }
302 
303     std::shared_ptr<StreamHandler> streamHandler =
304             ::ndk::SharedRefBase::make<StreamHandler>(camObj, this,
305                                                       EvsServiceContext::kMaxNumFramesInFlight);
306     if (!streamHandler) {
307         LOG(ERROR) << "Failed to initialize a stream streamHandler.";
308         if (!pService->closeCamera(camObj).isOk()) {
309             LOG(ERROR) << "Failed to close a temporary camera device";
310         }
311         return false;
312     }
313 
314     {
315         std::lock_guard lock(mLock);
316         mCamera = std::move(camObj);
317         mStreamHandler = std::move(streamHandler);
318         mCameraIdInUse = id;
319     }
320 
321     return true;
322 }
323 
closeCamera()324 void EvsServiceContext::closeCamera() {
325     std::lock_guard lock(mLock);
326     if (!isAvailableLocked() || !isCameraOpenedLocked()) {
327         LOG(DEBUG) << "Not connected to the Extended View System service or no camera has opened "
328                       "yet; a request to close a camera is ignored.";
329         return;
330     }
331 
332     if (!mServiceFactory->getService()->closeCamera(mCamera).isOk()) {
333         LOG(WARNING) << "Failed to close a current camera device.";
334     }
335 
336     // Reset a camera reference and id in use.
337     mCamera.reset();
338     mCameraIdInUse.clear();
339 }
340 
startVideoStream()341 bool EvsServiceContext::startVideoStream() {
342     std::lock_guard lock(mLock);
343     if (!isAvailableLocked() || !isCameraOpenedLocked()) {
344         LOG(ERROR)
345                 << "Not connected to the Extended View System service or no camera has opened yet.";
346         return JNI_FALSE;
347     }
348 
349     return mStreamHandler->startStream();
350 }
351 
stopVideoStream()352 void EvsServiceContext::stopVideoStream() {
353     std::lock_guard lock(mLock);
354     if (!isAvailableLocked() || !isCameraOpenedLocked()) {
355         LOG(DEBUG) << "Not connected to the Extended View System service or no camera has opened "
356                       "yet; a request to stop a video steram is ignored.";
357         return;
358     }
359 
360     mStreamHandler->blockingStopStream();
361 }
362 
acquireCameraAndDisplayLocked()363 void EvsServiceContext::acquireCameraAndDisplayLocked() {
364     if (!mCamera) {
365         LOG(DEBUG) << "A target camera is not available.";
366         return;
367     }
368 
369     // Acquires the display ownership.  Because EVS awards this to the single
370     // client, no other clients can use EvsDisplay as long as CarEvsManager
371     // alives.
372     ::ndk::ScopedAStatus status =
373             mServiceFactory->getService()->openDisplay(EvsServiceContext::kExclusiveMainDisplayId,
374                                                        &mDisplay);
375     if (!status.isOk() || !mDisplay) {
376         LOG(WARNING) << "Failed to acquire the display ownership.  "
377                      << "CarEvsManager may not be able to render "
378                      << "the contents on the screen.";
379 
380         // We hold a no-op IEvsDisplay object to avoid attempting to open a
381         // display repeatedly.
382         mDisplay = ndk::SharedRefBase::make<NoOpEvsDisplay>();
383         return;
384     }
385 
386     // Attempts to become a primary owner
387     status = mCamera->forcePrimaryClient(mDisplay);
388     if (!status.isOk() ||
389         static_cast<EvsResult>(status.getServiceSpecificError()) != EvsResult::OK) {
390         LOG(WARNING) << "Failed to own a camera device: " << status.getMessage();
391     }
392 }
393 
doneWithFrame(int bufferId)394 void EvsServiceContext::doneWithFrame(int bufferId) {
395     std::lock_guard<std::mutex> lock(mLock);
396     if (!mStreamHandler) {
397         LOG(DEBUG) << "A stream handler is not available.";
398         return;
399     }
400 
401     auto it = mBufferRecords.find(bufferId);
402     if (it == mBufferRecords.end()) {
403         LOG(WARNING) << "Unknown buffer is requested to return.";
404         return;
405     }
406 
407     mBufferRecords.erase(it);
408 
409     // If this is the first frame since current video stream started, we'd claim
410     // the exclusive ownership of the camera and the display and keep for the rest
411     // of the lifespan.
412     if (!mDisplay) {
413         acquireCameraAndDisplayLocked();
414     }
415     mStreamHandler->doneWithFrame(bufferId);
416 }
417 
418 /*
419  * Forwards EVS stream events to the client.  This method will run in the
420  * context of EvsCallbackThread.
421  */
onNewEvent(const EvsEventDesc & event)422 void EvsServiceContext::onNewEvent(const EvsEventDesc& event) {
423     mCallbackThread.enqueue([event, this](JNIEnv* env) {
424         // Gives an event callback
425         env->CallVoidMethod(mCarEvsServiceObj, mEventHandlerMethodId,
426                             static_cast<jint>(event.aType));
427     });
428 }
429 
430 /*
431  * Forwards EVS frames to the client.  This method will run in the context of
432  * EvsCallbackThread.
433  */
onNewFrame(const BufferDesc & bufferDesc)434 bool EvsServiceContext::onNewFrame(const BufferDesc& bufferDesc) {
435     // Create AHardwareBuffer from ::aidl::android::hardware::automotive::evs::BufferDesc
436     native_handle_t* nativeHandle = makeFromAidl(bufferDesc.buffer.handle);
437     const auto handleGuard = ::android::base::make_scope_guard([nativeHandle] {
438         // We only need to free an allocated memory because a source buffer is
439         // owned by EVS HAL implementation.
440         free(nativeHandle);
441     });
442 
443     if (nativeHandle == nullptr ||
444         !std::all_of(nativeHandle->data + 0, nativeHandle->data + nativeHandle->numFds,
445                      [](int fd) { return fd >= 0; })) {
446         LOG(ERROR) << " android::makeFromAidl returned an invalid native handle";
447         return false;
448     }
449 
450     const AHardwareBuffer_Desc desc{
451             .width = static_cast<uint32_t>(bufferDesc.buffer.description.width),
452             .height = static_cast<uint32_t>(bufferDesc.buffer.description.height),
453             .layers = static_cast<uint32_t>(bufferDesc.buffer.description.layers),
454             .format = static_cast<uint32_t>(bufferDesc.buffer.description.format),
455             .usage = static_cast<uint64_t>(bufferDesc.buffer.description.usage),
456             .stride = static_cast<uint32_t>(bufferDesc.buffer.description.stride),
457     };
458 
459     AHardwareBuffer* ahwb = nullptr;
460     const auto status =
461             AHardwareBuffer_createFromHandle(&desc, nativeHandle,
462                                              AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
463                                              &ahwb);
464     if (status != android::NO_ERROR) {
465         LOG(ERROR) << "Failed to create a raw hardware buffer from a native handle, "
466                    << "status = " << statusToString(status);
467         std::lock_guard lock(mLock);
468         mStreamHandler->doneWithFrame(bufferDesc.bufferId);
469         return false;
470     }
471 
472     mCallbackThread.enqueue([ahwb, bufferId = bufferDesc.bufferId, this](JNIEnv* env) {
473         jobject hwBuffer;
474         {
475             std::lock_guard lock(mLock);
476             mBufferRecords.insert(bufferId);
477 
478             // Forward AHardwareBuffer to the client
479             hwBuffer = AHardwareBuffer_toHardwareBuffer(env, ahwb);
480             if (!hwBuffer) {
481                 LOG(WARNING) << "Failed to create HardwareBuffer from AHardwareBuffer.";
482                 mStreamHandler->doneWithFrame(bufferId);
483                 AHardwareBuffer_release(ahwb);
484                 return;
485             }
486         }
487 
488         env->CallVoidMethod(mCarEvsServiceObj, mFrameHandlerMethodId, bufferId, hwBuffer);
489         env->DeleteLocalRef(hwBuffer);
490 
491         // We're done
492         AHardwareBuffer_release(ahwb);
493     });
494 
495     return true;
496 }
497 
498 /*
499  * Handles an unexpected death of EVS service.  This method will run in the
500  * context of EvsCallbackThread.
501  */
onEvsServiceDiedImpl()502 void EvsServiceContext::onEvsServiceDiedImpl() {
503     mCallbackThread.enqueue([this](JNIEnv* env) {
504         // Drops invalidated service handles.  We will re-initialize them when
505         // we try to reconnect.  The buffer record would be cleared safely
506         // because all buffer references get invalidated upon the death of the
507         // native EVS service.
508         {
509             std::lock_guard<std::mutex> lock(mLock);
510             mCamera = nullptr;
511             mStreamHandler = nullptr;
512             mBufferRecords.clear();
513             mCameraIdInUse.clear();
514             mLinkUnlinkImpl->unlinkToDeath(mServiceFactory->getService()->asBinder().get());
515             mServiceFactory->clear();
516         }
517 
518         LOG(ERROR) << "The native EVS service has died.";
519         // EVS service has died but CarEvsManager instance still alives.
520         // Only a service handle needs to be destroyed; this will be
521         // re-created when CarEvsManager successfully connects to EVS service
522         // when it comes back.
523         env->CallVoidMethod(mCarEvsServiceObj, mDeathHandlerMethodId);
524     });
525 }
526 
onEvsServiceBinderDied(void * cookie)527 void EvsServiceContext::onEvsServiceBinderDied(void* cookie) {
528     auto thiz = static_cast<EvsServiceContext*>(cookie);
529     if (!thiz) {
530         LOG(WARNING) << "A death of the EVS service is detected but ignored "
531                      << "because of the invalid service context.";
532         return;
533     }
534 
535     thiz->onEvsServiceDiedImpl();
536 }
537 
triggerBinderDied()538 void EvsServiceContext::triggerBinderDied() {
539 #ifdef __TEST__
540     EvsServiceContext::onEvsServiceBinderDied(mLinkUnlinkImpl->getCookie());
541 #endif
542 }
543 
544 }  // namespace android::automotive::evs
545