1 /*
2 * Copyright 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 "MockHidlEvsHal.h"
18
19 #include "Constants.h"
20
21 #include <android-base/logging.h>
22 #include <camera/CameraMetadata.h>
23 #include <hardware/gralloc.h>
24 #include <ui/DisplayMode.h>
25 #include <utils/SystemClock.h>
26
27 #include <functional>
28 #include <future>
29
30 #include <system/graphics-base.h>
31
32 namespace {
33
34 using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
35 using ::android::hardware::automotive::evs::V1_0::DisplayState;
36 using ::android::hardware::automotive::evs::V1_0::EvsResult;
37 using ::android::hardware::automotive::evs::V1_1::BufferDesc;
38 using ::android::hardware::automotive::evs::V1_1::CameraDesc;
39 using ::android::hardware::automotive::evs::V1_1::CameraParam;
40 using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
41 using ::android::hardware::automotive::evs::V1_1::EvsEventType;
42 using ::android::hardware::automotive::evs::V1_1::IEvsCamera;
43 using ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
44 using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
45 using ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
46 using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray;
47 using ::android::hardware::camera::device::V3_2::Stream;
48 using ::std::chrono_literals::operator""ms;
49 using ::std::chrono_literals::operator""s;
50
51 inline constexpr char kMockCameraDeviceNamePrefix[] = "/dev/mockcamera";
52 inline constexpr int32_t kCameraParamDefaultMinValue = -255;
53 inline constexpr int32_t kCameraParamDefaultMaxValue = 255;
54 inline constexpr int32_t kCameraParamDefaultStepValue = 3;
55 inline constexpr size_t kMinimumNumBuffers = 2;
56 inline constexpr size_t kMaximumNumBuffers = 10;
57
58 } // namespace
59
60 namespace aidl::android::automotive::evs::implementation {
61
~MockHidlEvsHal()62 MockHidlEvsHal::~MockHidlEvsHal() {
63 std::lock_guard lock(mLock);
64 for (auto& [id, state] : mStreamState) {
65 auto it = mCameraFrameThread.find(id);
66 if (it == mCameraFrameThread.end() || !it->second.joinable()) {
67 continue;
68 }
69
70 state = StreamState::kStopping;
71 it->second.join();
72 }
73
74 deinitializeBufferPoolLocked();
75 mCameraClient.clear();
76 }
77
getEnumerator()78 ::android::sp<IEvsEnumerator> MockHidlEvsHal::getEnumerator() {
79 if (!mMockHidlEvsEnumerator) {
80 LOG(ERROR) << "MockHidlEvsHal has not initialized yet.";
81 return nullptr;
82 }
83
84 return mMockHidlEvsEnumerator;
85 }
86
initialize()87 void MockHidlEvsHal::initialize() {
88 initializeBufferPool(kMaximumNumBuffers);
89 configureCameras(mNumCameras);
90 configureDisplays(mNumDisplays);
91 configureEnumerator();
92 }
93
buildCameraMetadata(int32_t width,int32_t height,int32_t format,::android::hardware::hidl_vec<uint8_t> * out)94 bool MockHidlEvsHal::buildCameraMetadata(int32_t width, int32_t height, int32_t format,
95 ::android::hardware::hidl_vec<uint8_t>* out) {
96 ::android::CameraMetadata metadata;
97
98 const std::vector<int32_t> availableStreamConfigurations =
99 {format, width, height, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT};
100
101 metadata.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
102 availableStreamConfigurations.data(), availableStreamConfigurations.size());
103
104 camera_metadata_t* p = metadata.release();
105 if (validate_camera_metadata_structure(p, /* expected_size= */ nullptr) != ::android::OK) {
106 LOG(ERROR) << "Failed to build a camera metadata.";
107 return false;
108 }
109
110 size_t n = get_camera_metadata_size(p);
111 out->resize(n);
112 memcpy(out->data(), p, n);
113
114 return true;
115 }
116
forwardFrames(size_t numberOfFramesToForward,const std::string & deviceId)117 void MockHidlEvsHal::forwardFrames(size_t numberOfFramesToForward, const std::string& deviceId) {
118 std::unique_lock l(mLock);
119 ::android::base::ScopedLockAssertion lock_assertion(mLock);
120 auto it = mStreamState.find(deviceId);
121 if (it != mStreamState.end() && it->second != StreamState::kStopped) {
122 LOG(WARNING) << "A mock video stream is already active.";
123 return;
124 }
125 mStreamState.insert_or_assign(deviceId, StreamState::kRunning);
126
127 for (size_t count = 0;
128 mStreamState[deviceId] == StreamState::kRunning && count < numberOfFramesToForward;
129 ++count) {
130 if (mBufferPool.empty()) {
131 if (!mBufferAvailableSignal.wait_for(l, /* rel_time= */ 10s, [this]() REQUIRES(mLock) {
132 // Waiting for a buffer to use.
133 return !mBufferPool.empty();
134 })) {
135 LOG(ERROR) << "Buffer timeout; " << count << "/" << numberOfFramesToForward
136 << " are sent.";
137 break;
138 }
139 }
140
141 auto it = mCameraClient.find(deviceId);
142 if (it == mCameraClient.end() || it->second == nullptr) {
143 LOG(ERROR) << "Failed to forward a frame as no active recipient exists; " << count
144 << "/" << numberOfFramesToForward << " are sent.";
145 break;
146 }
147
148 BufferDesc bufferToForward = mBufferPool.back();
149 mBufferPool.pop_back();
150
151 bufferToForward.timestamp = static_cast<int64_t>(::android::elapsedRealtimeNano() * 1e+3);
152 bufferToForward.deviceId = deviceId;
153
154 // Mark a buffer in-use.
155 mBuffersInUse.push_back(bufferToForward);
156 l.unlock();
157
158 // Forward a duplicated buffer. This must be done without a lock
159 // because a shared data will be modified in doneWithFrame().
160 ::android::hardware::hidl_vec<BufferDesc> packet;
161 packet.resize(1);
162 packet[0] = bufferToForward;
163 it->second->deliverFrame_1_1(packet);
164
165 LOG(DEBUG) << deviceId << ": " << (count + 1) << "/" << numberOfFramesToForward
166 << " frames are sent";
167 std::this_thread::sleep_for(33ms); // 30 frames per seconds
168 l.lock();
169 }
170
171 if (mStreamState.find(deviceId) != mStreamState.end()) {
172 mStreamState[deviceId] = StreamState::kStopped;
173 }
174 }
175
initializeBufferPool(size_t requested)176 size_t MockHidlEvsHal::initializeBufferPool(size_t requested) {
177 std::lock_guard lock(mLock);
178 for (auto count = 0; count < requested; ++count) {
179 AHardwareBuffer_Desc desc = {
180 .width = 64,
181 .height = 32,
182 .layers = 1,
183 .format = HAL_PIXEL_FORMAT_RGBA_8888,
184 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
185 };
186 AHardwareBuffer* ahwb;
187 if (AHardwareBuffer_allocate(&desc, &ahwb) != ::android::NO_ERROR) {
188 LOG(ERROR) << "Failed to allocate AHardwareBuffer";
189 return count;
190 }
191 buffer_handle_t memHandle = AHardwareBuffer_getNativeHandle(ahwb);
192 BufferDesc aBuffer = {
193 .buffer =
194 {
195 .nativeHandle = memHandle,
196 },
197 .pixelSize = 4,
198 .bufferId = static_cast<uint32_t>(count),
199 .deviceId = "Mock EvsCamera",
200 };
201
202 *(reinterpret_cast<AHardwareBuffer_Desc*>(&aBuffer.buffer.description)) = desc;
203 mBufferRecord.insert_or_assign(count, ahwb);
204 mBufferPool.push_back(std::move(aBuffer));
205 }
206
207 return mBufferPool.size();
208 }
209
deinitializeBufferPoolLocked()210 void MockHidlEvsHal::deinitializeBufferPoolLocked() {
211 for (auto&& descriptor : mBuffersInUse) {
212 auto it = mBufferRecord.find(descriptor.bufferId);
213 if (it == mBufferRecord.end()) {
214 LOG(WARNING) << "Ignoring unknown buffer id, " << descriptor.bufferId;
215 } else {
216 LOG(WARNING) << "Releasing buffer in use, id = " << descriptor.bufferId;
217 AHardwareBuffer_release(it->second);
218 mBufferRecord.erase(it);
219 }
220 }
221
222 for (auto&& descriptor : mBufferPool) {
223 auto it = mBufferRecord.find(descriptor.bufferId);
224 if (it == mBufferRecord.end()) {
225 LOG(WARNING) << "Ignoring unknown buffer id, " << descriptor.bufferId;
226 } else {
227 AHardwareBuffer_release(it->second);
228 mBufferRecord.erase(it);
229 }
230 }
231
232 mBuffersInUse.clear();
233 mBufferPool.clear();
234 }
235
configureCameras(size_t n)236 void MockHidlEvsHal::configureCameras(size_t n) {
237 // Initializes a list of the camera parameters each mock camera
238 // supports with their default values.
239 mCameraParams = {{CameraParam::BRIGHTNESS, 80},
240 {CameraParam::CONTRAST, 60},
241 {CameraParam::AUTOGAIN, 3},
242 {CameraParam::AUTO_EXPOSURE, 1}};
243
244 for (auto i = 0; i < n; ++i) {
245 (void)addMockCameraDevice(kMockCameraDeviceNamePrefix + std::to_string(i));
246 }
247 }
248
addMockCameraDevice(const std::string & deviceId)249 bool MockHidlEvsHal::addMockCameraDevice(const std::string& deviceId) {
250 ::android::sp<NiceMockHidlEvsCamera> mockCamera =
251 new (std::nothrow) NiceMockHidlEvsCamera(deviceId);
252
253 // For the testing purpose, this method will return
254 // EvsResult::INVALID_ARG if the client returns any buffer with
255 // unknown identifier.
256 ON_CALL(*mockCamera, doneWithFrame)
257 .WillByDefault([this](const hidlevs::V1_0::BufferDesc& buffer) {
258 std::lock_guard lock(mLock);
259 auto it = std::find_if(mBuffersInUse.begin(), mBuffersInUse.end(),
260 [id = buffer.bufferId](const BufferDesc& desc) {
261 return id == desc.bufferId;
262 });
263 if (it == mBuffersInUse.end()) {
264 return ::android::hardware::Void();
265 }
266
267 mBufferPool.push_back(std::move(*it));
268 mBuffersInUse.erase(it);
269
270 return ::android::hardware::Void();
271 });
272
273 ON_CALL(*mockCamera, doneWithFrame_1_1)
274 .WillByDefault([this](const ::android::hardware::hidl_vec<BufferDesc>& buffers) {
275 size_t returned = 0;
276 std::lock_guard lock(mLock);
277 for (auto& b : buffers) {
278 auto it = std::find_if(mBuffersInUse.begin(), mBuffersInUse.end(),
279 [id = b.bufferId](const BufferDesc& desc) {
280 return id == desc.bufferId;
281 });
282 if (it == mBuffersInUse.end()) {
283 continue;
284 }
285
286 ++returned;
287 mBufferPool.push_back(std::move(*it));
288 mBuffersInUse.erase(it);
289 }
290
291 if (returned > 0) {
292 mBufferAvailableSignal.notify_all();
293 return EvsResult::OK;
294 } else {
295 return EvsResult::INVALID_ARG;
296 }
297 });
298
299 // EVS HAL accepts only a single client; therefore, this method
300 // returns a success always.
301 ON_CALL(*mockCamera, forceMaster)
302 .WillByDefault(
303 [](const ::android::sp<hidlevs::V1_0::IEvsDisplay>&) { return EvsResult::OK; });
304
305 // We return a mock camera descriptor with the metadata but empty vendor
306 // flag.
307 ON_CALL(*mockCamera, getCameraInfo)
308 .WillByDefault([deviceId](MockHidlEvsCamera::getCameraInfo_cb callback) {
309 hidlevs::V1_0::CameraDesc mockDesc = {
310 .cameraId = deviceId,
311 .vendorFlags = 0x0,
312 };
313
314 callback(mockDesc);
315 return ::android::hardware::Void();
316 });
317
318 ON_CALL(*mockCamera, getCameraInfo_1_1)
319 .WillByDefault([deviceId, this](MockHidlEvsCamera::getCameraInfo_1_1_cb callback) {
320 CameraDesc mockDesc = {
321 .v1 =
322 {
323 .cameraId = deviceId,
324 .vendorFlags = 0x0,
325 },
326 .metadata = {},
327 };
328
329 if (!buildCameraMetadata(/* width= */ 640, /* height= */ 480,
330 /* format= */ HAL_PIXEL_FORMAT_RGBA_8888,
331 &mockDesc.metadata)) {
332 return ::android::hardware::Void();
333 }
334
335 callback(mockDesc);
336 return ::android::hardware::Void();
337 });
338
339 // This method will return a value associated with a given
340 // identifier if exists.
341 ON_CALL(*mockCamera, getExtendedInfo).WillByDefault([this](uint32_t id) {
342 auto it = mCameraExtendedInfo.find(id);
343 if (it == mCameraExtendedInfo.end()) {
344 // A requested information does not exist.
345 return 0;
346 }
347
348 if (it->second.size() < 4) {
349 // Stored information is in an invalid size.
350 return 0;
351 }
352
353 int value = *(reinterpret_cast<int32_t*>(it->second.data()));
354 return value;
355 });
356
357 ON_CALL(*mockCamera, getExtendedInfo_1_1)
358 .WillByDefault([this](uint32_t id, MockHidlEvsCamera::getExtendedInfo_1_1_cb callback) {
359 auto it = mCameraExtendedInfo.find(id);
360 if (it == mCameraExtendedInfo.end()) {
361 // A requested information does not exist.
362 callback(EvsResult::INVALID_ARG, 0);
363 return ::android::hardware::Void();
364 }
365
366 ::android::hardware::hidl_vec<uint8_t> value = it->second;
367 callback(EvsResult::OK, value);
368 return ::android::hardware::Void();
369 });
370
371 // This method will return a value of a requested camera parameter
372 // if it is supported by a mock EVS camera.
373 ON_CALL(*mockCamera, getIntParameter)
374 .WillByDefault([this](CameraParam id, MockHidlEvsCamera::getIntParameter_cb callback) {
375 auto it = mCameraParams.find(id);
376 if (it == mCameraParams.end()) {
377 LOG(ERROR) << "Ignore a request to read an unsupported parameter, " << (int)id;
378 callback(EvsResult::INVALID_ARG, 0);
379 return ::android::hardware::Void();
380 }
381
382 // EVS HAL always returns a single integer value.
383 ::android::hardware::hidl_vec<int32_t> values;
384 values.resize(1);
385 values[0] = it->second;
386 callback(EvsResult::OK, values);
387 return ::android::hardware::Void();
388 });
389
390 // This method returns the same range values if a requested camera
391 // parameter is supported by a mock EVS camera.
392 ON_CALL(*mockCamera, getIntParameterRange)
393 .WillByDefault(
394 [this](CameraParam id, MockHidlEvsCamera::getIntParameterRange_cb callback) {
395 auto it = mCameraParams.find(id);
396 if (it == mCameraParams.end()) {
397 callback(0, 0, 0);
398 return ::android::hardware::Void();
399 }
400
401 // For the testing purpose, this mock EVS HAL always returns the
402 // same values.
403 callback(kCameraParamDefaultMinValue, kCameraParamDefaultMaxValue,
404 kCameraParamDefaultStepValue);
405 return ::android::hardware::Void();
406 });
407
408 // This method returns a list of camera parameters supported by a
409 // mock EVS camera.
410 ON_CALL(*mockCamera, getParameterList)
411 .WillByDefault([this](MockHidlEvsCamera::getParameterList_cb callback) {
412 ::android::hardware::hidl_vec<CameraParam> list;
413 list.resize(mCameraParams.size());
414 unsigned idx = 0;
415 for (auto& [k, _] : mCameraParams) {
416 list[idx++] = k;
417 }
418
419 callback(list);
420 return ::android::hardware::Void();
421 });
422
423 // This method behaves exactly the same as getCameraInfo() because
424 // the EVS HAL does not support a concept of the group (or logical)
425 // camera.
426 ON_CALL(*mockCamera, getPhysicalCameraInfo)
427 .WillByDefault([deviceId]([[maybe_unused]] const ::android::hardware::hidl_string& id,
428 MockHidlEvsCamera::getPhysicalCameraInfo_cb callback) {
429 CameraDesc mockDesc = {
430 .v1 =
431 {
432 .cameraId = deviceId,
433 .vendorFlags = 0x0,
434 },
435 .metadata = {},
436 };
437
438 callback(mockDesc);
439 return ::android::hardware::Void();
440 });
441
442 // This method adds given buffer descriptors to the internal buffer
443 // pool if their identifiers do not conflict to existing ones.
444 ON_CALL(*mockCamera, importExternalBuffers)
445 .WillByDefault([this](const ::android::hardware::hidl_vec<BufferDesc>& buffers,
446 MockHidlEvsCamera::importExternalBuffers_cb callback) {
447 std::lock_guard l(mLock);
448 size_t count = 0;
449 for (auto i = 0; i < buffers.size(); ++i) {
450 auto it = std::find_if(mBufferPool.begin(), mBufferPool.end(),
451 [&](const BufferDesc& b) {
452 return b.bufferId == buffers[i].bufferId;
453 });
454 if (it != mBufferPool.end()) {
455 // Ignores external buffers with a conflicting
456 // identifier.
457 continue;
458 }
459
460 // TODO(b/235110887): Add external buffers to the pool.
461 //
462 // Temporarily, we count the number of buffers that
463 // identifiers do not conflict with existing buffers.
464 ++count;
465 }
466
467 callback(EvsResult::OK, count);
468 return ::android::hardware::Void();
469 });
470
471 ON_CALL(*mockCamera, pauseVideoStream).WillByDefault([]() {
472 return EvsResult::UNDERLYING_SERVICE_ERROR;
473 });
474
475 ON_CALL(*mockCamera, resumeVideoStream).WillByDefault([]() {
476 return EvsResult::UNDERLYING_SERVICE_ERROR;
477 });
478
479 // This method stores a given vector with id.
480 ON_CALL(*mockCamera, setExtendedInfo).WillByDefault([this](uint32_t id, int32_t v) {
481 ::android::hardware::hidl_vec<uint8_t> value;
482 value.resize(sizeof(v));
483 *(reinterpret_cast<int32_t*>(value.data())) = v;
484 mCameraExtendedInfo.insert_or_assign(id, value);
485 return EvsResult::OK;
486 });
487
488 ON_CALL(*mockCamera, setExtendedInfo_1_1)
489 .WillByDefault([this](uint32_t id, const ::android::hardware::hidl_vec<uint8_t>& v) {
490 mCameraExtendedInfo.insert_or_assign(id, v);
491 return EvsResult::OK;
492 });
493
494 // This method updates a parameter value if exists.
495 ON_CALL(*mockCamera, setIntParameter)
496 .WillByDefault([this](CameraParam id, int32_t in,
497 MockHidlEvsCamera::setIntParameter_cb callback) {
498 auto it = mCameraParams.find(id);
499 if (it == mCameraParams.end()) {
500 LOG(ERROR) << "Ignore a request to program an unsupported parameter, "
501 << (int)id;
502 callback(EvsResult::INVALID_ARG, {});
503 return ::android::hardware::Void();
504 }
505
506 in = in > kCameraParamDefaultMaxValue ? kCameraParamDefaultMaxValue
507 : in < kCameraParamDefaultMinValue ? kCameraParamDefaultMinValue
508 : in;
509 mCameraParams.insert_or_assign(id, in);
510 ::android::hardware::hidl_vec<int32_t> values;
511 values.resize(1);
512 values[0] = in;
513 callback(EvsResult::OK, values);
514 return ::android::hardware::Void();
515 });
516
517 // We always return a success because EVS HAL does not allow
518 // multiple camera clients exist.
519 ON_CALL(*mockCamera, setMaster).WillByDefault([]() { return EvsResult::OK; });
520
521 // Because EVS HAL does allow multiple camera clients exist, we simply
522 // set the size of the buffer pool.
523 ON_CALL(*mockCamera, setMaxFramesInFlight)
524 .WillByDefault([this, id = mockCamera->getId()](uint32_t bufferCount) {
525 std::lock_guard l(mLock);
526 if (bufferCount < kMinimumNumBuffers) {
527 LOG(WARNING) << "Requested buffer pool size is too small to run a camera; "
528 "adjusting the pool size to "
529 << kMinimumNumBuffers;
530 bufferCount = kMinimumNumBuffers;
531 }
532
533 int64_t delta = bufferCount;
534 auto it = mCameraBufferPoolSize.find(id);
535 if (it != mCameraBufferPoolSize.end()) {
536 delta -= it->second;
537 }
538
539 if (!delta) {
540 // No further action required.
541 return EvsResult::OK;
542 }
543
544 size_t totalSize = mBufferPoolSize + delta;
545 if (totalSize > kMaximumNumBuffers) {
546 LOG(ERROR) << "Requested size, " << totalSize << ", exceeds the limitation.";
547 return EvsResult::INVALID_ARG;
548 }
549
550 mBufferPoolSize = totalSize;
551 mCameraBufferPoolSize.insert_or_assign(id, bufferCount);
552 return EvsResult::OK;
553 });
554
555 // We manage the camera ownership on recency-basis; therefore we simply
556 // replace the client in this method.
557 ON_CALL(*mockCamera, startVideoStream)
558 .WillByDefault([this, id = mockCamera->getId()](
559 const ::android::sp<hidlevs::V1_0::IEvsCameraStream>& cb) {
560 // TODO(b/235110887): Notifies a camera loss to the current
561 // client.
562 size_t n = 0;
563 {
564 std::lock_guard l(mLock);
565 auto client = IEvsCameraStream::castFrom(cb).withDefault(nullptr);
566 if (!client) {
567 // This mock implementation supports v1.1 hidl
568 // client only.
569 return EvsResult::INVALID_ARG;
570 }
571 mCameraClient.insert_or_assign(id, client);
572 n = mNumberOfFramesToSend;
573 }
574
575 std::packaged_task<void(MockHidlEvsHal*, size_t, const std::string&)> task(
576 &MockHidlEvsHal::forwardFrames);
577 std::thread t(std::move(task), this, /* numberOfFramesForward= */ n, id);
578 std::lock_guard l(mLock);
579 mCameraFrameThread.insert_or_assign(id, std::move(t));
580
581 return EvsResult::OK;
582 });
583
584 // We simply drop a current client.
585 ON_CALL(*mockCamera, stopVideoStream).WillByDefault([this, id = mockCamera->getId()]() {
586 ::android::sp<IEvsCameraStream> cb;
587 std::thread threadToJoin;
588 {
589 std::lock_guard l(mLock);
590 auto state = mStreamState.find(id);
591 if (state == mStreamState.end() || state->second != StreamState::kRunning) {
592 return ::android::hardware::Void();
593 }
594
595 auto callback = mCameraClient.find(id);
596 if (callback == mCameraClient.end()) {
597 return ::android::hardware::Void();
598 }
599
600 cb = callback->second;
601 callback->second = nullptr;
602 state->second = StreamState::kStopping;
603
604 auto it = mCameraFrameThread.find(id);
605 if (it == mCameraFrameThread.end() || !it->second.joinable()) {
606 return ::android::hardware::Void();
607 }
608
609 threadToJoin = std::move(it->second);
610 mCameraFrameThread.erase(it);
611 }
612
613 if (cb) {
614 EvsEventDesc e = {
615 .aType = EvsEventType::STREAM_STOPPED,
616 .deviceId = id,
617 };
618 cb->notify(e);
619 }
620
621 // Join a frame-forward thread
622 threadToJoin.join();
623 return ::android::hardware::Void();
624 });
625
626 // We don't take any action because EVS HAL allows only a single camera
627 // client exists at a time.
628 ON_CALL(*mockCamera, unsetMaster).WillByDefault([]() { return EvsResult::OK; });
629
630 std::lock_guard l(mLock);
631 mMockHidlEvsCameras.push_back(std::move(mockCamera));
632 mMockDeviceStatus.insert_or_assign(deviceId, true);
633
634 return true;
635 }
636
removeMockCameraDevice(const std::string & deviceId)637 void MockHidlEvsHal::removeMockCameraDevice(const std::string& deviceId) {
638 std::lock_guard l(mLock);
639 auto it = mMockDeviceStatus.find(deviceId);
640 if (it == mMockDeviceStatus.end()) {
641 // Nothing to do.
642 return;
643 }
644
645 mMockDeviceStatus[deviceId] = false;
646 }
647
configureDisplays(size_t n)648 void MockHidlEvsHal::configureDisplays(size_t n) {
649 // Build mock IEvsDisplcy instances
650 std::vector<::android::sp<NiceMockHidlEvsDisplay>> displays(n);
651
652 for (auto i = 0; i < n; ++i) {
653 (void)addMockDisplayDevice(i);
654 }
655 }
656
addMockDisplayDevice(int id)657 bool MockHidlEvsHal::addMockDisplayDevice(int id) {
658 ::android::sp<NiceMockHidlEvsDisplay> mockDisplay = new (std::nothrow) NiceMockHidlEvsDisplay();
659
660 ON_CALL(*mockDisplay, getDisplayInfo)
661 .WillByDefault([id](MockHidlEvsDisplay::getDisplayInfo_cb callback) {
662 DisplayDesc desc = {
663 .displayId = "MockDisplay" + std::to_string(id),
664 // For the testing purpose, we put a display id in the vendor
665 // flag field.
666 .vendorFlags = static_cast<uint32_t>(id),
667 };
668
669 callback(desc);
670 return ::android::hardware::Void();
671 });
672
673 ON_CALL(*mockDisplay, getDisplayInfo_1_1)
674 .WillByDefault([id, this](MockHidlEvsDisplay::getDisplayInfo_1_1_cb callback) {
675 DisplayDesc desc = {
676 .displayId = "MockDisplay" + std::to_string(id),
677 // For the testing purpose, we put a display id in the vendor
678 // flag field.
679 .vendorFlags = static_cast<uint32_t>(id),
680 };
681
682 ::android::hardware::hidl_vec<uint8_t> config;
683 config.resize(sizeof(::android::ui::DisplayMode));
684 ::android::ui::DisplayMode* p =
685 reinterpret_cast<::android::ui::DisplayMode*>(config.data());
686 p->resolution = ::android::ui::Size(64, 32);
687
688 ::android::hardware::hidl_vec<uint8_t> state;
689 state.resize(sizeof(mCurrentDisplayState));
690 *(reinterpret_cast<DisplayState*>(state.data())) = mCurrentDisplayState;
691
692 callback(config, state);
693 return ::android::hardware::Void();
694 });
695
696 ON_CALL(*mockDisplay, getDisplayState).WillByDefault([this]() { return mCurrentDisplayState; });
697
698 ON_CALL(*mockDisplay, getTargetBuffer)
699 .WillByDefault([](MockHidlEvsDisplay::getTargetBuffer_cb callback) {
700 // TODO(b/263438927): implement this method.
701 callback({});
702 return ::android::hardware::Void();
703 });
704
705 ON_CALL(*mockDisplay, returnTargetBufferForDisplay)
706 .WillByDefault([](const hidlevs::V1_0::BufferDesc& in) {
707 // TODO(b/263438927): implement this method.
708 (void)in;
709 return EvsResult::OK;
710 });
711
712 ON_CALL(*mockDisplay, setDisplayState).WillByDefault([this](DisplayState in) {
713 mCurrentDisplayState = in;
714 return EvsResult::OK;
715 });
716
717 std::lock_guard l(mLock);
718 mMockHidlEvsDisplays.push_back(std::move(mockDisplay));
719 mMockDeviceStatus.insert_or_assign(std::to_string(id), true);
720
721 return true;
722 }
723
removeMockDisplayDevice(int id)724 void MockHidlEvsHal::removeMockDisplayDevice(int id) {
725 std::lock_guard l(mLock);
726 auto key = std::to_string(id);
727 auto it = mMockDeviceStatus.find(key);
728 if (it == mMockDeviceStatus.end()) {
729 // Nothing to do.
730 return;
731 }
732
733 mMockDeviceStatus[key] = false;
734 }
735
setNumberOfFramesToSend(size_t n)736 size_t MockHidlEvsHal::setNumberOfFramesToSend(size_t n) {
737 std::lock_guard l(mLock);
738 return mNumberOfFramesToSend = n;
739 }
740
configureEnumerator()741 void MockHidlEvsHal::configureEnumerator() {
742 ::android::sp<NiceMockHidlEvsEnumerator> mockEnumerator =
743 new (std::nothrow) NiceMockHidlEvsEnumerator();
744
745 ON_CALL(*mockEnumerator, closeCamera)
746 .WillByDefault([this](const ::android::sp<hidlevs::V1_0::IEvsCamera>& handle) {
747 ::android::sp<IEvsCamera> c = IEvsCamera::castFrom(handle);
748 CameraDesc desc;
749 c->getCameraInfo_1_1([&desc](auto& read) { desc = read; });
750
751 std::lock_guard l(mLock);
752 auto it = mCameraBufferPoolSize.find(desc.v1.cameraId);
753 if (it == mCameraBufferPoolSize.end()) {
754 // Safely ignore a request if we fail to find a corresponding mock
755 // camera.
756 return ::android::hardware::Void();
757 }
758
759 mBufferPoolSize -= it->second;
760 if (mBufferPoolSize < 0) {
761 LOG(WARNING) << "mBuffeRPoolSize should not have a negative value, "
762 << mBufferPoolSize;
763 mBufferPoolSize = 0;
764 }
765 mCameraBufferPoolSize.insert_or_assign(desc.v1.cameraId, 0);
766 return ::android::hardware::Void();
767 });
768
769 ON_CALL(*mockEnumerator, closeDisplay)
770 .WillByDefault([this]([[maybe_unused]] const ::android::sp<hidlevs::V1_0::IEvsDisplay>&
771 displayObj) {
772 auto pActiveDisplay = mActiveDisplay.promote();
773 if (!pActiveDisplay) {
774 LOG(WARNING) << "Got a request to close a display already destroyed.";
775 }
776
777 // Nothing else to do.
778 return ::android::hardware::Void();
779 });
780
781 ON_CALL(*mockEnumerator, closeUltrasonicsArray)
782 .WillByDefault([](const ::android::sp<IEvsUltrasonicsArray>&) {
783 // Mock EVS HAL does not support IEvsUltrasonicsArray.
784 return ::android::hardware::Void();
785 });
786
787 ON_CALL(*mockEnumerator, getCameraList)
788 .WillByDefault([this](MockHidlEvsEnumerator::getCameraList_cb callback) {
789 ::android::hardware::hidl_vec<hidlevs::V1_0::CameraDesc> list(
790 mMockHidlEvsCameras.size());
791
792 for (auto i = 0; i < mMockHidlEvsCameras.size(); ++i) {
793 mMockHidlEvsCameras[i]->getCameraInfo([&](auto& desc) { list[i] = desc; });
794
795 // Inserts a camera record if it does not exist.
796 if (mCameraList.find(list[i].cameraId) == mCameraList.end()) {
797 CameraDesc newDevice = {
798 .v1 = list[i],
799 };
800 mCameraList.insert_or_assign(list[i].cameraId, newDevice);
801 }
802 }
803
804 callback(list);
805 return ::android::hardware::Void();
806 });
807
808 ON_CALL(*mockEnumerator, getCameraList_1_1)
809 .WillByDefault([this](MockHidlEvsEnumerator::getCameraList_1_1_cb callback) {
810 std::vector<CameraDesc> list(mMockHidlEvsCameras.size());
811
812 for (auto i = 0; i < mMockHidlEvsCameras.size(); ++i) {
813 mMockHidlEvsCameras[i]->getCameraInfo_1_1([&](auto& desc) { list[i] = desc; });
814
815 // Inserts a camera record if it does not exist.
816 if (mCameraList.find(list[i].v1.cameraId) == mCameraList.end()) {
817 mCameraList.insert_or_assign(list[i].v1.cameraId, list[i]);
818 }
819 }
820
821 callback(list);
822 return ::android::hardware::Void();
823 });
824
825 ON_CALL(*mockEnumerator, getDisplayIdList)
826 .WillByDefault([this](MockHidlEvsEnumerator::getDisplayIdList_cb callback) {
827 ::android::hardware::hidl_vec<uint8_t> list;
828 list.resize(mMockHidlEvsDisplays.size());
829
830 for (auto i = 0; i < mMockHidlEvsDisplays.size(); ++i) {
831 mMockHidlEvsDisplays[i]->getDisplayInfo([&](auto& desc) {
832 // MockHidlEvsDisplay contains a display ID in its vendor flags.
833 list[i] = desc.vendorFlags;
834 });
835 }
836
837 callback(list);
838 return ::android::hardware::Void();
839 });
840
841 ON_CALL(*mockEnumerator, getDisplayState).WillByDefault([this]() {
842 return mCurrentDisplayState;
843 });
844
845 ON_CALL(*mockEnumerator, getUltrasonicsArrayList)
846 .WillByDefault([]([[maybe_unused]] MockHidlEvsEnumerator::getUltrasonicsArrayList_cb
847 callback) {
848 // Mock EVS HAL does not support IEvsUltrasonicsArray yet.
849 return ::android::hardware::Void();
850 });
851
852 ON_CALL(*mockEnumerator, isHardware).WillByDefault([]() { return false; });
853
854 ON_CALL(*mockEnumerator, openCamera)
855 .WillByDefault([this](const ::android::hardware::hidl_string& id)
856 -> ::android::sp<hidlevs::V1_0::IEvsCamera> {
857 auto it = std::find_if(mMockHidlEvsCameras.begin(), mMockHidlEvsCameras.end(),
858 [id](const ::android::sp<NiceMockHidlEvsCamera>& c) {
859 hidlevs::V1_0::CameraDesc desc;
860 c->getCameraInfo([&desc](auto& read) { desc = read; });
861 return desc.cameraId == id;
862 });
863
864 if (it == mMockHidlEvsCameras.end()) {
865 return nullptr;
866 }
867
868 auto instance = mCameraList.find(id); // Guaranteed to exist always.
869 instance->second.activeInstance = *it;
870 return *it;
871 });
872
873 ON_CALL(*mockEnumerator, openCamera_1_1)
874 .WillByDefault(
875 [this](const ::android::hardware::hidl_string& id,
876 [[maybe_unused]] const Stream& config) -> ::android::sp<IEvsCamera> {
877 auto it =
878 std::find_if(mMockHidlEvsCameras.begin(), mMockHidlEvsCameras.end(),
879 [id](const ::android::sp<NiceMockHidlEvsCamera>& c) {
880 CameraDesc desc;
881 c->getCameraInfo_1_1(
882 [&desc](auto& read) { desc = read; });
883 return desc.v1.cameraId == id;
884 });
885
886 if (it == mMockHidlEvsCameras.end()) {
887 return nullptr;
888 }
889
890 auto instance = mCameraList.find(id); // Guaranteed to exist always.
891 instance->second.activeInstance = *it;
892 return *it;
893 });
894
895 ON_CALL(*mockEnumerator, openDisplay).WillByDefault([]() {
896 // TODO(b/263438927): implement this method.
897 return nullptr;
898 });
899
900 ON_CALL(*mockEnumerator, openDisplay_1_1)
901 .WillByDefault([this](uint8_t id) -> ::android::sp<IEvsDisplay> {
902 if (id == kExclusiveDisplayId) {
903 if (mDisplayOwnedExclusively && !mActiveDisplay.promote()) {
904 return nullptr;
905 }
906
907 DisplayDesc desc;
908 mMockHidlEvsDisplays[0]->getDisplayInfo([&desc](auto& read) { desc = read; });
909 id = desc.vendorFlags; // the first display in the list is
910 // the main display.
911 mDisplayOwnedExclusively = true;
912 }
913
914 auto it = std::find_if(mMockHidlEvsDisplays.begin(), mMockHidlEvsDisplays.end(),
915 [id](const ::android::sp<NiceMockHidlEvsDisplay>& d) {
916 DisplayDesc desc;
917 d->getDisplayInfo([&desc](auto& read) { desc = read; });
918 return desc.vendorFlags == id;
919 });
920
921 if (it == mMockHidlEvsDisplays.end()) {
922 return nullptr;
923 }
924
925 mActiveDisplay = *it;
926 mCurrentDisplayState = DisplayState::NOT_VISIBLE;
927 return *it;
928 });
929
930 ON_CALL(*mockEnumerator, openUltrasonicsArray)
931 .WillByDefault([]([[maybe_unused]] const ::android::hardware::hidl_string& id) {
932 // Mock EVS HAL does not support IEvsUltrasonicsArray yet.
933 return nullptr;
934 });
935
936 mMockHidlEvsEnumerator = std::move(mockEnumerator);
937 }
938
939 } // namespace aidl::android::automotive::evs::implementation
940