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