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