1 /*
2  * Copyright (C) 2016 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 #include "EvsV4lCamera.h"
19 #include "EvsGlDisplay.h"
20 #include "ConfigManager.h"
21 
22 #include <dirent.h>
23 #include <hardware_legacy/uevent.h>
24 #include <hwbinder/IPCThreadState.h>
25 #include <cutils/android_filesystem_config.h>
26 
27 
28 using namespace std::chrono_literals;
29 using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
30 using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
31 
32 namespace android {
33 namespace hardware {
34 namespace automotive {
35 namespace evs {
36 namespace V1_1 {
37 namespace implementation {
38 
39 
40 // NOTE:  All members values are static so that all clients operate on the same state
41 //        That is to say, this is effectively a singleton despite the fact that HIDL
42 //        constructs a new instance for each client.
43 std::unordered_map<std::string, EvsEnumerator::CameraRecord> EvsEnumerator::sCameraList;
44 wp<EvsGlDisplay>                                             EvsEnumerator::sActiveDisplay;
45 std::mutex                                                   EvsEnumerator::sLock;
46 std::condition_variable                                      EvsEnumerator::sCameraSignal;
47 std::unique_ptr<ConfigManager>                               EvsEnumerator::sConfigManager;
48 sp<IAutomotiveDisplayProxyService>                           EvsEnumerator::sDisplayProxy;
49 std::unordered_map<uint8_t, uint64_t>                        EvsEnumerator::sDisplayPortList;
50 uint64_t                                                     EvsEnumerator::sInternalDisplayId;
51 
52 
53 // Constants
54 const auto kEnumerationTimeout = 10s;
55 
56 
checkPermission()57 bool EvsEnumerator::checkPermission() {
58     hardware::IPCThreadState *ipc = hardware::IPCThreadState::self();
59     if (AID_AUTOMOTIVE_EVS != ipc->getCallingUid() &&
60         AID_ROOT != ipc->getCallingUid()) {
61         LOG(ERROR) << "EVS access denied: "
62                    << "pid = " << ipc->getCallingPid()
63                    << ", uid = " << ipc->getCallingUid();
64         return false;
65     }
66 
67     return true;
68 }
69 
EvsUeventThread(std::atomic<bool> & running)70 void EvsEnumerator::EvsUeventThread(std::atomic<bool>& running) {
71     int status = uevent_init();
72     if (!status) {
73         LOG(ERROR) << "Failed to initialize uevent handler.";
74         return;
75     }
76 
77     char uevent_data[PAGE_SIZE - 2] = {};
78     while (running) {
79         int length = uevent_next_event(uevent_data, static_cast<int32_t>(sizeof(uevent_data)));
80 
81         // Ensure double-null termination.
82         uevent_data[length] = uevent_data[length + 1] = '\0';
83 
84         const char *action = nullptr;
85         const char *devname = nullptr;
86         const char *subsys = nullptr;
87         char *cp = uevent_data;
88         while (*cp) {
89             // EVS is interested only in ACTION, SUBSYSTEM, and DEVNAME.
90             if (!std::strncmp(cp, "ACTION=", 7)) {
91                 action = cp + 7;
92             } else if (!std::strncmp(cp, "SUBSYSTEM=", 10)) {
93                 subsys = cp + 10;
94             } else if (!std::strncmp(cp, "DEVNAME=", 8)) {
95                 devname = cp + 8;
96             }
97 
98             // Advance to after next \0
99             while (*cp++);
100         }
101 
102         if (!devname || !subsys || std::strcmp(subsys, "video4linux")) {
103             // EVS expects that the subsystem of enabled video devices is
104             // video4linux.
105             continue;
106         }
107 
108         // Update shared list.
109         bool cmd_addition = !std::strcmp(action, "add");
110         bool cmd_removal  = !std::strcmp(action, "remove");
111         {
112             std::string devpath = "/dev/";
113             devpath += devname;
114 
115             std::lock_guard<std::mutex> lock(sLock);
116             if (cmd_removal) {
117                 sCameraList.erase(devpath);
118                 LOG(INFO) << devpath << " is removed.";
119             } else if (cmd_addition) {
120                 // NOTE: we are here adding new device without a validation
121                 // because it always fails to open, b/132164956.
122                 CameraRecord cam(devpath.c_str());
123                 if (sConfigManager != nullptr) {
124                     unique_ptr<ConfigManager::CameraInfo> &camInfo =
125                         sConfigManager->getCameraInfo(devpath);
126                     if (camInfo != nullptr) {
127                         cam.desc.metadata.setToExternal(
128                             (uint8_t *)camInfo->characteristics,
129                              get_camera_metadata_size(camInfo->characteristics)
130                         );
131                     }
132                 }
133                 sCameraList.emplace(devpath, cam);
134                 LOG(INFO) << devpath << " is added.";
135             } else {
136                 // Ignore all other actions including "change".
137             }
138 
139             // Notify the change.
140             sCameraSignal.notify_all();
141         }
142     }
143 
144     return;
145 }
146 
EvsEnumerator(sp<IAutomotiveDisplayProxyService> proxyService)147 EvsEnumerator::EvsEnumerator(sp<IAutomotiveDisplayProxyService> proxyService) {
148     LOG(DEBUG) << "EvsEnumerator is created.";
149 
150     if (sConfigManager == nullptr) {
151         /* loads and initializes ConfigManager in a separate thread */
152         sConfigManager =
153             ConfigManager::Create("/vendor/etc/automotive/evs/evs_sample_configuration.xml");
154     }
155 
156     if (sDisplayProxy == nullptr) {
157         /* sets a car-window service handle */
158         sDisplayProxy = proxyService;
159     }
160 
161     enumerateCameras();
162     enumerateDisplays();
163 }
164 
enumerateCameras()165 void EvsEnumerator::enumerateCameras() {
166     // For every video* entry in the dev folder, see if it reports suitable capabilities
167     // WARNING:  Depending on the driver implementations this could be slow, especially if
168     //           there are timeouts or round trips to hardware required to collect the needed
169     //           information.  Platform implementers should consider hard coding this list of
170     //           known good devices to speed up the startup time of their EVS implementation.
171     //           For example, this code might be replaced with nothing more than:
172     //                   sCameraList.emplace("/dev/video0");
173     //                   sCameraList.emplace("/dev/video1");
174     LOG(INFO) << __FUNCTION__
175               << ": Starting dev/video* enumeration";
176     unsigned videoCount   = 0;
177     unsigned captureCount = 0;
178     DIR* dir = opendir("/dev");
179     if (!dir) {
180         LOG_FATAL("Failed to open /dev folder\n");
181     }
182     struct dirent* entry;
183     {
184         std::lock_guard<std::mutex> lock(sLock);
185 
186         while ((entry = readdir(dir)) != nullptr) {
187             // We're only looking for entries starting with 'video'
188             if (strncmp(entry->d_name, "video", 5) == 0) {
189                 std::string deviceName("/dev/");
190                 deviceName += entry->d_name;
191                 videoCount++;
192                 if (sCameraList.find(deviceName) != sCameraList.end()) {
193                     LOG(INFO) << deviceName << " has been added already.";
194                     captureCount++;
195                 } else if(qualifyCaptureDevice(deviceName.c_str())) {
196                     sCameraList.emplace(deviceName, deviceName.c_str());
197                     captureCount++;
198                 }
199             }
200         }
201     }
202 
203     LOG(INFO) << "Found " << captureCount << " qualified video capture devices "
204               << "of " << videoCount << " checked.";
205 }
206 
207 
enumerateDisplays()208 void EvsEnumerator::enumerateDisplays() {
209     LOG(INFO) << __FUNCTION__
210               << ": Starting display enumeration";
211     if (!sDisplayProxy) {
212         LOG(ERROR) << "AutomotiveDisplayProxyService is not available!";
213         return;
214     }
215 
216     sDisplayProxy->getDisplayIdList(
217         [](const auto& displayIds) {
218             // The first entry of the list is the internal display.  See
219             // SurfaceFlinger::getPhysicalDisplayIds() implementation.
220             if (displayIds.size() > 0) {
221                 sInternalDisplayId = displayIds[0];
222                 for (const auto& id : displayIds) {
223                     const auto port = id & 0xF;
224                     LOG(INFO) << "Display " << std::hex << id
225                               << " is detected on the port, " << port;
226                     sDisplayPortList.insert_or_assign(port, id);
227                 }
228             }
229         }
230     );
231 
232     LOG(INFO) << "Found " << sDisplayPortList.size() << " displays";
233 }
234 
235 
236 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
getCameraList(getCameraList_cb _hidl_cb)237 Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb)  {
238     LOG(DEBUG) << __FUNCTION__;
239     if (!checkPermission()) {
240         return Void();
241     }
242 
243     {
244         std::unique_lock<std::mutex> lock(sLock);
245         if (sCameraList.size() < 1) {
246             // No qualified device has been found.  Wait until new device is ready,
247             // for 10 seconds.
248             if (!sCameraSignal.wait_for(lock,
249                                         kEnumerationTimeout,
250                                         []{ return sCameraList.size() > 0; })) {
251                 LOG(DEBUG) << "Timer expired.  No new device has been added.";
252             }
253         }
254     }
255 
256     const unsigned numCameras = sCameraList.size();
257 
258     // Build up a packed array of CameraDesc for return
259     hidl_vec<CameraDesc_1_0> hidlCameras;
260     hidlCameras.resize(numCameras);
261     unsigned i = 0;
262     for (const auto& [key, cam] : sCameraList) {
263         hidlCameras[i++] = cam.desc.v1;
264     }
265 
266     // Send back the results
267     LOG(DEBUG) << "Reporting " << hidlCameras.size() << " cameras available";
268     _hidl_cb(hidlCameras);
269 
270     // HIDL convention says we return Void if we sent our result back via callback
271     return Void();
272 }
273 
274 
openCamera(const hidl_string & cameraId)275 Return<sp<IEvsCamera_1_0>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
276     LOG(DEBUG) << __FUNCTION__;
277     if (!checkPermission()) {
278         return nullptr;
279     }
280 
281     // Is this a recognized camera id?
282     CameraRecord *pRecord = findCameraById(cameraId);
283     if (pRecord == nullptr) {
284         LOG(ERROR) << cameraId << " does not exist!";
285         return nullptr;
286     }
287 
288     // Has this camera already been instantiated by another caller?
289     sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote();
290     if (pActiveCamera != nullptr) {
291         LOG(WARNING) << "Killing previous camera because of new caller";
292         closeCamera(pActiveCamera);
293     }
294 
295     // Construct a camera instance for the caller
296     if (sConfigManager == nullptr) {
297         pActiveCamera = EvsV4lCamera::Create(cameraId.c_str());
298     } else {
299         pActiveCamera = EvsV4lCamera::Create(cameraId.c_str(),
300                                              sConfigManager->getCameraInfo(cameraId));
301     }
302 
303     pRecord->activeInstance = pActiveCamera;
304     if (pActiveCamera == nullptr) {
305         LOG(ERROR) << "Failed to create new EvsV4lCamera object for " << cameraId;
306     }
307 
308     return pActiveCamera;
309 }
310 
311 
closeCamera(const::android::sp<IEvsCamera_1_0> & pCamera)312 Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& pCamera) {
313     LOG(DEBUG) << __FUNCTION__;
314 
315     if (pCamera == nullptr) {
316         LOG(ERROR) << "Ignoring call to closeCamera with null camera ptr";
317         return Void();
318     }
319 
320     // Get the camera id so we can find it in our list
321     std::string cameraId;
322     pCamera->getCameraInfo([&cameraId](CameraDesc_1_0 desc) {
323                                cameraId = desc.cameraId;
324                            }
325     );
326 
327     closeCamera_impl(pCamera, cameraId);
328 
329     return Void();
330 }
331 
332 
openDisplay()333 Return<sp<IEvsDisplay_1_0>> EvsEnumerator::openDisplay() {
334     LOG(DEBUG) << __FUNCTION__;
335     if (!checkPermission()) {
336         return nullptr;
337     }
338 
339     // If we already have a display active, then we need to shut it down so we can
340     // give exclusive access to the new caller.
341     sp<EvsGlDisplay> pActiveDisplay = sActiveDisplay.promote();
342     if (pActiveDisplay != nullptr) {
343         LOG(WARNING) << "Killing previous display because of new caller";
344         closeDisplay(pActiveDisplay);
345     }
346 
347     // Create a new display interface and return it.
348     pActiveDisplay = new EvsGlDisplay(sDisplayProxy, sInternalDisplayId);
349     sActiveDisplay = pActiveDisplay;
350 
351     LOG(DEBUG) << "Returning new EvsGlDisplay object " << pActiveDisplay.get();
352     return pActiveDisplay;
353 }
354 
355 
closeDisplay(const::android::sp<IEvsDisplay_1_0> & pDisplay)356 Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay_1_0>& pDisplay) {
357     LOG(DEBUG) << __FUNCTION__;
358 
359     // Do we still have a display object we think should be active?
360     sp<EvsGlDisplay> pActiveDisplay = sActiveDisplay.promote();
361     if (pActiveDisplay == nullptr) {
362         LOG(ERROR) << "Somehow a display is being destroyed "
363                    << "when the enumerator didn't know one existed";
364     } else if (sActiveDisplay != pDisplay) {
365         LOG(WARNING) << "Ignoring close of previously orphaned display - why did a client steal?";
366     } else {
367         // Drop the active display
368         pActiveDisplay->forceShutdown();
369         sActiveDisplay = nullptr;
370     }
371 
372     return Void();
373 }
374 
375 
getDisplayState()376 Return<EvsDisplayState> EvsEnumerator::getDisplayState()  {
377     LOG(DEBUG) << __FUNCTION__;
378     if (!checkPermission()) {
379         return EvsDisplayState::DEAD;
380     }
381 
382     // Do we still have a display object we think should be active?
383     sp<IEvsDisplay_1_0> pActiveDisplay = sActiveDisplay.promote();
384     if (pActiveDisplay != nullptr) {
385         return pActiveDisplay->getDisplayState();
386     } else {
387         return EvsDisplayState::NOT_OPEN;
388     }
389 }
390 
391 
392 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
getCameraList_1_1(getCameraList_1_1_cb _hidl_cb)393 Return<void> EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb)  {
394     LOG(DEBUG) << __FUNCTION__;
395     if (!checkPermission()) {
396         return Void();
397     }
398 
399     {
400         std::unique_lock<std::mutex> lock(sLock);
401         if (sCameraList.size() < 1) {
402             // No qualified device has been found.  Wait until new device is ready,
403             if (!sCameraSignal.wait_for(lock,
404                                         kEnumerationTimeout,
405                                         []{ return sCameraList.size() > 0; })) {
406                 LOG(DEBUG) << "Timer expired.  No new device has been added.";
407             }
408         }
409     }
410 
411     std::vector<CameraDesc_1_1> hidlCameras;
412     if (sConfigManager == nullptr) {
413         auto numCameras = sCameraList.size();
414 
415         // Build up a packed array of CameraDesc for return
416         hidlCameras.resize(numCameras);
417         unsigned i = 0;
418         for (auto&& [key, cam] : sCameraList) {
419             hidlCameras[i++] = cam.desc;
420         }
421     } else {
422         // Build up a packed array of CameraDesc for return
423         for (auto&& [key, cam] : sCameraList) {
424             unique_ptr<ConfigManager::CameraInfo> &tempInfo =
425                 sConfigManager->getCameraInfo(key);
426             if (tempInfo != nullptr) {
427                 cam.desc.metadata.setToExternal(
428                     (uint8_t *)tempInfo->characteristics,
429                      get_camera_metadata_size(tempInfo->characteristics)
430                 );
431             }
432 
433             hidlCameras.emplace_back(cam.desc);
434         }
435 
436         // Adding camera groups that represent logical camera devices
437         auto camGroups = sConfigManager->getCameraGroupIdList();
438         for (auto&& id : camGroups) {
439             if (sCameraList.find(id) != sCameraList.end()) {
440                 // Already exists in the list
441                 continue;
442             }
443 
444             unique_ptr<ConfigManager::CameraGroupInfo> &tempInfo =
445                 sConfigManager->getCameraGroupInfo(id);
446             CameraRecord cam(id.c_str());
447             if (tempInfo != nullptr) {
448                 cam.desc.metadata.setToExternal(
449                     (uint8_t *)tempInfo->characteristics,
450                      get_camera_metadata_size(tempInfo->characteristics)
451                 );
452             }
453 
454             sCameraList.emplace(id, cam);
455             hidlCameras.emplace_back(cam.desc);
456         }
457     }
458 
459     // Send back the results
460     _hidl_cb(hidlCameras);
461 
462     // HIDL convention says we return Void if we sent our result back via callback
463     return Void();
464 }
465 
466 
openCamera_1_1(const hidl_string & cameraId,const Stream & streamCfg)467 Return<sp<IEvsCamera_1_1>> EvsEnumerator::openCamera_1_1(const hidl_string& cameraId,
468                                                          const Stream& streamCfg) {
469     LOG(DEBUG) << __FUNCTION__;
470     if (!checkPermission()) {
471         return nullptr;
472     }
473 
474     // Is this a recognized camera id?
475     CameraRecord *pRecord = findCameraById(cameraId);
476     if (pRecord == nullptr) {
477         LOG(ERROR) << cameraId << " does not exist!";
478         return nullptr;
479     }
480 
481     // Has this camera already been instantiated by another caller?
482     sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote();
483     if (pActiveCamera != nullptr) {
484         LOG(WARNING) << "Killing previous camera because of new caller";
485         closeCamera(pActiveCamera);
486     }
487 
488     // Construct a camera instance for the caller
489     if (sConfigManager == nullptr) {
490         LOG(WARNING) << "ConfigManager is not available.  "
491                      << "Given stream configuration is ignored.";
492         pActiveCamera = EvsV4lCamera::Create(cameraId.c_str());
493     } else {
494         pActiveCamera = EvsV4lCamera::Create(cameraId.c_str(),
495                                              sConfigManager->getCameraInfo(cameraId),
496                                              &streamCfg);
497     }
498     pRecord->activeInstance = pActiveCamera;
499     if (pActiveCamera == nullptr) {
500         LOG(ERROR) << "Failed to create new EvsV4lCamera object for " << cameraId;
501     }
502 
503     return pActiveCamera;
504 }
505 
506 
getDisplayIdList(getDisplayIdList_cb _list_cb)507 Return<void> EvsEnumerator::getDisplayIdList(getDisplayIdList_cb _list_cb) {
508     hidl_vec<uint8_t> ids;
509 
510     if (sDisplayPortList.size() > 0) {
511         ids.resize(sDisplayPortList.size());
512         unsigned i = 0;
513         ids[i++] = sInternalDisplayId & 0xF;
514         for (const auto& [port, id] : sDisplayPortList) {
515             if (sInternalDisplayId != id) {
516                 ids[i++] = port;
517             }
518         }
519     }
520 
521     _list_cb(ids);
522     return Void();
523 }
524 
525 
openDisplay_1_1(uint8_t port)526 Return<sp<IEvsDisplay_1_1>> EvsEnumerator::openDisplay_1_1(uint8_t port) {
527     LOG(DEBUG) << __FUNCTION__;
528     if (!checkPermission()) {
529         return nullptr;
530     }
531 
532     // If we already have a display active, then we need to shut it down so we can
533     // give exclusive access to the new caller.
534     sp<EvsGlDisplay> pActiveDisplay = sActiveDisplay.promote();
535     if (pActiveDisplay != nullptr) {
536         LOG(WARNING) << "Killing previous display because of new caller";
537         closeDisplay(pActiveDisplay);
538     }
539 
540     // Create a new display interface and return it
541     if (sDisplayPortList.find(port) == sDisplayPortList.end()) {
542         LOG(ERROR) << "No display is available on the port "
543                    << static_cast<int32_t>(port);
544         return nullptr;
545     }
546 
547     pActiveDisplay = new EvsGlDisplay(sDisplayProxy, sDisplayPortList[port]);
548     sActiveDisplay = pActiveDisplay;
549 
550     LOG(DEBUG) << "Returning new EvsGlDisplay object " << pActiveDisplay.get();
551     return pActiveDisplay;
552 }
553 
554 
closeCamera_impl(const sp<IEvsCamera_1_0> & pCamera,const std::string & cameraId)555 void EvsEnumerator::closeCamera_impl(const sp<IEvsCamera_1_0>& pCamera,
556                                      const std::string& cameraId) {
557     // Find the named camera
558     CameraRecord *pRecord = findCameraById(cameraId);
559 
560     // Is the display being destroyed actually the one we think is active?
561     if (!pRecord) {
562         LOG(ERROR) << "Asked to close a camera whose name isn't recognized";
563     } else {
564         sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote();
565 
566         if (pActiveCamera == nullptr) {
567             LOG(ERROR) << "Somehow a camera is being destroyed "
568                        << "when the enumerator didn't know one existed";
569         } else if (pActiveCamera != pCamera) {
570             // This can happen if the camera was aggressively reopened,
571             // orphaning this previous instance
572             LOG(WARNING) << "Ignoring close of previously orphaned camera "
573                          << "- why did a client steal?";
574         } else {
575             // Drop the active camera
576             pActiveCamera->shutdown();
577             pRecord->activeInstance = nullptr;
578         }
579     }
580 
581     return;
582 }
583 
584 
qualifyCaptureDevice(const char * deviceName)585 bool EvsEnumerator::qualifyCaptureDevice(const char* deviceName) {
586     class FileHandleWrapper {
587     public:
588         FileHandleWrapper(int fd)   { mFd = fd; }
589         ~FileHandleWrapper()        { if (mFd > 0) close(mFd); }
590         operator int() const        { return mFd; }
591     private:
592         int mFd = -1;
593     };
594 
595 
596     FileHandleWrapper fd = open(deviceName, O_RDWR, 0);
597     if (fd < 0) {
598         return false;
599     }
600 
601     v4l2_capability caps;
602     int result = ioctl(fd, VIDIOC_QUERYCAP, &caps);
603     if (result  < 0) {
604         return false;
605     }
606     if (((caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) ||
607         ((caps.capabilities & V4L2_CAP_STREAMING)     == 0)) {
608         return false;
609     }
610 
611     // Enumerate the available capture formats (if any)
612     v4l2_fmtdesc formatDescription;
613     formatDescription.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
614     bool found = false;
615     for (int i=0; !found; i++) {
616         formatDescription.index = i;
617         if (ioctl(fd, VIDIOC_ENUM_FMT, &formatDescription) == 0) {
618             LOG(INFO) << "Format: 0x" << std::hex << formatDescription.pixelformat
619                       << " Type: 0x" << std::hex << formatDescription.type
620                       << " Desc: " << formatDescription.description
621                       << " Flags: 0x" << std::hex << formatDescription.flags;
622             switch (formatDescription.pixelformat)
623             {
624                 case V4L2_PIX_FMT_YUYV:     found = true; break;
625                 case V4L2_PIX_FMT_NV21:     found = true; break;
626                 case V4L2_PIX_FMT_NV16:     found = true; break;
627                 case V4L2_PIX_FMT_YVU420:   found = true; break;
628                 case V4L2_PIX_FMT_RGB32:    found = true; break;
629 #ifdef V4L2_PIX_FMT_ARGB32  // introduced with kernel v3.17
630                 case V4L2_PIX_FMT_ARGB32:   found = true; break;
631                 case V4L2_PIX_FMT_XRGB32:   found = true; break;
632 #endif // V4L2_PIX_FMT_ARGB32
633                 default:
634                     LOG(WARNING) << "Unsupported, "
635                                  << std::hex << formatDescription.pixelformat;
636                     break;
637             }
638         } else {
639             // No more formats available.
640             break;
641         }
642     }
643 
644     return found;
645 }
646 
647 
findCameraById(const std::string & cameraId)648 EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) {
649     // Find the named camera
650     auto found = sCameraList.find(cameraId);
651     if (sCameraList.end() != found) {
652         // Found a match!
653         return &found->second;
654     }
655 
656     // We didn't find a match
657     return nullptr;
658 }
659 
660 
661 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb)662 Return<void> EvsEnumerator::getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) {
663     hidl_vec<UltrasonicsArrayDesc> ultrasonicsArrayDesc;
664     _hidl_cb(ultrasonicsArrayDesc);
665     return Void();
666 }
667 
668 
669 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
openUltrasonicsArray(const hidl_string & ultrasonicsArrayId)670 Return<sp<IEvsUltrasonicsArray>> EvsEnumerator::openUltrasonicsArray(
671         const hidl_string& ultrasonicsArrayId) {
672     (void)ultrasonicsArrayId;
673     return sp<IEvsUltrasonicsArray>();
674 }
675 
676 
677 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
closeUltrasonicsArray(const::android::sp<IEvsUltrasonicsArray> & evsUltrasonicsArray)678 Return<void> EvsEnumerator::closeUltrasonicsArray(
679         const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray)  {
680     (void)evsUltrasonicsArray;
681     return Void();
682 }
683 
684 } // namespace implementation
685 } // namespace V1_1
686 } // namespace evs
687 } // namespace automotive
688 } // namespace hardware
689 } // namespace android
690