1 /*
2  * Copyright (C) 2019 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 "Enumerator.h"
18 #include "HalDisplay.h"
19 #include "emul/EvsEmulatedCamera.h"
20 
21 #include <regex>
22 
23 #include <android-base/chrono_utils.h>
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <android-base/parseint.h>
27 #include <android-base/strings.h>
28 #include <android-base/stringprintf.h>
29 #include <cutils/android_filesystem_config.h>
30 #include <hwbinder/IPCThreadState.h>
31 
32 namespace {
33 
34     const char* kSingleIndent = "\t";
35     const char* kDumpOptionAll = "all";
36     const char* kDumpDeviceCamera = "camera";
37     const char* kDumpDeviceDisplay = "display";
38 
39     const char* kDumpCameraCommandCurrent = "--current";
40     const char* kDumpCameraCommandCollected = "--collected";
41     const char* kDumpCameraCommandCustom = "--custom";
42     const char* kDumpCameraCommandCustomStart = "start";
43     const char* kDumpCameraCommandCustomStop = "stop";
44 
45     const int kDumpCameraMinNumArgs = 4;
46     const int kOptionDumpDeviceTypeIndex = 1;
47     const int kOptionDumpCameraTypeIndex = 2;
48     const int kOptionDumpCameraCommandIndex = 3;
49     const int kOptionDumpCameraArgsStartIndex = 4;
50 
51     const std::regex kEmulatedCameraNamePattern("emulated/[0-9]+", std::regex_constants::icase);
52 
53     // Display ID 255 is reserved for the special purpose.
54     constexpr int kExclusiveMainDisplayId = 255;
55 }
56 
57 namespace android {
58 namespace automotive {
59 namespace evs {
60 namespace V1_1 {
61 namespace implementation {
62 
63 using ::android::base::Error;
64 using ::android::base::EqualsIgnoreCase;
65 using ::android::base::StringAppendF;
66 using ::android::base::StringPrintf;
67 using ::android::base::WriteStringToFd;
68 using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
69 using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
70 
~Enumerator()71 Enumerator::~Enumerator() {
72     if (mClientsMonitor != nullptr) {
73         mClientsMonitor->stopCollection();
74     }
75 }
76 
init(const char * hardwareServiceName)77 bool Enumerator::init(const char* hardwareServiceName) {
78     LOG(DEBUG) << "init";
79 
80     // Connect with the underlying hardware enumerator
81     mHwEnumerator = IEvsEnumerator::getService(hardwareServiceName);
82     bool result = (mHwEnumerator != nullptr);
83     if (result) {
84         // Get an internal display identifier.
85         mHwEnumerator->getDisplayIdList(
86             [this](const auto& displayPorts) {
87                 for (auto& port : displayPorts) {
88                     mDisplayPorts.push_back(port);
89                 }
90 
91                 // The first element is the internal display
92                 mInternalDisplayPort = mDisplayPorts.front();
93                 if (mDisplayPorts.size() < 1) {
94                     LOG(WARNING) << "No display is available to EVS service.";
95                 }
96             }
97         );
98     }
99 
100     auto it = std::find(mDisplayPorts.begin(), mDisplayPorts.end(), kExclusiveMainDisplayId);
101     if (it != mDisplayPorts.end()) {
102         LOG(WARNING) << kExclusiveMainDisplayId << " is reserved for the special purpose "
103                      << "so will not be available for EVS service.";
104         mDisplayPorts.erase(it);
105     }
106     mDisplayOwnedExclusively = false;
107 
108     // Starts the statistics collection
109     mMonitorEnabled = false;
110     mClientsMonitor = new StatsCollector();
111     if (mClientsMonitor != nullptr) {
112         auto result = mClientsMonitor->startCollection();
113         if (!result.ok()) {
114             LOG(ERROR) << "Failed to start the usage monitor: "
115                        << result.error();
116         } else {
117             mMonitorEnabled = true;
118         }
119     }
120 
121     return result;
122 }
123 
124 
checkPermission()125 bool Enumerator::checkPermission() {
126     hardware::IPCThreadState *ipc = hardware::IPCThreadState::self();
127     const auto userId = ipc->getCallingUid() / AID_USER_OFFSET;
128     const auto appId = ipc->getCallingUid() % AID_USER_OFFSET;
129     if (AID_AUTOMOTIVE_EVS != appId && AID_ROOT != appId && AID_SYSTEM != appId) {
130         LOG(ERROR) << "EVS access denied? "
131                    << "pid = " << ipc->getCallingPid()
132                    << ", userId = " << userId
133                    << ", appId = " << appId;
134         return false;
135     }
136 
137     return true;
138 }
139 
140 
isLogicalCamera(const camera_metadata_t * metadata)141 bool Enumerator::isLogicalCamera(const camera_metadata_t *metadata) {
142     bool found = false;
143 
144     if (metadata == nullptr) {
145         LOG(ERROR) << "Metadata is null";
146         return found;
147     }
148 
149     camera_metadata_ro_entry_t entry;
150     int rc = find_camera_metadata_ro_entry(metadata,
151                                            ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
152                                            &entry);
153     if (0 != rc) {
154         // No capabilities are found in metadata.
155         LOG(DEBUG) << __FUNCTION__ << " does not find a target entry";
156         return found;
157     }
158 
159     for (size_t i = 0; i < entry.count; ++i) {
160         uint8_t capability = entry.data.u8[i];
161         if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
162             found = true;
163             break;
164         }
165     }
166 
167     if (!found) {
168         LOG(DEBUG) << __FUNCTION__ << " does not find a logical multi camera cap";
169     }
170     return found;
171 }
172 
173 
getPhysicalCameraIds(const std::string & id)174 std::unordered_set<std::string> Enumerator::getPhysicalCameraIds(const std::string& id) {
175     std::unordered_set<std::string> physicalCameras;
176     if (mCameraDevices.find(id) == mCameraDevices.end()) {
177         LOG(ERROR) << "Queried device " << id << " does not exist!";
178         return physicalCameras;
179     }
180 
181     const camera_metadata_t *metadata =
182         reinterpret_cast<camera_metadata_t *>(&mCameraDevices[id].metadata[0]);
183     if (!isLogicalCamera(metadata)) {
184         // EVS assumes that the device w/o a valid metadata is a physical
185         // device.
186         LOG(INFO) << id << " is not a logical camera device.";
187         physicalCameras.emplace(id);
188         return physicalCameras;
189     }
190 
191     camera_metadata_ro_entry entry;
192     int rc = find_camera_metadata_ro_entry(metadata,
193                                            ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
194                                            &entry);
195     if (0 != rc) {
196         LOG(ERROR) << "No physical camera ID is found for a logical camera device " << id;
197         return physicalCameras;
198     }
199 
200     const uint8_t *ids = entry.data.u8;
201     size_t start = 0;
202     for (size_t i = 0; i < entry.count; ++i) {
203         if (ids[i] == '\0') {
204             if (start != i) {
205                 std::string id(reinterpret_cast<const char *>(ids + start));
206                 physicalCameras.emplace(id);
207             }
208             start = i + 1;
209         }
210     }
211 
212     LOG(INFO) << id << " consists of "
213                << physicalCameras.size() << " physical camera devices.";
214     return physicalCameras;
215 }
216 
217 
218 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
getCameraList(getCameraList_cb list_cb)219 Return<void> Enumerator::getCameraList(getCameraList_cb list_cb)  {
220     hardware::hidl_vec<CameraDesc_1_0> cameraList;
221     mHwEnumerator->getCameraList_1_1([&cameraList](auto cameraList_1_1) {
222         cameraList.resize(cameraList_1_1.size());
223         unsigned i = 0;
224         for (auto&& cam : cameraList_1_1) {
225             cameraList[i++] = cam.v1;
226         }
227     });
228 
229     list_cb(cameraList);
230 
231     return Void();
232 }
233 
234 
openCamera(const hidl_string & cameraId)235 Return<sp<IEvsCamera_1_0>> Enumerator::openCamera(const hidl_string& cameraId) {
236     LOG(DEBUG) << __FUNCTION__;
237     if (!checkPermission()) {
238         return nullptr;
239     }
240 
241     // Is the underlying hardware camera already open?
242     sp<HalCamera> hwCamera;
243     if (mActiveCameras.find(cameraId) != mActiveCameras.end()) {
244         hwCamera = mActiveCameras[cameraId];
245     } else {
246         // Is the hardware camera available?
247         sp<IEvsCamera_1_1> device;
248         if (std::regex_match(cameraId.c_str(), kEmulatedCameraNamePattern)) {
249             if (mEmulatedCameraDevices.find(cameraId) == mEmulatedCameraDevices.end()) {
250                 LOG(ERROR) << cameraId << " is not available";
251             } else {
252                 device = EvsEmulatedCamera::Create(cameraId.c_str(),
253                                                    mEmulatedCameraDevices[cameraId]);
254             }
255         } else {
256             device = IEvsCamera_1_1::castFrom(mHwEnumerator->openCamera(cameraId))
257                      .withDefault(nullptr);
258         }
259         if (device == nullptr) {
260             LOG(ERROR) << "Failed to open hardware camera " << cameraId;
261         } else {
262             // Calculates the usage statistics record identifier
263             auto fn = mCameraDevices.hash_function();
264             auto recordId = fn(cameraId) & 0xFF;
265             hwCamera = new HalCamera(device, cameraId, recordId);
266             if (hwCamera == nullptr) {
267                 LOG(ERROR) << "Failed to allocate camera wrapper object";
268                 mHwEnumerator->closeCamera(device);
269             }
270         }
271     }
272 
273     // Construct a virtual camera wrapper for this hardware camera
274     sp<VirtualCamera> clientCamera;
275     if (hwCamera != nullptr) {
276         clientCamera = hwCamera->makeVirtualCamera();
277     }
278 
279     // Add the hardware camera to our list, which will keep it alive via ref count
280     if (clientCamera != nullptr) {
281         mActiveCameras.try_emplace(cameraId, hwCamera);
282     } else {
283         LOG(ERROR) << "Requested camera " << cameraId
284                    << " not found or not available";
285     }
286 
287     // Send the virtual camera object back to the client by strong pointer which will keep it alive
288     return clientCamera;
289 }
290 
291 
closeCamera(const::android::sp<IEvsCamera_1_0> & clientCamera)292 Return<void> Enumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& clientCamera) {
293     LOG(DEBUG) << __FUNCTION__;
294 
295     if (clientCamera == nullptr) {
296         LOG(ERROR) << "Ignoring call with null camera pointer.";
297         return Void();
298     }
299 
300     // All our client cameras are actually VirtualCamera objects
301     sp<VirtualCamera> virtualCamera = reinterpret_cast<VirtualCamera *>(clientCamera.get());
302 
303     // Find the parent camera that backs this virtual camera
304     for (auto&& halCamera : virtualCamera->getHalCameras()) {
305         // Tell the virtual camera's parent to clean it up and drop it
306         // NOTE:  The camera objects will only actually destruct when the sp<> ref counts get to
307         //        zero, so it is important to break all cyclic references.
308         halCamera->disownVirtualCamera(virtualCamera);
309 
310         // Did we just remove the last client of this camera?
311         if (halCamera->getClientCount() == 0) {
312             // Take this now unused camera out of our list
313             // NOTE:  This should drop our last reference to the camera, resulting in its
314             //        destruction.
315             mActiveCameras.erase(halCamera->getId());
316             mHwEnumerator->closeCamera(halCamera->getHwCamera());
317             if (mMonitorEnabled) {
318                 mClientsMonitor->unregisterClientToMonitor(halCamera->getId());
319             }
320         }
321     }
322 
323     // Make sure the virtual camera's stream is stopped
324     virtualCamera->stopVideoStream();
325 
326     return Void();
327 }
328 
329 
330 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
openCamera_1_1(const hidl_string & cameraId,const Stream & streamCfg)331 Return<sp<IEvsCamera_1_1>> Enumerator::openCamera_1_1(const hidl_string& cameraId,
332                                                       const Stream& streamCfg) {
333     LOG(DEBUG) << __FUNCTION__;
334     if (!checkPermission()) {
335         return nullptr;
336     }
337 
338     // If hwCamera is null, a requested camera device is either a logical camera
339     // device or a hardware camera, which is not being used now.
340     std::unordered_set<std::string> physicalCameras = getPhysicalCameraIds(cameraId);
341     std::vector<sp<HalCamera>> sourceCameras;
342     sp<HalCamera> hwCamera;
343     bool success = true;
344 
345     // 1. Try to open inactive camera devices.
346     for (auto&& id : physicalCameras) {
347         auto it = mActiveCameras.find(id);
348         if (it == mActiveCameras.end()) {
349             sp<IEvsCamera_1_1> device;
350             if (std::regex_match(cameraId.c_str(), kEmulatedCameraNamePattern)) {
351                 if (mEmulatedCameraDevices.find(id) == mEmulatedCameraDevices.end()) {
352                     LOG(ERROR) << cameraId << " is not available";
353                 } else {
354                     device = EvsEmulatedCamera::Create(id.c_str(),
355                                                        mEmulatedCameraDevices[id]);
356                 }
357             } else {
358                 device = mHwEnumerator->openCamera_1_1(id, streamCfg);
359             }
360 
361             if (device == nullptr) {
362                 LOG(ERROR) << "Failed to open hardware camera " << cameraId;
363                 success = false;
364                 break;
365             } else {
366                 // Calculates the usage statistics record identifier
367                 auto fn = mCameraDevices.hash_function();
368                 auto recordId = fn(id) & 0xFF;
369                 hwCamera = new HalCamera(device, id, recordId, streamCfg);
370                 if (hwCamera == nullptr) {
371                     LOG(ERROR) << "Failed to allocate camera wrapper object";
372                     mHwEnumerator->closeCamera(device);
373                     success = false;
374                     break;
375                 }
376             }
377 
378             // Add the hardware camera to our list, which will keep it alive via ref count
379             mActiveCameras.try_emplace(id, hwCamera);
380             if (mMonitorEnabled) {
381                 mClientsMonitor->registerClientToMonitor(hwCamera);
382             }
383 
384             sourceCameras.push_back(hwCamera);
385         } else {
386             if (it->second->getStreamConfig().id != streamCfg.id) {
387                 LOG(WARNING) << "Requested camera is already active in different configuration.";
388             } else {
389                 sourceCameras.push_back(it->second);
390             }
391         }
392     }
393 
394     if (!success || sourceCameras.size() < 1) {
395         LOG(ERROR) << "Failed to open any physical camera device";
396         return nullptr;
397     }
398 
399     // TODO(b/147170360): Implement a logic to handle a failure.
400     // 3. Create a proxy camera object
401     sp<VirtualCamera> clientCamera = new VirtualCamera(sourceCameras);
402     if (clientCamera == nullptr) {
403         // TODO: Any resource needs to be cleaned up explicitly?
404         LOG(ERROR) << "Failed to create a client camera object";
405     } else {
406         if (physicalCameras.size() > 1) {
407             // VirtualCamera, which represents a logical device, caches its
408             // descriptor.
409             clientCamera->setDescriptor(&mCameraDevices[cameraId]);
410         }
411 
412         // 4. Owns created proxy camera object
413         for (auto&& hwCamera : sourceCameras) {
414             if (!hwCamera->ownVirtualCamera(clientCamera)) {
415                 // TODO: Remove a referece to this camera from a virtual camera
416                 // object.
417                 LOG(ERROR) << hwCamera->getId()
418                            << " failed to own a created proxy camera object.";
419             }
420         }
421     }
422 
423     // Send the virtual camera object back to the client by strong pointer which will keep it alive
424     return clientCamera;
425 }
426 
427 
getCameraList_1_1(getCameraList_1_1_cb list_cb)428 Return<void> Enumerator::getCameraList_1_1(getCameraList_1_1_cb list_cb)  {
429     LOG(DEBUG) << __FUNCTION__;
430     if (!checkPermission()) {
431         return Void();
432     }
433 
434     hardware::hidl_vec<CameraDesc_1_1> hidlCameras;
435     mHwEnumerator->getCameraList_1_1(
436         [&hidlCameras](hardware::hidl_vec<CameraDesc_1_1> enumeratedCameras) {
437             hidlCameras.resize(enumeratedCameras.size());
438             unsigned count = 0;
439             for (auto&& camdesc : enumeratedCameras) {
440                 hidlCameras[count++] = camdesc;
441             }
442         }
443     );
444 
445     // Update the cached device list
446     mCameraDevices.clear();
447     for (auto&& desc : hidlCameras) {
448         mCameraDevices.insert_or_assign(desc.v1.cameraId, desc);
449     }
450 
451     // Add emulated devices if there is any
452     if (mEmulatedCameraDevices.size() > 0) {
453         int index = hidlCameras.size();
454         hidlCameras.resize(hidlCameras.size() + mEmulatedCameraDevices.size());
455         for (auto&& [id, desc] : mEmulatedCameraDevices) {
456             hidlCameras[index++].v1.cameraId = id;
457         }
458     }
459 
460     list_cb(hidlCameras);
461     return Void();
462 }
463 
464 
openDisplay()465 Return<sp<IEvsDisplay_1_0>> Enumerator::openDisplay() {
466     LOG(DEBUG) << __FUNCTION__;
467 
468     if (!checkPermission()) {
469         return nullptr;
470     }
471 
472     if (mDisplayOwnedExclusively) {
473         LOG(ERROR) << "Display is owned exclusively by another client.";
474         return nullptr;
475     }
476 
477     // We simply keep track of the most recently opened display instance.
478     // In the underlying layers we expect that a new open will cause the previous
479     // object to be destroyed.  This avoids any race conditions associated with
480     // create/destroy order and provides a cleaner restart sequence if the previous owner
481     // is non-responsive for some reason.
482     // Request exclusive access to the EVS display
483     sp<IEvsDisplay_1_0> pActiveDisplay = mHwEnumerator->openDisplay();
484     if (pActiveDisplay == nullptr) {
485         LOG(ERROR) << "EVS Display unavailable";
486 
487         return nullptr;
488     }
489 
490     // Remember (via weak pointer) who we think the most recently opened display is so that
491     // we can proxy state requests from other callers to it.
492     // TODO: Because of b/129284474, an additional class, HalDisplay, has been defined and
493     // wraps the IEvsDisplay object the driver returns.  We may want to remove this
494     // additional class when it is fixed properly.
495     sp<IEvsDisplay_1_0> pHalDisplay = new HalDisplay(pActiveDisplay, mInternalDisplayPort);
496     mActiveDisplay = pHalDisplay;
497 
498     return pHalDisplay;
499 }
500 
501 
closeDisplay(const::android::sp<IEvsDisplay_1_0> & display)502 Return<void> Enumerator::closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display) {
503     LOG(DEBUG) << __FUNCTION__;
504 
505     sp<IEvsDisplay_1_0> pActiveDisplay = mActiveDisplay.promote();
506 
507     // Drop the active display
508     if (display.get() != pActiveDisplay.get()) {
509         LOG(WARNING) << "Ignoring call to closeDisplay with unrecognized display object.";
510     } else {
511         // Pass this request through to the hardware layer
512         sp<HalDisplay> halDisplay = reinterpret_cast<HalDisplay *>(pActiveDisplay.get());
513         mHwEnumerator->closeDisplay(halDisplay->getHwDisplay());
514         mActiveDisplay = nullptr;
515         mDisplayOwnedExclusively = false;
516     }
517 
518     return Void();
519 }
520 
521 
getDisplayState()522 Return<EvsDisplayState> Enumerator::getDisplayState()  {
523     LOG(DEBUG) << __FUNCTION__;
524     if (!checkPermission()) {
525         return EvsDisplayState::DEAD;
526     }
527 
528     // Do we have a display object we think should be active?
529     sp<IEvsDisplay_1_0> pActiveDisplay = mActiveDisplay.promote();
530     if (pActiveDisplay != nullptr) {
531         // Pass this request through to the hardware layer
532         return pActiveDisplay->getDisplayState();
533     } else {
534         // We don't have a live display right now
535         mActiveDisplay = nullptr;
536         return EvsDisplayState::NOT_OPEN;
537     }
538 }
539 
540 
openDisplay_1_1(uint8_t id)541 Return<sp<IEvsDisplay_1_1>> Enumerator::openDisplay_1_1(uint8_t id) {
542     LOG(DEBUG) << __FUNCTION__;
543 
544     if (!checkPermission()) {
545         return nullptr;
546     }
547 
548     if (mDisplayOwnedExclusively) {
549         LOG(ERROR) << "Display is owned exclusively by another client.";
550         return nullptr;
551     }
552 
553     if (id == kExclusiveMainDisplayId) {
554         // The client requests to open the primary display exclusively.
555         id = mInternalDisplayPort;
556         mDisplayOwnedExclusively = true;
557     } else if (std::find(mDisplayPorts.begin(), mDisplayPorts.end(), id) == mDisplayPorts.end()) {
558         LOG(ERROR) << "No display is available on the port " << static_cast<int32_t>(id);
559         return nullptr;
560     }
561 
562     // We simply keep track of the most recently opened display instance.
563     // In the underlying layers we expect that a new open will cause the previous
564     // object to be destroyed.  This avoids any race conditions associated with
565     // create/destroy order and provides a cleaner restart sequence if the previous owner
566     // is non-responsive for some reason.
567     // Request exclusive access to the EVS display
568     sp<IEvsDisplay_1_1> pActiveDisplay = mHwEnumerator->openDisplay_1_1(id);
569     if (pActiveDisplay == nullptr) {
570         LOG(ERROR) << "EVS Display unavailable";
571 
572         return nullptr;
573     }
574 
575     // Remember (via weak pointer) who we think the most recently opened display is so that
576     // we can proxy state requests from other callers to it.
577     // TODO: Because of b/129284474, an additional class, HalDisplay, has been defined and
578     // wraps the IEvsDisplay object the driver returns.  We may want to remove this
579     // additional class when it is fixed properly.
580     sp<IEvsDisplay_1_1> pHalDisplay = new HalDisplay(pActiveDisplay, id);
581     mActiveDisplay = pHalDisplay;
582 
583     return pHalDisplay;
584 }
585 
586 
getDisplayIdList(getDisplayIdList_cb _list_cb)587 Return<void> Enumerator::getDisplayIdList(getDisplayIdList_cb _list_cb)  {
588     return mHwEnumerator->getDisplayIdList(_list_cb);
589 }
590 
591 
592 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb)593 Return<void> Enumerator::getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) {
594     hardware::hidl_vec<UltrasonicsArrayDesc> ultrasonicsArrayDesc;
595     _hidl_cb(ultrasonicsArrayDesc);
596     return Void();
597 }
598 
599 
600 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
openUltrasonicsArray(const hidl_string & ultrasonicsArrayId)601 Return<sp<IEvsUltrasonicsArray>> Enumerator::openUltrasonicsArray(
602         const hidl_string& ultrasonicsArrayId) {
603     (void)ultrasonicsArrayId;
604     sp<IEvsUltrasonicsArray> pEvsUltrasonicsArray;
605     return pEvsUltrasonicsArray;
606 }
607 
608 
609 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
closeUltrasonicsArray(const::android::sp<IEvsUltrasonicsArray> & evsUltrasonicsArray)610 Return<void> Enumerator::closeUltrasonicsArray(
611         const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray)  {
612     (void)evsUltrasonicsArray;
613     return Void();
614 }
615 
616 
debug(const hidl_handle & fd,const hidl_vec<hidl_string> & options)617 Return<void> Enumerator::debug(const hidl_handle& fd,
618                                const hidl_vec<hidl_string>& options) {
619     if (fd.getNativeHandle() != nullptr && fd->numFds > 0) {
620         cmdDump(fd->data[0], options);
621     } else {
622         LOG(ERROR) << "Given file descriptor is not valid.";
623     }
624 
625     return {};
626 }
627 
628 
cmdDump(int fd,const hidl_vec<hidl_string> & options)629 void Enumerator::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
630     if (options.size() == 0) {
631         WriteStringToFd("No option is given.\n", fd);
632         cmdHelp(fd);
633         return;
634     }
635 
636     const std::string option = options[0];
637     if (EqualsIgnoreCase(option, "--help")) {
638         cmdHelp(fd);
639     } else if (EqualsIgnoreCase(option, "--list")) {
640         cmdList(fd, options);
641     } else if (EqualsIgnoreCase(option, "--dump")) {
642         cmdDumpDevice(fd, options);
643     } else if (EqualsIgnoreCase(option, "--configure-emulated-camera")) {
644         cmdConfigureEmulatedCamera(fd, options);
645     } else {
646         WriteStringToFd(StringPrintf("Invalid option: %s\n", option.c_str()),
647                         fd);
648     }
649 }
650 
651 
cmdHelp(int fd)652 void Enumerator::cmdHelp(int fd) {
653     WriteStringToFd("--help: shows this help.\n"
654                     "--list [all|camera|display]: lists camera or display devices or both "
655                     "available to EVS manager.\n"
656                     "--dump camera [all|device_id] --[current|collected|custom] [args]\n"
657                     "\tcurrent: shows the current status\n"
658                     "\tcollected: shows 10 most recent periodically collected camera usage "
659                     "statistics\n"
660                     "\tcustom: starts/stops collecting the camera usage statistics\n"
661                     "\t\tstart [interval] [duration]: starts collecting usage statistics "
662                     "at every [interval] during [duration].  Interval and duration are in "
663                     "milliseconds.\n"
664                     "\t\tstop: stops collecting usage statistics and shows collected records.\n"
665                     "--dump display: shows current status of the display\n"
666                     "--configure-emulated-camera [id] [path] [width] [height] [interval]\n"
667                     "\tid: emulated device id to use; emulated/[0-9]+\n"
668                     "\tpath: a path to the directory where source files are stored\n"
669                     "\twidth: image width in pixels\n"
670                     "\theight: image height in pixels\n"
671                     "\tinterval: interval between consecutive frames in milliseconds.\n", fd);
672 }
673 
674 
cmdList(int fd,const hidl_vec<hidl_string> & options)675 void Enumerator::cmdList(int fd, const hidl_vec<hidl_string>& options) {
676     bool listCameras = true;
677     bool listDisplays = true;
678     if (options.size() > 1) {
679         const std::string option = options[1];
680         const bool listAll = EqualsIgnoreCase(option, kDumpOptionAll);
681         listCameras = listAll || EqualsIgnoreCase(option, kDumpDeviceCamera);
682         listDisplays = listAll || EqualsIgnoreCase(option, kDumpDeviceDisplay);
683         if (!listCameras && !listDisplays) {
684             WriteStringToFd(StringPrintf("Unrecognized option, %s, is ignored.\n",
685                                          option.c_str()),
686                             fd);
687 
688             // Nothing to show, return
689             return;
690         }
691     }
692 
693     std::string buffer;
694     if (listCameras) {
695         StringAppendF(&buffer,"Camera devices available to EVS service:\n");
696         if (mCameraDevices.size() < 1) {
697             // Camera devices may not be enumerated yet.  This may fail if the
698             // user is not permitted to use EVS service.
699             getCameraList_1_1(
700                 [](const auto cameras) {
701                     if (cameras.size() < 1) {
702                         LOG(WARNING) << "No camera device is available to EVS.";
703                     }
704                 });
705         }
706 
707         for (auto& [id, desc] : mCameraDevices) {
708             StringAppendF(&buffer, "%s%s\n", kSingleIndent, id.c_str());
709         }
710 
711         StringAppendF(&buffer, "%sCamera devices currently in use:\n", kSingleIndent);
712         for (auto& [id, ptr] : mActiveCameras) {
713             StringAppendF(&buffer, "%s%s\n", kSingleIndent, id.c_str());
714         }
715         StringAppendF(&buffer, "\n");
716     }
717 
718     if (listDisplays) {
719         if (mHwEnumerator != nullptr) {
720             StringAppendF(&buffer, "Display devices available to EVS service:\n");
721             // Get an internal display identifier.
722             mHwEnumerator->getDisplayIdList(
723                 [&](const auto& displayPorts) {
724                     for (auto&& port : displayPorts) {
725                         StringAppendF(&buffer, "%sdisplay port %u\n",
726                                                kSingleIndent,
727                                                static_cast<unsigned>(port));
728                     }
729                 }
730             );
731         } else {
732             LOG(WARNING) << "EVS HAL implementation is not available.";
733         }
734     }
735 
736     WriteStringToFd(buffer, fd);
737 }
738 
739 
cmdDumpDevice(int fd,const hidl_vec<hidl_string> & options)740 void Enumerator::cmdDumpDevice(int fd, const hidl_vec<hidl_string>& options) {
741     // Dumps both cameras and displays if the target device type is not given
742     bool dumpCameras = false;
743     bool dumpDisplays = false;
744     const auto numOptions = options.size();
745     if (numOptions > kOptionDumpDeviceTypeIndex) {
746         const std::string target = options[kOptionDumpDeviceTypeIndex];
747         dumpCameras = EqualsIgnoreCase(target, kDumpDeviceCamera);
748         dumpDisplays = EqualsIgnoreCase(target, kDumpDeviceDisplay);
749         if (!dumpCameras && !dumpDisplays) {
750             WriteStringToFd(StringPrintf("Unrecognized option, %s, is ignored.\n",
751                                          target.c_str()),
752                             fd);
753             cmdHelp(fd);
754             return;
755         }
756     } else {
757         WriteStringToFd(StringPrintf("Necessary arguments are missing.  "
758                                      "Please check the usages:\n"),
759                         fd);
760         cmdHelp(fd);
761         return;
762     }
763 
764     if (dumpCameras) {
765         // --dump camera [all|device_id] --[current|collected|custom] [args]
766         if (numOptions < kDumpCameraMinNumArgs) {
767             WriteStringToFd(StringPrintf("Necessary arguments are missing.  "
768                                          "Please check the usages:\n"),
769                             fd);
770             cmdHelp(fd);
771             return;
772         }
773 
774         const std::string deviceId = options[kOptionDumpCameraTypeIndex];
775         auto target = mActiveCameras.find(deviceId);
776         const bool dumpAllCameras = EqualsIgnoreCase(deviceId,
777                                                      kDumpOptionAll);
778         if (!dumpAllCameras && target == mActiveCameras.end()) {
779             // Unknown camera identifier
780             WriteStringToFd(StringPrintf("Given camera ID %s is unknown or not active.\n",
781                                          deviceId.c_str()),
782                             fd);
783             return;
784         }
785 
786         const std::string command = options[kOptionDumpCameraCommandIndex];
787         std::string cameraInfo;
788         if (EqualsIgnoreCase(command, kDumpCameraCommandCurrent)) {
789             // Active stream configuration from each active HalCamera objects
790             if (!dumpAllCameras) {
791                 StringAppendF(&cameraInfo, "HalCamera: %s\n%s",
792                                            deviceId.c_str(),
793                                            target->second->toString(kSingleIndent).c_str());
794             } else {
795                 for (auto&& [id, handle] : mActiveCameras) {
796                     // Appends the current status
797                     cameraInfo += handle->toString(kSingleIndent);
798                 }
799             }
800         } else if (EqualsIgnoreCase(command, kDumpCameraCommandCollected)) {
801             // Reads the usage statistics from active HalCamera objects
802             std::unordered_map<std::string, std::string> usageStrings;
803             if (mMonitorEnabled) {
804                 auto result = mClientsMonitor->toString(&usageStrings, kSingleIndent);
805                 if (!result.ok()) {
806                     LOG(ERROR) << "Failed to get the monitoring result";
807                     return;
808                 }
809 
810                 if (!dumpAllCameras) {
811                     cameraInfo += usageStrings[deviceId];
812                 } else {
813                     for (auto&& [id, stats] : usageStrings) {
814                         cameraInfo += stats;
815                     }
816                 }
817             } else {
818                 WriteStringToFd(StringPrintf("Client monitor is not available.\n"),
819                                 fd);
820                 return;
821             }
822         } else if (EqualsIgnoreCase(command, kDumpCameraCommandCustom)) {
823             // Additional arguments are expected for this command:
824             // --dump camera device_id --custom start [interval] [duration]
825             // or, --dump camera device_id --custom stop
826             if (numOptions < kDumpCameraMinNumArgs + 1) {
827                 WriteStringToFd(StringPrintf("Necessary arguments are missing. "
828                                              "Please check the usages:\n"),
829                                 fd);
830                 cmdHelp(fd);
831                 return;
832             }
833 
834             if (!mMonitorEnabled) {
835                 WriteStringToFd(StringPrintf("Client monitor is not available."), fd);
836                 return;
837             }
838 
839             const std::string subcommand = options[kOptionDumpCameraArgsStartIndex];
840             if (EqualsIgnoreCase(subcommand, kDumpCameraCommandCustomStart)) {
841                 using std::chrono::nanoseconds;
842                 using std::chrono::milliseconds;
843                 using std::chrono::duration_cast;
844                 nanoseconds interval = 0ns;
845                 nanoseconds duration = 0ns;
846                 if (numOptions > kOptionDumpCameraArgsStartIndex + 2) {
847                     duration = duration_cast<nanoseconds>(
848                             milliseconds(
849                                     std::stoi(options[kOptionDumpCameraArgsStartIndex + 2])
850                             ));
851                 }
852 
853                 if (numOptions > kOptionDumpCameraArgsStartIndex + 1) {
854                     interval = duration_cast<nanoseconds>(
855                             milliseconds(
856                                     std::stoi(options[kOptionDumpCameraArgsStartIndex + 1])
857                             ));
858                 }
859 
860                 // Starts a custom collection
861                 auto result = mClientsMonitor->startCustomCollection(interval, duration);
862                 if (!result.ok()) {
863                     LOG(ERROR) << "Failed to start a custom collection.  "
864                                << result.error();
865                     StringAppendF(&cameraInfo, "Failed to start a custom collection. %s\n",
866                                                result.error().message().c_str());
867                 }
868             } else if (EqualsIgnoreCase(subcommand, kDumpCameraCommandCustomStop)) {
869                 if (!mMonitorEnabled) {
870                     WriteStringToFd(StringPrintf("Client monitor is not available."), fd);
871                     return;
872                 }
873 
874                 auto result = mClientsMonitor->stopCustomCollection(deviceId);
875                 if (!result.ok()) {
876                     LOG(ERROR) << "Failed to stop a custom collection.  "
877                                << result.error();
878                     StringAppendF(&cameraInfo, "Failed to stop a custom collection. %s\n",
879                                                result.error().message().c_str());
880                 } else {
881                     // Pull the custom collection
882                     cameraInfo += *result;
883                 }
884             } else {
885                 WriteStringToFd(StringPrintf("Unknown argument: %s\n",
886                                              subcommand.c_str()),
887                                 fd);
888                 cmdHelp(fd);
889                 return;
890             }
891         } else {
892             WriteStringToFd(StringPrintf("Unknown command: %s\n"
893                                          "Please check the usages:\n", command.c_str()),
894                             fd);
895             cmdHelp(fd);
896             return;
897         }
898 
899         // Outputs the report
900         WriteStringToFd(cameraInfo, fd);
901     }
902 
903     if (dumpDisplays) {
904         HalDisplay* pDisplay =
905             reinterpret_cast<HalDisplay*>(mActiveDisplay.promote().get());
906         if (!pDisplay) {
907             WriteStringToFd("No active display is found.\n", fd);
908         } else {
909             WriteStringToFd(pDisplay->toString(kSingleIndent), fd);
910         }
911     }
912 }
913 
914 
cmdConfigureEmulatedCamera(int fd,const hidl_vec<hidl_string> & options)915 void Enumerator::cmdConfigureEmulatedCamera(int fd, const hidl_vec<hidl_string>& options) {
916     if (options.size() < 6) {
917         WriteStringToFd(StringPrintf("Necessary arguments are missing.\n"), fd);
918         cmdHelp(fd);
919         return;
920     }
921 
922     // --configure-emulated-camera [id] [path] [width] [height] [interval]
923     const std::string id = options[1];
924     if (!std::regex_match(id.c_str(), kEmulatedCameraNamePattern)) {
925         WriteStringToFd(StringPrintf("%s does not match to the pattern.\n", id.c_str()), fd);
926         return;
927     }
928 
929     if (mCameraDevices.find(id) != mCameraDevices.end()) {
930         WriteStringToFd(
931             StringPrintf("Updating %s's configuration.  "
932                          "This will get effective when currently active stream is closed.\n",
933                          id.c_str()), fd);
934     }
935 
936     std::string sourceDir = options[2];
937     int width = std::stoi(options[3]);
938     int height = std::stoi(options[4]);
939     std::chrono::nanoseconds interval = std::chrono::duration_cast<std::chrono::nanoseconds>(
940                                             std::chrono::milliseconds(std::stoi(options[5]))
941                                         );
942     WriteStringToFd(StringPrintf("Configuring %s as:\n"
943                                  "\tResolution: %dx%d\n"
944                                  "\tInterval: %f ms\n",
945                                  id.c_str(), width, height,
946                                  interval.count() / 1000000.), fd);
947 
948     EmulatedCameraDesc desc = {width, height, sourceDir, interval};
949     mEmulatedCameraDevices.insert_or_assign(id, std::move(desc));
950 }
951 
952 
953 } // namespace implementation
954 } // namespace V1_1
955 } // namespace evs
956 } // namespace automotive
957 } // namespace android
958