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