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