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