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