1 /*
2 * Copyright (C) 2022 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 "EvsEnumerator.h"
18
19 #include "ConfigManager.h"
20 #include "EvsGlDisplay.h"
21 #include "EvsV4lCamera.h"
22
23 #include <aidl/android/hardware/automotive/evs/DeviceStatusType.h>
24 #include <aidl/android/hardware/automotive/evs/EvsResult.h>
25 #include <aidl/android/hardware/automotive/evs/Rotation.h>
26 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
27 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
28 #include <android-base/file.h>
29 #include <android-base/stringprintf.h>
30 #include <android-base/strings.h>
31 #include <cutils/android_filesystem_config.h>
32 #include <cutils/properties.h>
33
34 #include <dirent.h>
35 #include <sys/inotify.h>
36
37 #include <string_view>
38
39 namespace {
40
41 using ::aidl::android::frameworks::automotive::display::ICarDisplayProxy;
42 using ::aidl::android::hardware::automotive::evs::DeviceStatusType;
43 using ::aidl::android::hardware::automotive::evs::EvsResult;
44 using ::aidl::android::hardware::automotive::evs::Rotation;
45 using ::aidl::android::hardware::graphics::common::BufferUsage;
46 using ::android::base::EqualsIgnoreCase;
47 using ::android::base::StringPrintf;
48 using ::android::base::WriteStringToFd;
49 using ::ndk::ScopedAStatus;
50 using std::chrono_literals::operator""s;
51
52 // Constants
53 constexpr std::chrono::seconds kEnumerationTimeout = 10s;
54 constexpr std::string_view kDevicePath = "/dev/";
55 constexpr std::string_view kPrefix = "video";
56 constexpr size_t kEventBufferSize = 512;
57 constexpr uint64_t kInvalidDisplayId = std::numeric_limits<uint64_t>::max();
58 const std::set<uid_t> kAllowedUids = {AID_AUTOMOTIVE_EVS, AID_SYSTEM, AID_ROOT};
59
60 } // namespace
61
62 namespace aidl::android::hardware::automotive::evs::implementation {
63
64 // NOTE: All members values are static so that all clients operate on the same state
65 // That is to say, this is effectively a singleton despite the fact that HIDL
66 // constructs a new instance for each client.
67 std::unordered_map<std::string, EvsEnumerator::CameraRecord> EvsEnumerator::sCameraList;
68 std::mutex EvsEnumerator::sLock;
69 std::condition_variable EvsEnumerator::sCameraSignal;
70 std::unique_ptr<ConfigManager> EvsEnumerator::sConfigManager;
71 std::shared_ptr<ICarDisplayProxy> EvsEnumerator::sDisplayProxy;
72 std::unordered_map<uint8_t, uint64_t> EvsEnumerator::sDisplayPortList;
73
mutableActiveDisplays()74 EvsEnumerator::ActiveDisplays& EvsEnumerator::mutableActiveDisplays() {
75 static ActiveDisplays active_displays;
76 return active_displays;
77 }
78
EvsHotplugThread(std::shared_ptr<EvsEnumerator> service,std::atomic<bool> & running)79 void EvsEnumerator::EvsHotplugThread(std::shared_ptr<EvsEnumerator> service,
80 std::atomic<bool>& running) {
81 // Watch new video devices
82 if (!service) {
83 LOG(ERROR) << "EvsEnumerator is invalid";
84 return;
85 }
86
87 auto notifyFd = inotify_init();
88 if (notifyFd < 0) {
89 LOG(ERROR) << "Failed to initialize inotify. Exiting a thread loop";
90 return;
91 }
92
93 int watchFd = inotify_add_watch(notifyFd, kDevicePath.data(), IN_CREATE | IN_DELETE);
94 if (watchFd < 0) {
95 LOG(ERROR) << "Failed to add a watch. Exiting a thread loop";
96 return;
97 }
98
99 LOG(INFO) << "Start monitoring new V4L2 devices";
100
101 char eventBuf[kEventBufferSize] = {};
102 while (running) {
103 size_t len = read(notifyFd, eventBuf, sizeof(eventBuf));
104 if (len < sizeof(struct inotify_event)) {
105 // We have no valid event.
106 continue;
107 }
108
109 size_t offset = 0;
110 while (offset < len) {
111 struct inotify_event* event =
112 reinterpret_cast<struct inotify_event*>(&eventBuf[offset]);
113 offset += sizeof(struct inotify_event) + event->len;
114 if (event->wd != watchFd || strncmp(kPrefix.data(), event->name, kPrefix.size())) {
115 continue;
116 }
117
118 std::string deviceName = std::string(kDevicePath) + std::string(event->name);
119 if (event->mask & IN_CREATE) {
120 if (addCaptureDevice(deviceName)) {
121 service->notifyDeviceStatusChange(deviceName,
122 DeviceStatusType::CAMERA_AVAILABLE);
123 }
124 }
125
126 if (event->mask & IN_DELETE) {
127 if (removeCaptureDevice(deviceName)) {
128 service->notifyDeviceStatusChange(deviceName,
129 DeviceStatusType::CAMERA_NOT_AVAILABLE);
130 }
131 }
132 }
133 }
134 }
135
EvsEnumerator(const std::shared_ptr<ICarDisplayProxy> & proxyService)136 EvsEnumerator::EvsEnumerator(const std::shared_ptr<ICarDisplayProxy>& proxyService) {
137 LOG(DEBUG) << "EvsEnumerator is created.";
138
139 if (!sConfigManager) {
140 /* loads and initializes ConfigManager in a separate thread */
141 sConfigManager = ConfigManager::Create();
142 }
143
144 if (!sDisplayProxy) {
145 /* sets a car-window service handle */
146 sDisplayProxy = proxyService;
147 }
148
149 // Enumerate existing devices
150 enumerateCameras();
151 mInternalDisplayId = enumerateDisplays();
152 }
153
checkPermission()154 bool EvsEnumerator::checkPermission() {
155 const auto uid = AIBinder_getCallingUid();
156 if (kAllowedUids.find(uid) == kAllowedUids.end()) {
157 LOG(ERROR) << "EVS access denied: " << "pid = " << AIBinder_getCallingPid()
158 << ", uid = " << uid;
159 return false;
160 }
161
162 return true;
163 }
164
addCaptureDevice(const std::string & deviceName)165 bool EvsEnumerator::addCaptureDevice(const std::string& deviceName) {
166 if (!qualifyCaptureDevice(deviceName.data())) {
167 LOG(DEBUG) << deviceName << " is not qualified for this EVS HAL implementation";
168 return false;
169 }
170
171 CameraRecord cam(deviceName.data());
172 if (sConfigManager) {
173 std::unique_ptr<ConfigManager::CameraInfo>& camInfo =
174 sConfigManager->getCameraInfo(deviceName);
175 if (camInfo) {
176 uint8_t* ptr = reinterpret_cast<uint8_t*>(camInfo->characteristics);
177 const size_t len = get_camera_metadata_size(camInfo->characteristics);
178 cam.desc.metadata.insert(cam.desc.metadata.end(), ptr, ptr + len);
179 }
180 }
181
182 {
183 std::lock_guard lock(sLock);
184 // insert_or_assign() returns std::pair<std::unordered_map<>, bool>
185 auto result = sCameraList.insert_or_assign(deviceName, std::move(cam));
186 LOG(INFO) << deviceName << (std::get<1>(result) ? " is added" : " is modified");
187 }
188
189 return true;
190 }
191
removeCaptureDevice(const std::string & deviceName)192 bool EvsEnumerator::removeCaptureDevice(const std::string& deviceName) {
193 std::lock_guard lock(sLock);
194 if (sCameraList.erase(deviceName) != 0) {
195 LOG(INFO) << deviceName << " is removed";
196 return true;
197 }
198
199 return false;
200 }
201
enumerateCameras()202 void EvsEnumerator::enumerateCameras() {
203 // For every video* entry in the dev folder, see if it reports suitable capabilities
204 // WARNING: Depending on the driver implementations this could be slow, especially if
205 // there are timeouts or round trips to hardware required to collect the needed
206 // information. Platform implementers should consider hard coding this list of
207 // known good devices to speed up the startup time of their EVS implementation.
208 // For example, this code might be replaced with nothing more than:
209 // sCameraList.insert("/dev/video0");
210 // sCameraList.insert("/dev/video1");
211 LOG(INFO) << __FUNCTION__ << ": Starting dev/video* enumeration";
212 auto videoCount = 0;
213 auto captureCount = 0;
214 DIR* dir = opendir("/dev");
215 if (!dir) {
216 LOG_FATAL("Failed to open /dev folder\n");
217 }
218 struct dirent* entry;
219 while ((entry = readdir(dir)) != nullptr) {
220 // We're only looking for entries starting with 'video'
221 if (strncmp(entry->d_name, "video", 5) == 0) {
222 std::string deviceName("/dev/");
223 deviceName += entry->d_name;
224 ++videoCount;
225
226 if (addCaptureDevice(deviceName)) {
227 ++captureCount;
228 }
229 }
230 }
231
232 LOG(INFO) << "Found " << captureCount << " qualified video capture devices " << "of "
233 << videoCount << " checked.";
234 }
235
enumerateDisplays()236 uint64_t EvsEnumerator::enumerateDisplays() {
237 LOG(INFO) << __FUNCTION__ << ": Starting display enumeration";
238 uint64_t internalDisplayId = kInvalidDisplayId;
239 if (!sDisplayProxy) {
240 LOG(ERROR) << "ICarDisplayProxy is not available!";
241 return internalDisplayId;
242 }
243
244 std::vector<int64_t> displayIds;
245 if (auto status = sDisplayProxy->getDisplayIdList(&displayIds); !status.isOk()) {
246 LOG(ERROR) << "Failed to retrieve a display id list"
247 << ::android::statusToString(status.getStatus());
248 return internalDisplayId;
249 }
250
251 if (displayIds.size() > 0) {
252 // The first entry of the list is the internal display. See
253 // SurfaceFlinger::getPhysicalDisplayIds() implementation.
254 internalDisplayId = displayIds[0];
255 for (const auto& id : displayIds) {
256 const auto port = id & 0xFF;
257 LOG(INFO) << "Display " << std::hex << id << " is detected on the port, " << port;
258 sDisplayPortList.insert_or_assign(port, id);
259 }
260 }
261
262 LOG(INFO) << "Found " << sDisplayPortList.size() << " displays";
263 return internalDisplayId;
264 }
265
266 // Methods from ::android::hardware::automotive::evs::IEvsEnumerator follow.
getCameraList(std::vector<CameraDesc> * _aidl_return)267 ScopedAStatus EvsEnumerator::getCameraList(std::vector<CameraDesc>* _aidl_return) {
268 LOG(DEBUG) << __FUNCTION__;
269 if (!checkPermission()) {
270 return ScopedAStatus::fromServiceSpecificError(
271 static_cast<int>(EvsResult::PERMISSION_DENIED));
272 }
273
274 {
275 std::unique_lock<std::mutex> lock(sLock);
276 if (sCameraList.size() < 1) {
277 // No qualified device has been found. Wait until new device is ready,
278 // for 10 seconds.
279 if (!sCameraSignal.wait_for(lock, kEnumerationTimeout,
280 [] { return sCameraList.size() > 0; })) {
281 LOG(DEBUG) << "Timer expired. No new device has been added.";
282 }
283 }
284 }
285
286 // Build up a packed array of CameraDesc for return
287 _aidl_return->resize(sCameraList.size());
288 unsigned i = 0;
289 for (const auto& [key, cam] : sCameraList) {
290 (*_aidl_return)[i++] = cam.desc;
291 }
292
293 if (sConfigManager) {
294 // Adding camera groups that represent logical camera devices
295 auto camGroups = sConfigManager->getCameraGroupIdList();
296 for (auto&& id : camGroups) {
297 if (sCameraList.find(id) != sCameraList.end()) {
298 // Already exists in the _aidl_return
299 continue;
300 }
301
302 std::unique_ptr<ConfigManager::CameraGroupInfo>& tempInfo =
303 sConfigManager->getCameraGroupInfo(id);
304 CameraRecord cam(id.data());
305 if (tempInfo) {
306 uint8_t* ptr = reinterpret_cast<uint8_t*>(tempInfo->characteristics);
307 const size_t len = get_camera_metadata_size(tempInfo->characteristics);
308 cam.desc.metadata.insert(cam.desc.metadata.end(), ptr, ptr + len);
309 }
310
311 sCameraList.insert_or_assign(id, cam);
312 _aidl_return->push_back(cam.desc);
313 }
314 }
315
316 // Send back the results
317 LOG(DEBUG) << "Reporting " << sCameraList.size() << " cameras available";
318 return ScopedAStatus::ok();
319 }
320
getStreamList(const CameraDesc & desc,std::vector<Stream> * _aidl_return)321 ScopedAStatus EvsEnumerator::getStreamList(const CameraDesc& desc,
322 std::vector<Stream>* _aidl_return) {
323 using AidlPixelFormat = ::aidl::android::hardware::graphics::common::PixelFormat;
324
325 camera_metadata_t* pMetadata = const_cast<camera_metadata_t*>(
326 reinterpret_cast<const camera_metadata_t*>(desc.metadata.data()));
327 camera_metadata_entry_t streamConfig;
328 if (!find_camera_metadata_entry(pMetadata, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
329 &streamConfig)) {
330 const unsigned numStreamConfigs = streamConfig.count / sizeof(StreamConfiguration);
331 _aidl_return->resize(numStreamConfigs);
332 const StreamConfiguration* pCurrentConfig =
333 reinterpret_cast<StreamConfiguration*>(streamConfig.data.i32);
334 for (unsigned i = 0; i < numStreamConfigs; ++i, ++pCurrentConfig) {
335 // Build ::aidl::android::hardware::automotive::evs::Stream from
336 // StreamConfiguration.
337 Stream current = {
338 .id = pCurrentConfig->id,
339 .streamType = pCurrentConfig->type ==
340 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT
341 ? StreamType::INPUT
342 : StreamType::OUTPUT,
343 .width = pCurrentConfig->width,
344 .height = pCurrentConfig->height,
345 .format = static_cast<AidlPixelFormat>(pCurrentConfig->format),
346 .usage = BufferUsage::CAMERA_INPUT,
347 .rotation = Rotation::ROTATION_0,
348 };
349
350 (*_aidl_return)[i] = std::move(current);
351 }
352 }
353
354 return ScopedAStatus::ok();
355 }
356
openCamera(const std::string & id,const Stream & cfg,std::shared_ptr<IEvsCamera> * obj)357 ScopedAStatus EvsEnumerator::openCamera(const std::string& id, const Stream& cfg,
358 std::shared_ptr<IEvsCamera>* obj) {
359 LOG(DEBUG) << __FUNCTION__;
360 if (!checkPermission()) {
361 return ScopedAStatus::fromServiceSpecificError(
362 static_cast<int>(EvsResult::PERMISSION_DENIED));
363 }
364
365 // Is this a recognized camera id?
366 CameraRecord* pRecord = findCameraById(id);
367 if (!pRecord) {
368 LOG(ERROR) << id << " does not exist!";
369 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
370 }
371
372 // Has this camera already been instantiated by another caller?
373 std::shared_ptr<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.lock();
374 if (pActiveCamera) {
375 LOG(WARNING) << "Killing previous camera because of new caller";
376 closeCamera(pActiveCamera);
377 }
378
379 // Construct a camera instance for the caller
380 if (!sConfigManager) {
381 pActiveCamera = EvsV4lCamera::Create(id.data());
382 } else {
383 pActiveCamera = EvsV4lCamera::Create(id.data(), sConfigManager->getCameraInfo(id), &cfg);
384 }
385
386 pRecord->activeInstance = pActiveCamera;
387 if (!pActiveCamera) {
388 LOG(ERROR) << "Failed to create new EvsV4lCamera object for " << id;
389 return ScopedAStatus::fromServiceSpecificError(
390 static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR));
391 }
392
393 *obj = pActiveCamera;
394 return ScopedAStatus::ok();
395 }
396
closeCamera(const std::shared_ptr<IEvsCamera> & cameraObj)397 ScopedAStatus EvsEnumerator::closeCamera(const std::shared_ptr<IEvsCamera>& cameraObj) {
398 LOG(DEBUG) << __FUNCTION__;
399
400 if (!cameraObj) {
401 LOG(ERROR) << "Ignoring call to closeCamera with null camera ptr";
402 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
403 }
404
405 // Get the camera id so we can find it in our list
406 CameraDesc desc;
407 auto status = cameraObj->getCameraInfo(&desc);
408 if (!status.isOk()) {
409 LOG(ERROR) << "Failed to read a camera descriptor";
410 return ScopedAStatus::fromServiceSpecificError(
411 static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR));
412 }
413 auto cameraId = desc.id;
414 closeCamera_impl(cameraObj, cameraId);
415 return ScopedAStatus::ok();
416 }
417
openDisplay(int32_t id,std::shared_ptr<IEvsDisplay> * displayObj)418 ScopedAStatus EvsEnumerator::openDisplay(int32_t id, std::shared_ptr<IEvsDisplay>* displayObj) {
419 LOG(DEBUG) << __FUNCTION__;
420 if (!checkPermission()) {
421 return ScopedAStatus::fromServiceSpecificError(
422 static_cast<int>(EvsResult::PERMISSION_DENIED));
423 }
424
425 auto& displays = mutableActiveDisplays();
426
427 if (auto existing_display_search = displays.popDisplay(id)) {
428 // If we already have a display active, then we need to shut it down so we can
429 // give exclusive access to the new caller.
430 std::shared_ptr<EvsGlDisplay> pActiveDisplay = existing_display_search->displayWeak.lock();
431 if (pActiveDisplay) {
432 LOG(WARNING) << "Killing previous display because of new caller";
433 pActiveDisplay->forceShutdown();
434 }
435 }
436
437 // Create a new display interface and return it
438 uint64_t targetDisplayId = mInternalDisplayId;
439 auto it = sDisplayPortList.find(id);
440 if (it != sDisplayPortList.end()) {
441 targetDisplayId = it->second;
442 } else {
443 LOG(WARNING) << "No display is available on the port " << static_cast<int32_t>(id)
444 << ". The main display " << mInternalDisplayId << " will be used instead";
445 }
446
447 // Create a new display interface and return it.
448 std::shared_ptr<EvsGlDisplay> pActiveDisplay =
449 ndk::SharedRefBase::make<EvsGlDisplay>(sDisplayProxy, targetDisplayId);
450
451 if (auto insert_result = displays.tryInsert(id, pActiveDisplay); !insert_result) {
452 LOG(ERROR) << "Display ID " << id << " has been used by another caller.";
453 pActiveDisplay->forceShutdown();
454 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::RESOURCE_BUSY));
455 }
456
457 LOG(DEBUG) << "Returning new EvsGlDisplay object " << pActiveDisplay.get();
458 *displayObj = pActiveDisplay;
459 return ScopedAStatus::ok();
460 }
461
closeDisplay(const std::shared_ptr<IEvsDisplay> & obj)462 ScopedAStatus EvsEnumerator::closeDisplay(const std::shared_ptr<IEvsDisplay>& obj) {
463 LOG(DEBUG) << __FUNCTION__;
464
465 auto& displays = mutableActiveDisplays();
466 const auto display_search = displays.popDisplay(obj);
467
468 if (!display_search) {
469 LOG(WARNING) << "Ignoring close of previously orphaned display - why did a client steal?";
470 return ScopedAStatus::ok();
471 }
472
473 auto pActiveDisplay = display_search->displayWeak.lock();
474
475 if (!pActiveDisplay) {
476 LOG(ERROR) << "Somehow a display is being destroyed "
477 << "when the enumerator didn't know one existed";
478 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
479 }
480
481 pActiveDisplay->forceShutdown();
482 return ScopedAStatus::ok();
483 }
484
getDisplayState(DisplayState * state)485 ScopedAStatus EvsEnumerator::getDisplayState(DisplayState* state) {
486 LOG(DEBUG) << __FUNCTION__;
487 return getDisplayStateImpl(std::nullopt, state);
488 }
489
getDisplayStateById(int32_t displayId,DisplayState * state)490 ScopedAStatus EvsEnumerator::getDisplayStateById(int32_t displayId, DisplayState* state) {
491 LOG(DEBUG) << __FUNCTION__;
492 return getDisplayStateImpl(displayId, state);
493 }
494
getDisplayStateImpl(std::optional<int32_t> displayId,DisplayState * state)495 ScopedAStatus EvsEnumerator::getDisplayStateImpl(std::optional<int32_t> displayId,
496 DisplayState* state) {
497 if (!checkPermission()) {
498 *state = DisplayState::DEAD;
499 return ScopedAStatus::fromServiceSpecificError(
500 static_cast<int>(EvsResult::PERMISSION_DENIED));
501 }
502
503 const auto& all_displays = mutableActiveDisplays().getAllDisplays();
504
505 const auto display_search = displayId ? all_displays.find(*displayId) : all_displays.begin();
506
507 if (display_search == all_displays.end()) {
508 *state = DisplayState::NOT_OPEN;
509 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
510 }
511
512 std::shared_ptr<IEvsDisplay> pActiveDisplay = display_search->second.displayWeak.lock();
513 if (pActiveDisplay) {
514 return pActiveDisplay->getDisplayState(state);
515 } else {
516 *state = DisplayState::NOT_OPEN;
517 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
518 }
519 }
520
getDisplayIdList(std::vector<uint8_t> * list)521 ScopedAStatus EvsEnumerator::getDisplayIdList(std::vector<uint8_t>* list) {
522 std::vector<uint8_t>& output = *list;
523 if (sDisplayPortList.size() > 0) {
524 output.resize(sDisplayPortList.size());
525 unsigned i = 0;
526 output[i++] = mInternalDisplayId & 0xFF;
527 for (const auto& [port, id] : sDisplayPortList) {
528 if (mInternalDisplayId != id) {
529 output[i++] = port;
530 }
531 }
532 }
533
534 return ScopedAStatus::ok();
535 }
536
isHardware(bool * flag)537 ScopedAStatus EvsEnumerator::isHardware(bool* flag) {
538 *flag = true;
539 return ScopedAStatus::ok();
540 }
541
notifyDeviceStatusChange(const std::string_view & deviceName,DeviceStatusType type)542 void EvsEnumerator::notifyDeviceStatusChange(const std::string_view& deviceName,
543 DeviceStatusType type) {
544 std::lock_guard lock(sLock);
545 if (!mCallback) {
546 return;
547 }
548
549 std::vector<DeviceStatus> status{{.id = std::string(deviceName), .status = type}};
550 if (!mCallback->deviceStatusChanged(status).isOk()) {
551 LOG(WARNING) << "Failed to notify a device status change, name = " << deviceName
552 << ", type = " << static_cast<int>(type);
553 }
554 }
555
registerStatusCallback(const std::shared_ptr<IEvsEnumeratorStatusCallback> & callback)556 ScopedAStatus EvsEnumerator::registerStatusCallback(
557 const std::shared_ptr<IEvsEnumeratorStatusCallback>& callback) {
558 std::lock_guard lock(sLock);
559 if (mCallback) {
560 LOG(INFO) << "Replacing an existing device status callback";
561 }
562 mCallback = callback;
563 return ScopedAStatus::ok();
564 }
565
closeCamera_impl(const std::shared_ptr<IEvsCamera> & pCamera,const std::string & cameraId)566 void EvsEnumerator::closeCamera_impl(const std::shared_ptr<IEvsCamera>& pCamera,
567 const std::string& cameraId) {
568 // Find the named camera
569 CameraRecord* pRecord = findCameraById(cameraId);
570
571 // Is the display being destroyed actually the one we think is active?
572 if (!pRecord) {
573 LOG(ERROR) << "Asked to close a camera whose name isn't recognized";
574 } else {
575 std::shared_ptr<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.lock();
576 if (!pActiveCamera) {
577 LOG(WARNING) << "Somehow a camera is being destroyed "
578 << "when the enumerator didn't know one existed";
579 } else if (pActiveCamera != pCamera) {
580 // This can happen if the camera was aggressively reopened,
581 // orphaning this previous instance
582 LOG(WARNING) << "Ignoring close of previously orphaned camera "
583 << "- why did a client steal?";
584 } else {
585 // Shutdown the active camera
586 pActiveCamera->shutdown();
587 }
588 }
589
590 return;
591 }
592
qualifyCaptureDevice(const char * deviceName)593 bool EvsEnumerator::qualifyCaptureDevice(const char* deviceName) {
594 class FileHandleWrapper {
595 public:
596 FileHandleWrapper(int fd) { mFd = fd; }
597 ~FileHandleWrapper() {
598 if (mFd > 0) close(mFd);
599 }
600 operator int() const { return mFd; }
601
602 private:
603 int mFd = -1;
604 };
605
606 FileHandleWrapper fd = open(deviceName, O_RDWR, 0);
607 if (fd < 0) {
608 return false;
609 }
610
611 v4l2_capability caps;
612 int result = ioctl(fd, VIDIOC_QUERYCAP, &caps);
613 if (result < 0) {
614 return false;
615 }
616 if (((caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) ||
617 ((caps.capabilities & V4L2_CAP_STREAMING) == 0)) {
618 return false;
619 }
620
621 // Enumerate the available capture formats (if any)
622 v4l2_fmtdesc formatDescription;
623 formatDescription.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
624 bool found = false;
625 for (int i = 0; !found; ++i) {
626 formatDescription.index = i;
627 if (ioctl(fd, VIDIOC_ENUM_FMT, &formatDescription) == 0) {
628 LOG(DEBUG) << "Format: 0x" << std::hex << formatDescription.pixelformat << " Type: 0x"
629 << std::hex << formatDescription.type
630 << " Desc: " << formatDescription.description << " Flags: 0x" << std::hex
631 << formatDescription.flags;
632 switch (formatDescription.pixelformat) {
633 case V4L2_PIX_FMT_YUYV:
634 found = true;
635 break;
636 case V4L2_PIX_FMT_NV21:
637 found = true;
638 break;
639 case V4L2_PIX_FMT_NV16:
640 found = true;
641 break;
642 case V4L2_PIX_FMT_YVU420:
643 found = true;
644 break;
645 case V4L2_PIX_FMT_RGB32:
646 found = true;
647 break;
648 #ifdef V4L2_PIX_FMT_ARGB32 // introduced with kernel v3.17
649 case V4L2_PIX_FMT_ARGB32:
650 found = true;
651 break;
652 case V4L2_PIX_FMT_XRGB32:
653 found = true;
654 break;
655 #endif // V4L2_PIX_FMT_ARGB32
656 default:
657 LOG(WARNING) << "Unsupported, " << std::hex << formatDescription.pixelformat;
658 break;
659 }
660 } else {
661 // No more formats available.
662 break;
663 }
664 }
665
666 return found;
667 }
668
findCameraById(const std::string & cameraId)669 EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) {
670 // Find the named camera
671 auto found = sCameraList.find(cameraId);
672 if (found != sCameraList.end()) {
673 // Found a match!
674 return &found->second;
675 }
676
677 // We didn't find a match
678 return nullptr;
679 }
680
popDisplay(int32_t id)681 std::optional<EvsEnumerator::ActiveDisplays::DisplayInfo> EvsEnumerator::ActiveDisplays::popDisplay(
682 int32_t id) {
683 std::lock_guard lck(mMutex);
684 const auto search = mIdToDisplay.find(id);
685 if (search == mIdToDisplay.end()) {
686 return std::nullopt;
687 }
688 const auto display_info = search->second;
689 mIdToDisplay.erase(search);
690 mDisplayToId.erase(display_info.internalDisplayRawAddr);
691 return display_info;
692 }
693
popDisplay(std::shared_ptr<IEvsDisplay> display)694 std::optional<EvsEnumerator::ActiveDisplays::DisplayInfo> EvsEnumerator::ActiveDisplays::popDisplay(
695 std::shared_ptr<IEvsDisplay> display) {
696 const auto display_ptr_val = reinterpret_cast<uintptr_t>(display.get());
697 std::lock_guard lck(mMutex);
698 const auto display_to_id_search = mDisplayToId.find(display_ptr_val);
699 if (display_to_id_search == mDisplayToId.end()) {
700 LOG(ERROR) << "Unknown display.";
701 return std::nullopt;
702 }
703 const auto id = display_to_id_search->second;
704 const auto id_to_display_search = mIdToDisplay.find(id);
705 mDisplayToId.erase(display_to_id_search);
706 if (id_to_display_search == mIdToDisplay.end()) {
707 LOG(ERROR) << "No correspsonding ID for the display, probably orphaned.";
708 return std::nullopt;
709 }
710 const auto display_info = id_to_display_search->second;
711 mIdToDisplay.erase(id);
712 return display_info;
713 }
714
715 std::unordered_map<int32_t, EvsEnumerator::ActiveDisplays::DisplayInfo>
getAllDisplays()716 EvsEnumerator::ActiveDisplays::getAllDisplays() {
717 std::lock_guard lck(mMutex);
718 const auto id_to_display_map_copy = mIdToDisplay;
719 return id_to_display_map_copy;
720 }
721
tryInsert(int32_t id,std::shared_ptr<EvsGlDisplay> display)722 bool EvsEnumerator::ActiveDisplays::tryInsert(int32_t id, std::shared_ptr<EvsGlDisplay> display) {
723 std::lock_guard lck(mMutex);
724 const auto display_ptr_val = reinterpret_cast<uintptr_t>(display.get());
725
726 auto id_to_display_insert_result =
727 mIdToDisplay.emplace(id,
728 DisplayInfo{
729 .id = id,
730 .displayWeak = display,
731 .internalDisplayRawAddr = display_ptr_val,
732 });
733 if (!id_to_display_insert_result.second) {
734 return false;
735 }
736 auto display_to_id_insert_result = mDisplayToId.emplace(display_ptr_val, id);
737 if (!display_to_id_insert_result.second) {
738 mIdToDisplay.erase(id);
739 return false;
740 }
741 return true;
742 }
743
getUltrasonicsArrayList(std::vector<UltrasonicsArrayDesc> * list)744 ScopedAStatus EvsEnumerator::getUltrasonicsArrayList(
745 [[maybe_unused]] std::vector<UltrasonicsArrayDesc>* list) {
746 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
747 return ScopedAStatus::ok();
748 }
749
openUltrasonicsArray(const std::string & id,std::shared_ptr<IEvsUltrasonicsArray> * obj)750 ScopedAStatus EvsEnumerator::openUltrasonicsArray(
751 [[maybe_unused]] const std::string& id,
752 [[maybe_unused]] std::shared_ptr<IEvsUltrasonicsArray>* obj) {
753 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
754 return ScopedAStatus::ok();
755 }
756
closeUltrasonicsArray(const std::shared_ptr<IEvsUltrasonicsArray> & obj)757 ScopedAStatus EvsEnumerator::closeUltrasonicsArray(
758 [[maybe_unused]] const std::shared_ptr<IEvsUltrasonicsArray>& obj) {
759 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
760 return ScopedAStatus::ok();
761 }
762
dump(int fd,const char ** args,uint32_t numArgs)763 binder_status_t EvsEnumerator::dump(int fd, const char** args, uint32_t numArgs) {
764 std::vector<std::string> options(args, args + numArgs);
765 return parseCommand(fd, options);
766 }
767
parseCommand(int fd,const std::vector<std::string> & options)768 binder_status_t EvsEnumerator::parseCommand(int fd, const std::vector<std::string>& options) {
769 if (options.size() < 1) {
770 WriteStringToFd("No option is given.\n", fd);
771 cmdHelp(fd);
772 return STATUS_BAD_VALUE;
773 }
774
775 const std::string command = options[0];
776 if (EqualsIgnoreCase(command, "--help")) {
777 cmdHelp(fd);
778 return STATUS_OK;
779 } else if (EqualsIgnoreCase(command, "--dump")) {
780 return cmdDump(fd, options);
781 } else {
782 WriteStringToFd(StringPrintf("Invalid option: %s\n", command.data()), fd);
783 return STATUS_INVALID_OPERATION;
784 }
785 }
786
cmdHelp(int fd)787 void EvsEnumerator::cmdHelp(int fd) {
788 WriteStringToFd("--help: shows this help.\n"
789 "--dump [id] [start|stop] [directory]\n"
790 "\tDump camera frames to a target directory\n",
791 fd);
792 }
793
cmdDump(int fd,const std::vector<std::string> & options)794 binder_status_t EvsEnumerator::cmdDump(int fd, const std::vector<std::string>& options) {
795 if (options.size() < 3) {
796 WriteStringToFd("Necessary argument is missing\n", fd);
797 cmdHelp(fd);
798 return STATUS_BAD_VALUE;
799 }
800
801 EvsEnumerator::CameraRecord* pRecord = findCameraById(options[1]);
802 if (pRecord == nullptr) {
803 WriteStringToFd(StringPrintf("%s is not active\n", options[1].data()), fd);
804 return STATUS_BAD_VALUE;
805 }
806
807 auto device = pRecord->activeInstance.lock();
808 if (device == nullptr) {
809 WriteStringToFd(StringPrintf("%s seems dead\n", options[1].data()), fd);
810 return STATUS_DEAD_OBJECT;
811 }
812
813 const std::string command = options[2];
814 if (EqualsIgnoreCase(command, "start")) {
815 // --dump [device id] start [path]
816 if (options.size() < 4) {
817 WriteStringToFd("Necessary argument is missing\n", fd);
818 cmdHelp(fd);
819 return STATUS_BAD_VALUE;
820 }
821
822 const std::string path = options[3];
823 auto ret = device->startDumpFrames(path);
824 if (!ret.ok()) {
825 WriteStringToFd(StringPrintf("Failed to start storing frames: %s\n",
826 ret.error().message().data()),
827 fd);
828 return STATUS_FAILED_TRANSACTION;
829 }
830 } else if (EqualsIgnoreCase(command, "stop")) {
831 // --dump [device id] stop
832 auto ret = device->stopDumpFrames();
833 if (!ret.ok()) {
834 WriteStringToFd(StringPrintf("Failed to stop storing frames: %s\n",
835 ret.error().message().data()),
836 fd);
837 return STATUS_FAILED_TRANSACTION;
838 }
839 } else {
840 WriteStringToFd(StringPrintf("Unknown command: %s", command.data()), fd);
841 cmdHelp(fd);
842 }
843
844 return STATUS_OK;
845 }
846
847 } // namespace aidl::android::hardware::automotive::evs::implementation
848