• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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? "
102                        << "pid = " << ipc->getCallingPid() << ", userId = " << userId
103                        << ", appId = " << appId;
104             return false;
105         }
106 
107         return true;
108     }
109 };
110 
111 }  // namespace
112 
113 namespace android::automotive::evs::V1_1::implementation {
114 
Enumerator(std::unique_ptr<ServiceFactory> serviceFactory,std::unique_ptr<IStatsCollector> statsCollector,std::unique_ptr<IPermissionsChecker> permissionChecker)115 Enumerator::Enumerator(std::unique_ptr<ServiceFactory> serviceFactory,
116                        std::unique_ptr<IStatsCollector> statsCollector,
117                        std::unique_ptr<IPermissionsChecker> permissionChecker) :
118       mServiceFactory(std::move(serviceFactory)),
119       mStatsCollector(std::move(statsCollector)),
120       mPermissionChecker(std::move(permissionChecker)) {
121     // Get an internal display identifier.
122     mServiceFactory->getService()->getDisplayIdList(
123             [this](const android::hardware::hidl_vec<unsigned char>& displayPorts) {
124                 for (unsigned char port : displayPorts) {
125                     mDisplayPorts.push_back(port);
126                 }
127 
128                 if (mDisplayPorts.empty()) {
129                     LOG(WARNING) << "No display is available to EVS service.";
130                 } else {
131                     // The first element must be the internal display
132                     mInternalDisplayPort = mDisplayPorts.front();
133                 }
134             });
135 
136     removeIfPresent(&mDisplayPorts, kExclusiveMainDisplayId, []() {
137         LOG(WARNING) << kExclusiveMainDisplayId
138                      << " is reserved so will not be available for EVS service.";
139     });
140 
141     mMonitorEnabled = mStatsCollector->startCollection().ok();
142 }
143 
build(std::unique_ptr<ServiceFactory> serviceFactory,std::unique_ptr<IStatsCollector> statsCollector,std::unique_ptr<IPermissionsChecker> permissionChecker)144 std::unique_ptr<Enumerator> Enumerator::build(
145         std::unique_ptr<ServiceFactory> serviceFactory,
146         std::unique_ptr<IStatsCollector> statsCollector,
147         std::unique_ptr<IPermissionsChecker> permissionChecker) {
148     // Connect with the underlying hardware enumerator.
149     if (!serviceFactory->getService()) {
150         return nullptr;
151     }
152 
153     return std::unique_ptr<Enumerator>{new Enumerator(std::move(serviceFactory),
154                                                       std::move(statsCollector),
155                                                       std::move(permissionChecker))};
156 }
157 
build(const char * hardwareServiceName)158 std::unique_ptr<Enumerator> Enumerator::build(const char* hardwareServiceName) {
159     if (!hardwareServiceName) {
160         return nullptr;
161     }
162 
163     return build(std::make_unique<ProdServiceFactory>(hardwareServiceName),
164                  std::make_unique<StatsCollector>(), std::make_unique<ProdPermissionChecker>());
165 }
166 
isLogicalCamera(const camera_metadata_t * metadata)167 bool Enumerator::isLogicalCamera(const camera_metadata_t* metadata) {
168     bool found = false;
169 
170     if (metadata == nullptr) {
171         LOG(ERROR) << "Metadata is null";
172         return found;
173     }
174 
175     camera_metadata_ro_entry_t entry;
176     int rc =
177             find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
178     if (0 != rc) {
179         // No capabilities are found in metadata.
180         LOG(DEBUG) << __FUNCTION__ << " does not find a target entry";
181         return found;
182     }
183 
184     for (size_t i = 0; i < entry.count; ++i) {
185         uint8_t capability = entry.data.u8[i];
186         if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
187             found = true;
188             break;
189         }
190     }
191 
192     if (!found) {
193         LOG(DEBUG) << __FUNCTION__ << " does not find a logical multi camera cap";
194     }
195     return found;
196 }
197 
getPhysicalCameraIds(const std::string & id)198 std::unordered_set<std::string> Enumerator::getPhysicalCameraIds(const std::string& id) {
199     std::unordered_set<std::string> physicalCameras;
200     if (mCameraDevices.find(id) == mCameraDevices.end()) {
201         LOG(ERROR) << "Queried device " << id << " does not exist!";
202         return physicalCameras;
203     }
204 
205     const camera_metadata_t* metadata =
206             reinterpret_cast<camera_metadata_t*>(&mCameraDevices[id].metadata[0]);
207     if (!isLogicalCamera(metadata)) {
208         // EVS assumes that the device w/o a valid metadata is a physical
209         // device.
210         LOG(INFO) << id << " is not a logical camera device.";
211         physicalCameras.emplace(id);
212         return physicalCameras;
213     }
214 
215     camera_metadata_ro_entry entry;
216     int rc = find_camera_metadata_ro_entry(metadata, ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
217                                            &entry);
218     if (0 != rc) {
219         LOG(ERROR) << "No physical camera ID is found for a logical camera device " << id;
220         return physicalCameras;
221     }
222 
223     const uint8_t* ids = entry.data.u8;
224     size_t start = 0;
225     for (size_t i = 0; i < entry.count; ++i) {
226         if (ids[i] == '\0') {
227             if (start != i) {
228                 std::string id(reinterpret_cast<const char*>(ids + start));
229                 physicalCameras.emplace(id);
230             }
231             start = i + 1;
232         }
233     }
234 
235     LOG(INFO) << id << " consists of " << physicalCameras.size() << " physical camera devices.";
236     return physicalCameras;
237 }
238 
239 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
getCameraList(getCameraList_cb list_cb)240 Return<void> Enumerator::getCameraList(getCameraList_cb list_cb) {
241     if (!mPermissionChecker->processHasPermissionsForEvs()) {
242         list_cb({});
243         return Void();
244     }
245 
246     hardware::hidl_vec<CameraDesc_1_0> cameraList;
247     mServiceFactory->getService()->getCameraList([&cameraList](auto enumeratedCameras) {
248         cameraList.resize(enumeratedCameras.size());
249         unsigned count = 0;
250         for (auto&& cam : enumeratedCameras) {
251             cameraList[count++] = cam;
252         }
253     });
254 
255     // Update the cached device list.
256     for (auto&& desc : cameraList) {
257         auto it = mCameraDevices.find(desc.cameraId);
258         if (it != mCameraDevices.end()) {
259             it->second.v1 = desc;
260         } else {
261             CameraDesc desc_1_1 = { .v1 = desc };
262             mCameraDevices.emplace(desc.cameraId, desc_1_1);
263         }
264     }
265 
266     list_cb(cameraList);
267     return Void();
268 }
269 
openCamera(const hidl_string & cameraId)270 Return<sp<IEvsCamera_1_0>> Enumerator::openCamera(const hidl_string& cameraId) {
271     LOG(DEBUG) << __FUNCTION__;
272     if (!mPermissionChecker->processHasPermissionsForEvs()) {
273         return nullptr;
274     }
275 
276     // Is the underlying hardware camera already open?
277     sp<HalCamera> hwCamera;
278     if (mActiveCameras.find(cameraId) != mActiveCameras.end()) {
279         hwCamera = mActiveCameras[cameraId];
280     } else {
281         // Is the hardware camera available?
282         sp<IEvsCamera_1_1> device;
283         if (std::regex_match(cameraId.c_str(), kEmulatedCameraNamePattern)) {
284             if (mEmulatedCameraDevices.find(cameraId) == mEmulatedCameraDevices.end()) {
285                 LOG(ERROR) << cameraId << " is not available";
286             } else {
287                 device = EvsEmulatedCamera::Create(cameraId.c_str(),
288                                                    mEmulatedCameraDevices[cameraId]);
289             }
290         } else {
291             device = IEvsCamera_1_1::castFrom(mServiceFactory->getService()->openCamera(cameraId))
292                              .withDefault(nullptr);
293         }
294         if (device == nullptr) {
295             LOG(ERROR) << "Failed to open hardware camera " << cameraId;
296         } else {
297             // Calculates the usage statistics record identifier
298             auto fn = mCameraDevices.hash_function();
299             auto recordId = fn(cameraId) & 0xFF;
300             hwCamera = new HalCamera(device, cameraId, recordId);
301             if (hwCamera == nullptr) {
302                 LOG(ERROR) << "Failed to allocate camera wrapper object";
303                 mServiceFactory->getService()->closeCamera(device);
304             }
305         }
306     }
307 
308     // Construct a virtual camera wrapper for this hardware camera
309     sp<VirtualCamera> clientCamera;
310     if (hwCamera != nullptr) {
311         clientCamera = hwCamera->makeVirtualCamera();
312     }
313 
314     // Add the hardware camera to our list, which will keep it alive via ref count
315     if (clientCamera != nullptr) {
316         mActiveCameras.try_emplace(cameraId, hwCamera);
317     } else {
318         LOG(ERROR) << "Requested camera " << cameraId << " not found or not available";
319     }
320 
321     // Send the virtual camera object back to the client by strong pointer which will keep it alive
322     return clientCamera;
323 }
324 
closeCamera(const::android::sp<IEvsCamera_1_0> & clientCamera)325 Return<void> Enumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& clientCamera) {
326     LOG(DEBUG) << __FUNCTION__;
327 
328     if (clientCamera == nullptr) {
329         LOG(ERROR) << "Ignoring call with null camera pointer.";
330         return Void();
331     }
332 
333     // All our client cameras are actually VirtualCamera objects
334     sp<VirtualCamera> virtualCamera = reinterpret_cast<VirtualCamera*>(clientCamera.get());
335 
336     // Find the parent camera that backs this virtual camera
337     for (auto&& halCamera : virtualCamera->getHalCameras()) {
338         // Tell the virtual camera's parent to clean it up and drop it
339         // NOTE:  The camera objects will only actually destruct when the sp<> ref counts get to
340         //        zero, so it is important to break all cyclic references.
341         halCamera->disownVirtualCamera(virtualCamera);
342 
343         // Did we just remove the last client of this camera?
344         if (halCamera->getClientCount() == 0) {
345             // Take this now unused camera out of our list
346             // NOTE:  This should drop our last reference to the camera, resulting in its
347             //        destruction.
348             mActiveCameras.erase(halCamera->getId());
349             mServiceFactory->getService()->closeCamera(halCamera->getHwCamera());
350             if (mMonitorEnabled) {
351                 mStatsCollector->unregisterClientToMonitor(halCamera->getId());
352             }
353         }
354     }
355 
356     // Make sure the virtual camera's stream is stopped
357     virtualCamera->stopVideoStream();
358 
359     return Void();
360 }
361 
362 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
openCamera_1_1(const hidl_string & cameraId,const Stream & streamCfg)363 Return<sp<IEvsCamera_1_1>> Enumerator::openCamera_1_1(const hidl_string& cameraId,
364                                                       const Stream& streamCfg) {
365     LOG(DEBUG) << __FUNCTION__;
366     if (!mPermissionChecker->processHasPermissionsForEvs()) {
367         return nullptr;
368     }
369 
370     // If hwCamera is null, a requested camera device is either a logical camera
371     // device or a hardware camera, which is not being used now.
372     std::unordered_set<std::string> physicalCameras = getPhysicalCameraIds(cameraId);
373     std::vector<sp<HalCamera>> sourceCameras;
374     sp<HalCamera> hwCamera;
375     bool success = true;
376 
377     // 1. Try to open inactive camera devices.
378     for (auto&& id : physicalCameras) {
379         auto it = mActiveCameras.find(id);
380         if (it == mActiveCameras.end()) {
381             sp<IEvsCamera_1_1> device;
382             if (std::regex_match(cameraId.c_str(), kEmulatedCameraNamePattern)) {
383                 if (mEmulatedCameraDevices.find(id) == mEmulatedCameraDevices.end()) {
384                     LOG(ERROR) << cameraId << " is not available";
385                 } else {
386                     device = EvsEmulatedCamera::Create(id.c_str(), mEmulatedCameraDevices[id]);
387                 }
388             } else {
389                 device = mServiceFactory->getService()->openCamera_1_1(id, streamCfg);
390             }
391 
392             if (device == nullptr) {
393                 LOG(ERROR) << "Failed to open hardware camera " << cameraId;
394                 success = false;
395                 break;
396             } else {
397                 // Calculates the usage statistics record identifier
398                 auto fn = mCameraDevices.hash_function();
399                 auto recordId = fn(id) & 0xFF;
400                 hwCamera = new HalCamera(device, id, recordId, streamCfg);
401                 if (hwCamera == nullptr) {
402                     LOG(ERROR) << "Failed to allocate camera wrapper object";
403                     mServiceFactory->getService()->closeCamera(device);
404                     success = false;
405                     break;
406                 }
407             }
408 
409             // Add the hardware camera to our list, which will keep it alive via ref count
410             mActiveCameras.try_emplace(id, hwCamera);
411             if (mMonitorEnabled) {
412                 mStatsCollector->registerClientToMonitor(hwCamera);
413             }
414 
415             sourceCameras.push_back(hwCamera);
416         } else {
417             if (it->second->getStreamConfig().id != streamCfg.id) {
418                 LOG(WARNING) << "Requested camera is already active in different configuration.";
419             } else {
420                 sourceCameras.push_back(it->second);
421             }
422         }
423     }
424 
425     if (!success || sourceCameras.size() < 1) {
426         LOG(ERROR) << "Failed to open any physical camera device";
427         return nullptr;
428     }
429 
430     // TODO(b/147170360): Implement a logic to handle a failure.
431     // 3. Create a proxy camera object
432     sp<VirtualCamera> clientCamera = new VirtualCamera(sourceCameras);
433     if (clientCamera == nullptr) {
434         // TODO(b/206829268): Any resource needs to be cleaned up explicitly?
435         LOG(ERROR) << "Failed to create a client camera object";
436     } else {
437         if (physicalCameras.size() > 1) {
438             // VirtualCamera, which represents a logical device, caches its
439             // descriptor.
440             clientCamera->setDescriptor(&mCameraDevices[cameraId]);
441         }
442 
443         // 4. Owns created proxy camera object
444         for (auto&& hwCamera : sourceCameras) {
445             if (!hwCamera->ownVirtualCamera(clientCamera)) {
446                 // TODO(b/206829268): Remove a reference to this camera from a virtual camera.
447                 // object.
448                 LOG(ERROR) << hwCamera->getId() << " failed to own a created proxy camera object.";
449             }
450         }
451     }
452 
453     // Send the virtual camera object back to the client by strong pointer which will keep it alive
454     return clientCamera;
455 }
456 
getCameraList_1_1(getCameraList_1_1_cb list_cb)457 Return<void> Enumerator::getCameraList_1_1(getCameraList_1_1_cb list_cb) {
458     LOG(DEBUG) << __FUNCTION__;
459     if (!mPermissionChecker->processHasPermissionsForEvs()) {
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