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