1 /*
2 * Copyright (C) 2023 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 "EvsEnumerator.h"
18
19 #include "ConfigManager.h"
20 #include "EvsAllCameras.h"
21 #include "EvsCameraBase.h"
22 #include "EvsGlDisplay.h"
23
24 #include <aidl/android/hardware/automotive/evs/EvsResult.h>
25 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
26 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
27 #include <cutils/android_filesystem_config.h>
28
29 #include <set>
30 #include <string_view>
31
32 namespace {
33
34 using ::aidl::android::frameworks::automotive::display::ICarDisplayProxy;
35 using ::aidl::android::hardware::graphics::common::BufferUsage;
36 using ::ndk::ScopedAStatus;
37 using std::chrono_literals::operator""s;
38
39 // Constants
40 constexpr std::chrono::seconds kEnumerationTimeout = 10s;
41 constexpr uint64_t kInvalidDisplayId = std::numeric_limits<uint64_t>::max();
42 const std::set<uid_t> kAllowedUids = {AID_AUTOMOTIVE_EVS, AID_SYSTEM, AID_ROOT};
43
44 } // namespace
45
46 namespace aidl::android::hardware::automotive::evs::implementation {
47
48 // NOTE: All members values are static so that all clients operate on the same state
49 // That is to say, this is effectively a singleton despite the fact that HIDL
50 // constructs a new instance for each client.
51 std::unordered_map<std::string, EvsEnumerator::CameraRecord> EvsEnumerator::sCameraList;
52 std::mutex EvsEnumerator::sLock;
53 std::condition_variable EvsEnumerator::sCameraSignal;
54 std::unique_ptr<ConfigManager> EvsEnumerator::sConfigManager;
55 std::shared_ptr<ICarDisplayProxy> EvsEnumerator::sDisplayProxy;
56 std::unordered_map<uint8_t, uint64_t> EvsEnumerator::sDisplayPortList;
57
mutableActiveDisplays()58 EvsEnumerator::ActiveDisplays& EvsEnumerator::mutableActiveDisplays() {
59 static ActiveDisplays active_displays;
60 return active_displays;
61 }
62
EvsEnumerator(const std::shared_ptr<ICarDisplayProxy> & proxyService)63 EvsEnumerator::EvsEnumerator(const std::shared_ptr<ICarDisplayProxy>& proxyService) {
64 LOG(DEBUG) << "EvsEnumerator is created.";
65
66 if (!sConfigManager) {
67 /* loads and initializes ConfigManager in a separate thread */
68 sConfigManager = ConfigManager::Create();
69 }
70
71 if (!sDisplayProxy) {
72 /* sets a car-window service handle */
73 sDisplayProxy = proxyService;
74 }
75
76 // Enumerate existing devices
77 enumerateCameras();
78 mInternalDisplayId = enumerateDisplays();
79 }
80
checkPermission()81 bool EvsEnumerator::checkPermission() {
82 const auto uid = AIBinder_getCallingUid();
83 if (kAllowedUids.find(uid) == kAllowedUids.end()) {
84 LOG(ERROR) << "EVS access denied: "
85 << "pid = " << AIBinder_getCallingPid() << ", uid = " << uid;
86 return false;
87 }
88
89 return true;
90 }
91
enumerateCameras()92 void EvsEnumerator::enumerateCameras() {
93 if (!sConfigManager) {
94 return;
95 }
96
97 for (auto id : sConfigManager->getCameraIdList()) {
98 CameraRecord rec(id.data());
99 std::unique_ptr<ConfigManager::CameraInfo>& pInfo = sConfigManager->getCameraInfo(id);
100 if (pInfo) {
101 uint8_t* ptr = reinterpret_cast<uint8_t*>(pInfo->characteristics);
102 const size_t len = get_camera_metadata_size(pInfo->characteristics);
103 rec.desc.metadata.insert(rec.desc.metadata.end(), ptr, ptr + len);
104 }
105 sCameraList.insert_or_assign(id, std::move(rec));
106 }
107 }
108
enumerateDisplays()109 uint64_t EvsEnumerator::enumerateDisplays() {
110 LOG(INFO) << __FUNCTION__ << ": Starting display enumeration";
111 uint64_t internalDisplayId = kInvalidDisplayId;
112 if (!sDisplayProxy) {
113 LOG(ERROR) << "ICarDisplayProxy is not available!";
114 return internalDisplayId;
115 }
116
117 std::vector<int64_t> displayIds;
118 if (auto status = sDisplayProxy->getDisplayIdList(&displayIds); !status.isOk()) {
119 LOG(ERROR) << "Failed to retrieve a display id list"
120 << ::android::statusToString(status.getStatus());
121 return internalDisplayId;
122 }
123
124 if (displayIds.size() > 0) {
125 // The first entry of the list is the internal display. See
126 // SurfaceFlinger::getPhysicalDisplayIds() implementation.
127 internalDisplayId = displayIds[0];
128 for (const auto& id : displayIds) {
129 const auto port = id & 0xFF;
130 LOG(INFO) << "Display " << std::hex << id << " is detected on the port, " << port;
131 sDisplayPortList.insert_or_assign(port, id);
132 }
133 }
134
135 LOG(INFO) << "Found " << sDisplayPortList.size() << " displays";
136 return internalDisplayId;
137 }
138
139 // Methods from ::android::hardware::automotive::evs::IEvsEnumerator follow.
getCameraList(std::vector<CameraDesc> * _aidl_return)140 ScopedAStatus EvsEnumerator::getCameraList(std::vector<CameraDesc>* _aidl_return) {
141 LOG(DEBUG) << __FUNCTION__;
142 if (!checkPermission()) {
143 return ScopedAStatus::fromServiceSpecificError(
144 static_cast<int>(EvsResult::PERMISSION_DENIED));
145 }
146
147 {
148 std::unique_lock<std::mutex> lock(sLock);
149 if (sCameraList.size() < 1) {
150 // No qualified device has been found. Wait until new device is ready,
151 // for 10 seconds.
152 if (!sCameraSignal.wait_for(lock, kEnumerationTimeout,
153 [] { return sCameraList.size() > 0; })) {
154 LOG(DEBUG) << "Timer expired. No new device has been added.";
155 }
156 }
157 }
158
159 // Build up a packed array of CameraDesc for return
160 _aidl_return->resize(sCameraList.size());
161 unsigned i = 0;
162 for (const auto& [key, cam] : sCameraList) {
163 (*_aidl_return)[i++] = cam.desc;
164 }
165
166 if (sConfigManager) {
167 // Adding camera groups that represent logical camera devices
168 auto camGroups = sConfigManager->getCameraGroupIdList();
169 for (auto&& id : camGroups) {
170 if (sCameraList.find(id) != sCameraList.end()) {
171 // Already exists in the _aidl_return
172 continue;
173 }
174
175 std::unique_ptr<ConfigManager::CameraGroupInfo>& tempInfo =
176 sConfigManager->getCameraGroupInfo(id);
177 CameraRecord cam(id.data());
178 if (tempInfo) {
179 uint8_t* ptr = reinterpret_cast<uint8_t*>(tempInfo->characteristics);
180 const size_t len = get_camera_metadata_size(tempInfo->characteristics);
181 cam.desc.metadata.insert(cam.desc.metadata.end(), ptr, ptr + len);
182 }
183
184 sCameraList.insert_or_assign(id, cam);
185 _aidl_return->push_back(cam.desc);
186 }
187 }
188
189 // Send back the results
190 LOG(DEBUG) << "Reporting " << sCameraList.size() << " cameras available";
191 return ScopedAStatus::ok();
192 }
193
getStreamList(const CameraDesc & desc,std::vector<Stream> * _aidl_return)194 ScopedAStatus EvsEnumerator::getStreamList(const CameraDesc& desc,
195 std::vector<Stream>* _aidl_return) {
196 using AidlPixelFormat = ::aidl::android::hardware::graphics::common::PixelFormat;
197
198 camera_metadata_t* pMetadata = const_cast<camera_metadata_t*>(
199 reinterpret_cast<const camera_metadata_t*>(desc.metadata.data()));
200 camera_metadata_entry_t streamConfig;
201 if (!find_camera_metadata_entry(pMetadata, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
202 &streamConfig)) {
203 const unsigned numStreamConfigs = streamConfig.count / sizeof(StreamConfiguration);
204 _aidl_return->resize(numStreamConfigs);
205 const StreamConfiguration* pCurrentConfig =
206 reinterpret_cast<StreamConfiguration*>(streamConfig.data.i32);
207 for (unsigned i = 0; i < numStreamConfigs; ++i, ++pCurrentConfig) {
208 // Build ::aidl::android::hardware::automotive::evs::Stream from
209 // StreamConfiguration.
210 Stream current = {
211 .id = pCurrentConfig->id,
212 .streamType =
213 pCurrentConfig->type ==
214 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT
215 ? StreamType::INPUT
216 : StreamType::OUTPUT,
217 .width = pCurrentConfig->width,
218 .height = pCurrentConfig->height,
219 .format = static_cast<AidlPixelFormat>(pCurrentConfig->format),
220 .usage = BufferUsage::CAMERA_INPUT,
221 .rotation = Rotation::ROTATION_0,
222 };
223
224 (*_aidl_return)[i] = current;
225 }
226 }
227
228 return ScopedAStatus::ok();
229 }
230
openCamera(const std::string & id,const Stream & cfg,std::shared_ptr<IEvsCamera> * obj)231 ScopedAStatus EvsEnumerator::openCamera(const std::string& id, const Stream& cfg,
232 std::shared_ptr<IEvsCamera>* obj) {
233 LOG(DEBUG) << __FUNCTION__;
234 if (!checkPermission()) {
235 return ScopedAStatus::fromServiceSpecificError(
236 static_cast<int>(EvsResult::PERMISSION_DENIED));
237 }
238
239 // Is this a recognized camera id?
240 CameraRecord* pRecord = findCameraById(id);
241 if (!pRecord) {
242 LOG(ERROR) << id << " does not exist!";
243 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
244 }
245
246 // Has this camera already been instantiated by another caller?
247 std::shared_ptr<EvsCameraBase> pActiveCamera = pRecord->activeInstance.lock();
248 if (pActiveCamera) {
249 LOG(WARNING) << "Killing previous camera because of new caller";
250 closeCamera(pActiveCamera);
251 }
252
253 // Construct a camera instance for the caller
254 if (!sConfigManager) {
255 pActiveCamera = EvsMockCamera::Create(id.data());
256 } else {
257 auto& cameraInfo = sConfigManager->getCameraInfo(id);
258 switch (cameraInfo->deviceType) {
259 using DeviceType = ConfigManager::CameraInfo::DeviceType;
260
261 // Default to MOCK for backward compatibility.
262 case DeviceType::NONE:
263 case DeviceType::MOCK:
264 pActiveCamera = EvsMockCamera::Create(id.data(), cameraInfo, &cfg);
265 break;
266
267 case DeviceType::VIDEO:
268 pActiveCamera = EvsVideoEmulatedCamera::Create(id.data(), cameraInfo, &cfg);
269 break;
270
271 default:
272 LOG(ERROR) << __func__ << ": camera device type "
273 << static_cast<std::int32_t>(cameraInfo->deviceType)
274 << " is not supported.";
275 break;
276 }
277 }
278
279 pRecord->activeInstance = pActiveCamera;
280 if (!pActiveCamera) {
281 LOG(ERROR) << "Failed to create new EVS camera object for " << id;
282 return ScopedAStatus::fromServiceSpecificError(
283 static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR));
284 }
285
286 *obj = pActiveCamera;
287 return ScopedAStatus::ok();
288 }
289
closeCamera(const std::shared_ptr<IEvsCamera> & cameraObj)290 ScopedAStatus EvsEnumerator::closeCamera(const std::shared_ptr<IEvsCamera>& cameraObj) {
291 LOG(DEBUG) << __FUNCTION__;
292
293 if (!cameraObj) {
294 LOG(ERROR) << "Ignoring call to closeCamera with null camera ptr";
295 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
296 }
297
298 // Get the camera id so we can find it in our list
299 CameraDesc desc;
300 auto status = cameraObj->getCameraInfo(&desc);
301 if (!status.isOk()) {
302 LOG(ERROR) << "Failed to read a camera descriptor";
303 return ScopedAStatus::fromServiceSpecificError(
304 static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR));
305 }
306 auto cameraId = desc.id;
307 closeCamera_impl(cameraObj, cameraId);
308 return ScopedAStatus::ok();
309 }
310
openDisplay(int32_t id,std::shared_ptr<IEvsDisplay> * displayObj)311 ScopedAStatus EvsEnumerator::openDisplay(int32_t id, std::shared_ptr<IEvsDisplay>* displayObj) {
312 LOG(DEBUG) << __FUNCTION__;
313 if (!checkPermission()) {
314 return ScopedAStatus::fromServiceSpecificError(
315 static_cast<int>(EvsResult::PERMISSION_DENIED));
316 }
317
318 auto& displays = mutableActiveDisplays();
319
320 if (auto existing_display_search = displays.popDisplay(id)) {
321 // If we already have a display active, then we need to shut it down so we can
322 // give exclusive access to the new caller.
323 std::shared_ptr<EvsGlDisplay> pActiveDisplay = existing_display_search->displayWeak.lock();
324 if (pActiveDisplay) {
325 LOG(WARNING) << "Killing previous display because of new caller";
326 pActiveDisplay->forceShutdown();
327 }
328 }
329
330 // Create a new display interface and return it
331 uint64_t targetDisplayId = mInternalDisplayId;
332 auto it = sDisplayPortList.find(id);
333 if (it != sDisplayPortList.end()) {
334 targetDisplayId = it->second;
335 } else {
336 LOG(WARNING) << "No display is available on the port " << static_cast<int32_t>(id)
337 << ". The main display " << mInternalDisplayId << " will be used instead";
338 }
339
340 // Create a new display interface and return it.
341 std::shared_ptr<EvsGlDisplay> pActiveDisplay =
342 ndk::SharedRefBase::make<EvsGlDisplay>(sDisplayProxy, targetDisplayId);
343
344 if (auto insert_result = displays.tryInsert(id, pActiveDisplay); !insert_result) {
345 LOG(ERROR) << "Display ID " << id << " has been used by another caller.";
346 pActiveDisplay->forceShutdown();
347 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::RESOURCE_BUSY));
348 }
349
350 LOG(DEBUG) << "Returning new EvsGlDisplay object " << pActiveDisplay.get();
351 *displayObj = pActiveDisplay;
352 return ScopedAStatus::ok();
353 }
354
closeDisplay(const std::shared_ptr<IEvsDisplay> & obj)355 ScopedAStatus EvsEnumerator::closeDisplay(const std::shared_ptr<IEvsDisplay>& obj) {
356 LOG(DEBUG) << __FUNCTION__;
357
358 auto& displays = mutableActiveDisplays();
359 const auto display_search = displays.popDisplay(obj);
360
361 if (!display_search) {
362 LOG(WARNING) << "Ignoring close of previously orphaned display - why did a client steal?";
363 return ScopedAStatus::ok();
364 }
365
366 auto pActiveDisplay = display_search->displayWeak.lock();
367
368 if (!pActiveDisplay) {
369 LOG(ERROR) << "Somehow a display is being destroyed "
370 << "when the enumerator didn't know one existed";
371 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
372 }
373
374 pActiveDisplay->forceShutdown();
375 return ScopedAStatus::ok();
376 }
377
getDisplayState(DisplayState * state)378 ScopedAStatus EvsEnumerator::getDisplayState(DisplayState* state) {
379 LOG(DEBUG) << __FUNCTION__;
380 return getDisplayStateImpl(std::nullopt, state);
381 }
382
getDisplayStateById(int32_t displayId,DisplayState * state)383 ScopedAStatus EvsEnumerator::getDisplayStateById(int32_t displayId, DisplayState* state) {
384 LOG(DEBUG) << __FUNCTION__;
385 return getDisplayStateImpl(displayId, state);
386 }
387
getDisplayStateImpl(std::optional<int32_t> displayId,DisplayState * state)388 ScopedAStatus EvsEnumerator::getDisplayStateImpl(std::optional<int32_t> displayId,
389 DisplayState* state) {
390 if (!checkPermission()) {
391 *state = DisplayState::DEAD;
392 return ScopedAStatus::fromServiceSpecificError(
393 static_cast<int>(EvsResult::PERMISSION_DENIED));
394 }
395
396 const auto& all_displays = mutableActiveDisplays().getAllDisplays();
397
398 const auto display_search = displayId ? all_displays.find(*displayId) : all_displays.begin();
399
400 if (display_search == all_displays.end()) {
401 *state = DisplayState::NOT_OPEN;
402 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
403 }
404
405 std::shared_ptr<IEvsDisplay> pActiveDisplay = display_search->second.displayWeak.lock();
406 if (pActiveDisplay) {
407 return pActiveDisplay->getDisplayState(state);
408 } else {
409 *state = DisplayState::NOT_OPEN;
410 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
411 }
412 }
413
getDisplayIdList(std::vector<uint8_t> * list)414 ScopedAStatus EvsEnumerator::getDisplayIdList(std::vector<uint8_t>* list) {
415 std::vector<uint8_t>& output = *list;
416 if (sDisplayPortList.size() > 0) {
417 output.resize(sDisplayPortList.size());
418 unsigned i = 0;
419 output[i++] = mInternalDisplayId & 0xFF;
420 for (const auto& [port, id] : sDisplayPortList) {
421 if (mInternalDisplayId != id) {
422 output[i++] = port;
423 }
424 }
425 }
426
427 return ScopedAStatus::ok();
428 }
429
isHardware(bool * flag)430 ScopedAStatus EvsEnumerator::isHardware(bool* flag) {
431 *flag = true;
432 return ScopedAStatus::ok();
433 }
434
notifyDeviceStatusChange(const std::string_view & deviceName,DeviceStatusType type)435 void EvsEnumerator::notifyDeviceStatusChange(const std::string_view& deviceName,
436 DeviceStatusType type) {
437 std::lock_guard lock(sLock);
438 if (!mCallback) {
439 return;
440 }
441
442 std::vector<DeviceStatus> status{{.id = std::string(deviceName), .status = type}};
443 if (!mCallback->deviceStatusChanged(status).isOk()) {
444 LOG(WARNING) << "Failed to notify a device status change, name = " << deviceName
445 << ", type = " << static_cast<int>(type);
446 }
447 }
448
registerStatusCallback(const std::shared_ptr<IEvsEnumeratorStatusCallback> & callback)449 ScopedAStatus EvsEnumerator::registerStatusCallback(
450 const std::shared_ptr<IEvsEnumeratorStatusCallback>& callback) {
451 std::lock_guard lock(sLock);
452 if (mCallback) {
453 LOG(INFO) << "Replacing an existing device status callback";
454 }
455 mCallback = callback;
456 return ScopedAStatus::ok();
457 }
458
closeCamera_impl(const std::shared_ptr<IEvsCamera> & pCamera,const std::string & cameraId)459 void EvsEnumerator::closeCamera_impl(const std::shared_ptr<IEvsCamera>& pCamera,
460 const std::string& cameraId) {
461 // Find the named camera
462 CameraRecord* pRecord = findCameraById(cameraId);
463
464 // Is the display being destroyed actually the one we think is active?
465 if (!pRecord) {
466 LOG(ERROR) << "Asked to close a camera whose name isn't recognized";
467 } else {
468 std::shared_ptr<EvsCameraBase> pActiveCamera = pRecord->activeInstance.lock();
469 if (!pActiveCamera) {
470 LOG(WARNING) << "Somehow a camera is being destroyed "
471 << "when the enumerator didn't know one existed";
472 } else if (pActiveCamera != pCamera) {
473 // This can happen if the camera was aggressively reopened,
474 // orphaning this previous instance
475 LOG(WARNING) << "Ignoring close of previously orphaned camera "
476 << "- why did a client steal?";
477 } else {
478 // Shutdown the active camera
479 pActiveCamera->shutdown();
480 }
481 }
482
483 return;
484 }
485
findCameraById(const std::string & cameraId)486 EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) {
487 // Find the named camera
488 auto found = sCameraList.find(cameraId);
489 if (found != sCameraList.end()) {
490 // Found a match!
491 return &found->second;
492 }
493
494 // We didn't find a match
495 return nullptr;
496 }
497
popDisplay(int32_t id)498 std::optional<EvsEnumerator::ActiveDisplays::DisplayInfo> EvsEnumerator::ActiveDisplays::popDisplay(
499 int32_t id) {
500 std::lock_guard lck(mMutex);
501 const auto search = mIdToDisplay.find(id);
502 if (search == mIdToDisplay.end()) {
503 return std::nullopt;
504 }
505 const auto display_info = search->second;
506 mIdToDisplay.erase(search);
507 mDisplayToId.erase(display_info.internalDisplayRawAddr);
508 return display_info;
509 }
510
popDisplay(const std::shared_ptr<IEvsDisplay> & display)511 std::optional<EvsEnumerator::ActiveDisplays::DisplayInfo> EvsEnumerator::ActiveDisplays::popDisplay(
512 const std::shared_ptr<IEvsDisplay>& display) {
513 const auto display_ptr_val = reinterpret_cast<uintptr_t>(display.get());
514 std::lock_guard lck(mMutex);
515 const auto display_to_id_search = mDisplayToId.find(display_ptr_val);
516 if (display_to_id_search == mDisplayToId.end()) {
517 LOG(ERROR) << "Unknown display.";
518 return std::nullopt;
519 }
520 const auto id = display_to_id_search->second;
521 const auto id_to_display_search = mIdToDisplay.find(id);
522 mDisplayToId.erase(display_to_id_search);
523 if (id_to_display_search == mIdToDisplay.end()) {
524 LOG(ERROR) << "No correspsonding ID for the display, probably orphaned.";
525 return std::nullopt;
526 }
527 const auto display_info = id_to_display_search->second;
528 mIdToDisplay.erase(id);
529 return display_info;
530 }
531
532 std::unordered_map<int32_t, EvsEnumerator::ActiveDisplays::DisplayInfo>
getAllDisplays()533 EvsEnumerator::ActiveDisplays::getAllDisplays() {
534 std::lock_guard lck(mMutex);
535 auto id_to_display_map_copy = mIdToDisplay;
536 return id_to_display_map_copy;
537 }
538
tryInsert(int32_t id,const std::shared_ptr<EvsGlDisplay> & display)539 bool EvsEnumerator::ActiveDisplays::tryInsert(int32_t id,
540 const std::shared_ptr<EvsGlDisplay>& display) {
541 std::lock_guard lck(mMutex);
542 const auto display_ptr_val = reinterpret_cast<uintptr_t>(display.get());
543
544 auto id_to_display_insert_result =
545 mIdToDisplay.emplace(id, DisplayInfo{
546 .id = id,
547 .displayWeak = display,
548 .internalDisplayRawAddr = display_ptr_val,
549 });
550 if (!id_to_display_insert_result.second) {
551 return false;
552 }
553 auto display_to_id_insert_result = mDisplayToId.emplace(display_ptr_val, id);
554 if (!display_to_id_insert_result.second) {
555 mIdToDisplay.erase(id);
556 return false;
557 }
558 return true;
559 }
560
getUltrasonicsArrayList(std::vector<UltrasonicsArrayDesc> * list)561 ScopedAStatus EvsEnumerator::getUltrasonicsArrayList(
562 [[maybe_unused]] std::vector<UltrasonicsArrayDesc>* list) {
563 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
564 return ScopedAStatus::ok();
565 }
566
openUltrasonicsArray(const std::string & id,std::shared_ptr<IEvsUltrasonicsArray> * obj)567 ScopedAStatus EvsEnumerator::openUltrasonicsArray(
568 [[maybe_unused]] const std::string& id,
569 [[maybe_unused]] std::shared_ptr<IEvsUltrasonicsArray>* obj) {
570 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
571 return ScopedAStatus::ok();
572 }
573
closeUltrasonicsArray(const std::shared_ptr<IEvsUltrasonicsArray> & obj)574 ScopedAStatus EvsEnumerator::closeUltrasonicsArray(
575 [[maybe_unused]] const std::shared_ptr<IEvsUltrasonicsArray>& obj) {
576 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
577 return ScopedAStatus::ok();
578 }
579
580 } // namespace aidl::android::hardware::automotive::evs::implementation
581