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