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