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