1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "MockHidlEvsHal_1_0.h"
18 
19 #include <android-base/logging.h>
20 #include <hardware/gralloc.h>
21 #include <ui/DisplayMode.h>
22 #include <utils/SystemClock.h>
23 
24 #include <functional>
25 #include <future>
26 
27 #include <system/graphics-base.h>
28 
29 namespace {
30 
31 using ::android::hardware::automotive::evs::V1_0::BufferDesc;
32 using ::android::hardware::automotive::evs::V1_0::CameraDesc;
33 using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
34 using ::android::hardware::automotive::evs::V1_0::DisplayState;
35 using ::android::hardware::automotive::evs::V1_0::EvsResult;
36 using ::android::hardware::automotive::evs::V1_0::IEvsCamera;
37 using ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
38 using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
39 using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
40 using ::std::chrono_literals::operator""ms;
41 using ::std::chrono_literals::operator""s;
42 
43 inline constexpr char kMockCameraDeviceNamePrefix[] = "/dev/mockcamera";
44 inline constexpr size_t kMinimumNumBuffers = 2;
45 inline constexpr size_t kMaximumNumBuffers = 10;
46 
47 }  // namespace
48 
49 namespace aidl::android::automotive::evs::implementation {
50 
~MockHidlEvsHal_1_0()51 MockHidlEvsHal_1_0::~MockHidlEvsHal_1_0() {
52     std::lock_guard lock(mLock);
53     for (auto& [id, state] : mStreamState) {
54         auto it = mCameraFrameThread.find(id);
55         if (it == mCameraFrameThread.end() || !it->second.joinable()) {
56             continue;
57         }
58 
59         state = StreamState::kStopping;
60         it->second.join();
61     }
62 
63     deinitializeBufferPoolLocked();
64     mCameraClient.clear();
65 }
66 
getEnumerator()67 ::android::sp<IEvsEnumerator> MockHidlEvsHal_1_0::getEnumerator() {
68     if (!mMockHidlEvsEnumerator) {
69         LOG(ERROR) << "MockHidlEvsHal_1_0 has not initialized yet.";
70         return nullptr;
71     }
72 
73     return mMockHidlEvsEnumerator;
74 }
75 
initialize()76 void MockHidlEvsHal_1_0::initialize() {
77     initializeBufferPool(kMaximumNumBuffers);
78     configureCameras(mNumCameras);
79     configureDisplays(mNumDisplays);
80     configureEnumerator();
81 }
82 
forwardFrames(size_t numberOfFramesToForward,const std::string & deviceId)83 void MockHidlEvsHal_1_0::forwardFrames(size_t numberOfFramesToForward,
84                                        const std::string& deviceId) {
85     std::unique_lock l(mLock);
86     ::android::base::ScopedLockAssertion lock_assertion(mLock);
87     auto it = mStreamState.find(deviceId);
88     if (it != mStreamState.end() && it->second != StreamState::kStopped) {
89         LOG(WARNING) << "A mock video stream is already active.";
90         return;
91     }
92     mStreamState.insert_or_assign(deviceId, StreamState::kRunning);
93 
94     for (size_t count = 0;
95          mStreamState[deviceId] == StreamState::kRunning && count < numberOfFramesToForward;
96          ++count) {
97         if (mBufferPool.empty()) {
98             if (!mBufferAvailableSignal.wait_for(l, /* rel_time= */ 10s, [this]() REQUIRES(mLock) {
99                     // Waiting for a buffer to use.
100                     return !mBufferPool.empty();
101                 })) {
102                 LOG(ERROR) << "Buffer timeout; " << count << "/" << numberOfFramesToForward
103                            << " are sent.";
104                 break;
105             }
106         }
107 
108         auto it = mCameraClient.find(deviceId);
109         if (it == mCameraClient.end() || it->second == nullptr) {
110             LOG(ERROR) << "Failed to forward a frame as no active recipient exists; " << count
111                        << "/" << numberOfFramesToForward << " are sent.";
112             break;
113         }
114 
115         BufferDesc bufferToForward = mBufferPool.back();
116         mBufferPool.pop_back();
117 
118         // Mark a buffer in-use.
119         mBuffersInUse.push_back(bufferToForward);
120         l.unlock();
121 
122         // Forward a duplicated buffer.  This must be done without a lock
123         // because a shared data will be modified in doneWithFrame().
124         it->second->deliverFrame(bufferToForward);
125 
126         LOG(DEBUG) << deviceId << ": " << (count + 1) << "/" << numberOfFramesToForward
127                    << " frames are sent";
128         std::this_thread::sleep_for(33ms);  // 30 frames per seconds
129         l.lock();
130     }
131 
132     if (mStreamState.find(deviceId) != mStreamState.end()) {
133         mStreamState[deviceId] = StreamState::kStopped;
134     }
135 }
136 
initializeBufferPool(size_t requested)137 size_t MockHidlEvsHal_1_0::initializeBufferPool(size_t requested) {
138     std::lock_guard lock(mLock);
139     for (auto count = 0; count < requested; ++count) {
140         AHardwareBuffer_Desc desc = {
141                 .width = 64,
142                 .height = 32,
143                 .layers = 1,
144                 .format = HAL_PIXEL_FORMAT_RGBA_8888,
145                 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
146         };
147         AHardwareBuffer* ahwb;
148         if (AHardwareBuffer_allocate(&desc, &ahwb) != ::android::NO_ERROR) {
149             LOG(ERROR) << "Failed to allocate AHardwareBuffer";
150             return count;
151         }
152 
153         BufferDesc aBuffer = {
154                 .width = desc.width,
155                 .height = desc.height,
156                 .stride = 256,  // 4 bytes per pixel.
157                 .pixelSize = 4,
158                 .format = desc.format,
159                 .usage = static_cast<uint32_t>(desc.usage),
160                 .bufferId = static_cast<uint32_t>(count),
161                 .memHandle = AHardwareBuffer_getNativeHandle(ahwb),
162         };
163         mBufferRecord.insert_or_assign(count, ahwb);
164         mBufferPool.push_back(std::move(aBuffer));
165     }
166 
167     return mBufferPool.size();
168 }
169 
deinitializeBufferPoolLocked()170 void MockHidlEvsHal_1_0::deinitializeBufferPoolLocked() {
171     for (auto&& descriptor : mBuffersInUse) {
172         auto it = mBufferRecord.find(descriptor.bufferId);
173         if (it == mBufferRecord.end()) {
174             LOG(WARNING) << "Ignoring unknown buffer id, " << descriptor.bufferId;
175         } else {
176             LOG(WARNING) << "Releasing buffer in use, id = " << descriptor.bufferId;
177             AHardwareBuffer_release(it->second);
178             mBufferRecord.erase(it);
179         }
180     }
181 
182     for (auto&& descriptor : mBufferPool) {
183         auto it = mBufferRecord.find(descriptor.bufferId);
184         if (it == mBufferRecord.end()) {
185             LOG(WARNING) << "Ignoring unknown buffer id, " << descriptor.bufferId;
186         } else {
187             AHardwareBuffer_release(it->second);
188             mBufferRecord.erase(it);
189         }
190     }
191 
192     mBuffersInUse.clear();
193     mBufferPool.clear();
194 }
195 
configureCameras(size_t n)196 void MockHidlEvsHal_1_0::configureCameras(size_t n) {
197     // Initializes a list of the camera parameters each mock camera
198     // supports with their default values.
199     for (auto i = 0; i < n; ++i) {
200         (void)addMockCameraDevice(kMockCameraDeviceNamePrefix + std::to_string(i));
201     }
202 }
203 
addMockCameraDevice(const std::string & deviceId)204 bool MockHidlEvsHal_1_0::addMockCameraDevice(const std::string& deviceId) {
205     ::android::sp<NiceMockHidlEvsCamera> mockCamera =
206             new (std::nothrow) NiceMockHidlEvsCamera(deviceId);
207 
208     // For the testing purpose, this method will return
209     // EvsResult::INVALID_ARG if the client returns any buffer with
210     // unknown identifier.
211     ON_CALL(*mockCamera, doneWithFrame)
212             .WillByDefault([this](const hidlevs::V1_0::BufferDesc& buffer) {
213                 std::lock_guard lock(mLock);
214                 auto it = std::find_if(mBuffersInUse.begin(), mBuffersInUse.end(),
215                                        [id = buffer.bufferId](const BufferDesc& desc) {
216                                            return id == desc.bufferId;
217                                        });
218                 if (it == mBuffersInUse.end()) {
219                     return ::android::hardware::Void();
220                 }
221 
222                 mBufferPool.push_back(std::move(*it));
223                 mBuffersInUse.erase(it);
224 
225                 return ::android::hardware::Void();
226             });
227 
228     // We return a mock camera descriptor with the metadata but empty vendor
229     // flag.
230     ON_CALL(*mockCamera, getCameraInfo)
231             .WillByDefault([deviceId](MockHidlEvsCamera::getCameraInfo_cb callback) {
232                 hidlevs::V1_0::CameraDesc mockDesc = {
233                         .cameraId = deviceId,
234                         .vendorFlags = 0x0,
235                 };
236 
237                 callback(mockDesc);
238                 return ::android::hardware::Void();
239             });
240 
241     // This method will return a value associated with a given
242     // identifier if exists.
243     ON_CALL(*mockCamera, getExtendedInfo).WillByDefault([this](uint32_t id) {
244         auto it = mCameraExtendedInfo.find(id);
245         if (it == mCameraExtendedInfo.end()) {
246             // A requested information does not exist.
247             return 0;
248         }
249 
250         if (it->second.size() < 4) {
251             // Stored information is in an invalid size.
252             return 0;
253         }
254 
255         int value = *(reinterpret_cast<int32_t*>(it->second.data()));
256         return value;
257     });
258 
259     // This method stores a given vector with id.
260     ON_CALL(*mockCamera, setExtendedInfo).WillByDefault([this](uint32_t id, int32_t v) {
261         ::android::hardware::hidl_vec<uint8_t> value;
262         value.resize(sizeof(v));
263         *(reinterpret_cast<int32_t*>(value.data())) = v;
264         mCameraExtendedInfo.insert_or_assign(id, value);
265         return EvsResult::OK;
266     });
267 
268     // Because EVS HAL does allow multiple camera clients exist, we simply
269     // set the size of the buffer pool.
270     ON_CALL(*mockCamera, setMaxFramesInFlight)
271             .WillByDefault([this, id = mockCamera->getId()](uint32_t bufferCount) {
272                 std::lock_guard l(mLock);
273                 if (bufferCount < kMinimumNumBuffers) {
274                     LOG(WARNING) << "Requested buffer pool size is too small to run a camera; "
275                                     "adjusting the pool size to "
276                                  << kMinimumNumBuffers;
277                     bufferCount = kMinimumNumBuffers;
278                 }
279 
280                 int64_t delta = bufferCount;
281                 auto it = mCameraBufferPoolSize.find(id);
282                 if (it != mCameraBufferPoolSize.end()) {
283                     delta -= it->second;
284                 }
285 
286                 if (delta == 0) {
287                     // No further action required.
288                     return EvsResult::OK;
289                 }
290 
291                 size_t totalSize = mBufferPoolSize + delta;
292                 if (totalSize > kMaximumNumBuffers) {
293                     LOG(ERROR) << "Requested size, " << totalSize << ", exceeds the limitation.";
294                     return EvsResult::INVALID_ARG;
295                 }
296 
297                 mBufferPoolSize = totalSize;
298                 mCameraBufferPoolSize.insert_or_assign(id, bufferCount);
299                 return EvsResult::OK;
300             });
301 
302     // We manage the camera ownership on recency-basis; therefore we simply
303     // replace the client in this method.
304     ON_CALL(*mockCamera, startVideoStream)
305             .WillByDefault([this, id = mockCamera->getId()](
306                                    const ::android::sp<hidlevs::V1_0::IEvsCameraStream>& cb) {
307                 // TODO(b/235110887): Notifies a camera loss to the current
308                 //                    client.
309                 size_t n = 0;
310                 {
311                     std::lock_guard l(mLock);
312                     mCameraClient.insert_or_assign(id, cb);
313                     n = mNumberOfFramesToSend;
314                 }
315 
316                 std::packaged_task<void(MockHidlEvsHal_1_0*, size_t, const std::string&)> task(
317                         &MockHidlEvsHal_1_0::forwardFrames);
318                 std::thread t(std::move(task), this, /* numberOfFramesForward= */ n, id);
319                 std::lock_guard l(mLock);
320                 mCameraFrameThread.insert_or_assign(id, std::move(t));
321 
322                 return EvsResult::OK;
323             });
324 
325     // We simply drop a current client.
326     ON_CALL(*mockCamera, stopVideoStream).WillByDefault([this, id = mockCamera->getId()]() {
327         ::android::sp<IEvsCameraStream> cb;
328         std::thread threadToJoin;
329         {
330             std::lock_guard l(mLock);
331             auto state = mStreamState.find(id);
332             if (state == mStreamState.end() || state->second != StreamState::kRunning) {
333                 return ::android::hardware::Void();
334             }
335 
336             auto callback = mCameraClient.find(id);
337             if (callback == mCameraClient.end()) {
338                 return ::android::hardware::Void();
339             }
340 
341             cb = callback->second;
342             callback->second = nullptr;
343             state->second = StreamState::kStopping;
344 
345             auto it = mCameraFrameThread.find(id);
346             if (it == mCameraFrameThread.end() || !it->second.joinable()) {
347                 return ::android::hardware::Void();
348             }
349 
350             threadToJoin = std::move(it->second);
351             mCameraFrameThread.erase(it);
352         }
353 
354         if (cb) {
355             cb->deliverFrame({});
356         }
357 
358         // Join a frame-forward thread
359         threadToJoin.join();
360         return ::android::hardware::Void();
361     });
362 
363     std::lock_guard l(mLock);
364     mMockHidlEvsCameras.push_back(std::move(mockCamera));
365     mMockDeviceStatus.insert_or_assign(deviceId, true);
366 
367     return true;
368 }
369 
removeMockCameraDevice(const std::string & deviceId)370 void MockHidlEvsHal_1_0::removeMockCameraDevice(const std::string& deviceId) {
371     std::lock_guard l(mLock);
372     auto it = mMockDeviceStatus.find(deviceId);
373     if (it == mMockDeviceStatus.end()) {
374         // Nothing to do.
375         return;
376     }
377 
378     mMockDeviceStatus[deviceId] = false;
379 }
380 
configureDisplays(size_t n)381 void MockHidlEvsHal_1_0::configureDisplays(size_t n) {
382     // Build mock IEvsDisplcy instances
383     std::vector<::android::sp<NiceMockHidlEvsDisplay>> displays(n);
384 
385     for (auto i = 0; i < n; ++i) {
386         (void)addMockDisplayDevice(i);
387     }
388 }
389 
addMockDisplayDevice(int id)390 bool MockHidlEvsHal_1_0::addMockDisplayDevice(int id) {
391     ::android::sp<NiceMockHidlEvsDisplay> mockDisplay = new (std::nothrow) NiceMockHidlEvsDisplay();
392 
393     ON_CALL(*mockDisplay, getDisplayInfo)
394             .WillByDefault([id](MockHidlEvsDisplay::getDisplayInfo_cb callback) {
395                 DisplayDesc desc = {
396                         .displayId = "MockDisplay" + std::to_string(id),
397                         // For the testing purpose, we put a display id in the vendor
398                         // flag field.
399                         .vendorFlags = static_cast<uint32_t>(id),
400                 };
401 
402                 callback(desc);
403                 return ::android::hardware::Void();
404             });
405 
406     ON_CALL(*mockDisplay, getDisplayState).WillByDefault([this]() { return mCurrentDisplayState; });
407 
408     ON_CALL(*mockDisplay, getTargetBuffer)
409             .WillByDefault([](MockHidlEvsDisplay::getTargetBuffer_cb callback) {
410                 // TODO(b/263438927): implement this method.
411                 callback({});
412                 return ::android::hardware::Void();
413             });
414 
415     ON_CALL(*mockDisplay, returnTargetBufferForDisplay)
416             .WillByDefault([](const hidlevs::V1_0::BufferDesc& in) {
417                 // TODO(b/263438927): implement this method.
418                 (void)in;
419                 return EvsResult::OK;
420             });
421 
422     ON_CALL(*mockDisplay, setDisplayState).WillByDefault([this](DisplayState in) {
423         mCurrentDisplayState = in;
424         return EvsResult::OK;
425     });
426 
427     std::lock_guard l(mLock);
428     mMockHidlEvsDisplays.push_back(std::move(mockDisplay));
429     mMockDeviceStatus.insert_or_assign(std::to_string(id), true);
430 
431     return true;
432 }
433 
removeMockDisplayDevice(int id)434 void MockHidlEvsHal_1_0::removeMockDisplayDevice(int id) {
435     std::lock_guard l(mLock);
436     auto key = std::to_string(id);
437     auto it = mMockDeviceStatus.find(key);
438     if (it == mMockDeviceStatus.end()) {
439         // Nothing to do.
440         return;
441     }
442 
443     mMockDeviceStatus[key] = false;
444 }
445 
setNumberOfFramesToSend(size_t n)446 size_t MockHidlEvsHal_1_0::setNumberOfFramesToSend(size_t n) {
447     std::lock_guard l(mLock);
448     return mNumberOfFramesToSend = n;
449 }
450 
configureEnumerator()451 void MockHidlEvsHal_1_0::configureEnumerator() {
452     ::android::sp<NiceMockHidlEvsEnumerator_1_0> mockEnumerator =
453             new (std::nothrow) NiceMockHidlEvsEnumerator_1_0();
454 
455     ON_CALL(*mockEnumerator, closeCamera)
456             .WillByDefault([this](const ::android::sp<hidlevs::V1_0::IEvsCamera>& handle) {
457                 ::android::sp<IEvsCamera> c = IEvsCamera::castFrom(handle);
458                 CameraDesc desc;
459                 c->getCameraInfo([&desc](auto& read) { desc = read; });
460 
461                 std::lock_guard l(mLock);
462                 auto it = mCameraBufferPoolSize.find(desc.cameraId);
463                 if (it == mCameraBufferPoolSize.end()) {
464                     // Safely ignore a request if we fail to find a corresponding mock
465                     // camera.
466                     return ::android::hardware::Void();
467                 }
468 
469                 mBufferPoolSize -= it->second;
470                 if (mBufferPoolSize < 0) {
471                     LOG(WARNING) << "mBuffeRPoolSize should not have a negative value, "
472                                  << mBufferPoolSize;
473                     mBufferPoolSize = 0;
474                 }
475                 mCameraBufferPoolSize.insert_or_assign(desc.cameraId, 0);
476                 return ::android::hardware::Void();
477             });
478 
479     ON_CALL(*mockEnumerator, closeDisplay)
480             .WillByDefault([this]([[maybe_unused]] const ::android::sp<hidlevs::V1_0::IEvsDisplay>&
481                                           displayObj) {
482                 auto pActiveDisplay = mActiveDisplay.promote();
483                 if (!pActiveDisplay) {
484                     LOG(WARNING) << "Got a request to close a display already destroyed.";
485                 }
486 
487                 // Nothing else to do.
488                 return ::android::hardware::Void();
489             });
490 
491     ON_CALL(*mockEnumerator, getCameraList)
492             .WillByDefault([this](MockHidlEvsEnumerator_1_0::getCameraList_cb callback) {
493                 ::android::hardware::hidl_vec<hidlevs::V1_0::CameraDesc> list(
494                         mMockHidlEvsCameras.size());
495 
496                 for (auto i = 0; i < mMockHidlEvsCameras.size(); ++i) {
497                     mMockHidlEvsCameras[i]->getCameraInfo([&](auto& desc) { list[i] = desc; });
498 
499                     // Inserts a camera record if it does not exist.
500                     if (mCameraList.find(list[i].cameraId) == mCameraList.end()) {
501                         mCameraList.insert_or_assign(list[i].cameraId, list[i]);
502                     }
503                 }
504 
505                 callback(list);
506                 return ::android::hardware::Void();
507             });
508 
509     ON_CALL(*mockEnumerator, getDisplayState).WillByDefault([this]() {
510         return mCurrentDisplayState;
511     });
512 
513     ON_CALL(*mockEnumerator, openCamera)
514             .WillByDefault([this](const ::android::hardware::hidl_string& id)
515                                    -> ::android::sp<hidlevs::V1_0::IEvsCamera> {
516                 auto it = std::find_if(mMockHidlEvsCameras.begin(), mMockHidlEvsCameras.end(),
517                                        [id](const ::android::sp<NiceMockHidlEvsCamera>& c) {
518                                            hidlevs::V1_0::CameraDesc desc;
519                                            c->getCameraInfo([&desc](auto& read) { desc = read; });
520                                            return desc.cameraId == id;
521                                        });
522 
523                 if (it == mMockHidlEvsCameras.end()) {
524                     return nullptr;
525                 }
526 
527                 auto instance = mCameraList.find(id);  // Guaranteed to exist always.
528                 instance->second.activeInstance = *it;
529                 return *it;
530             });
531 
532     ON_CALL(*mockEnumerator, openDisplay).WillByDefault([this]() -> ::android::sp<IEvsDisplay> {
533         // This method returns the first display always.
534         if (mMockHidlEvsDisplays.empty()) {
535             return nullptr;
536         }
537 
538         mActiveDisplay = mMockHidlEvsDisplays[0];
539         mCurrentDisplayState = DisplayState::NOT_VISIBLE;
540         return mMockHidlEvsDisplays[0];
541     });
542 
543     mMockHidlEvsEnumerator = std::move(mockEnumerator);
544 }
545 
546 }  // namespace aidl::android::automotive::evs::implementation
547