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