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