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