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