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