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