1 /*
2  * Copyright (C) 2023 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 "EvsCamera.h"
18 
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 
22 #include <cstdint>
23 #include <unordered_set>
24 #include <vector>
25 
26 namespace aidl::android::hardware::automotive::evs::implementation {
27 
28 class EvsCameraForTest : public EvsCamera {
29   public:
30     using EvsCamera::increaseAvailableFrames_unsafe;
31     using EvsCamera::returnBuffer_unsafe;
32     using EvsCamera::useBuffer_unsafe;
33 
~EvsCameraForTest()34     ~EvsCameraForTest() override { shutdown(); }
35 
allocateOneFrame(buffer_handle_t * handle)36     ::android::status_t allocateOneFrame(buffer_handle_t* handle) override {
37         static std::intptr_t handle_cnt = 0;
38         *handle = reinterpret_cast<buffer_handle_t>(++handle_cnt);
39         return ::android::OK;
40     }
41 
freeOneFrame(const buffer_handle_t)42     void freeOneFrame(const buffer_handle_t /* handle */) override {
43         // Nothing to free because the handles are fake.
44     }
45 
checkBufferOrder()46     void checkBufferOrder() {
47         for (std::size_t idx = 0; idx < mBuffers.size(); ++idx) {
48             const auto& buffer = mBuffers[idx];
49             EXPECT_EQ(idx < mFramesInUse, buffer.inUse);
50             EXPECT_EQ(idx < mAvailableFrames, buffer.handle != nullptr);
51             EXPECT_LE(mFramesInUse, mAvailableFrames);
52         }
53     }
54 
55     MOCK_METHOD(::ndk::ScopedAStatus, forcePrimaryClient,
56                 (const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>&
57                          in_display),
58                 (override));
59     MOCK_METHOD(::ndk::ScopedAStatus, getCameraInfo,
60                 (::aidl::android::hardware::automotive::evs::CameraDesc * _aidl_return),
61                 (override));
62     MOCK_METHOD(::ndk::ScopedAStatus, getExtendedInfo,
63                 (int32_t in_opaqueIdentifier, std::vector<uint8_t>* _aidl_return), (override));
64     MOCK_METHOD(::ndk::ScopedAStatus, getIntParameter,
65                 (::aidl::android::hardware::automotive::evs::CameraParam in_id,
66                  std::vector<int32_t>* _aidl_return),
67                 (override));
68     MOCK_METHOD(::ndk::ScopedAStatus, getIntParameterRange,
69                 (::aidl::android::hardware::automotive::evs::CameraParam in_id,
70                  ::aidl::android::hardware::automotive::evs::ParameterRange* _aidl_return),
71                 (override));
72     MOCK_METHOD(::ndk::ScopedAStatus, getParameterList,
73                 (std::vector<::aidl::android::hardware::automotive::evs::CameraParam> *
74                  _aidl_return),
75                 (override));
76     MOCK_METHOD(::ndk::ScopedAStatus, getPhysicalCameraInfo,
77                 (const std::string& in_deviceId,
78                  ::aidl::android::hardware::automotive::evs::CameraDesc* _aidl_return),
79                 (override));
80     MOCK_METHOD(::ndk::ScopedAStatus, setExtendedInfo,
81                 (int32_t in_opaqueIdentifier, const std::vector<uint8_t>& in_opaqueValue),
82                 (override));
83     MOCK_METHOD(::ndk::ScopedAStatus, setIntParameter,
84                 (::aidl::android::hardware::automotive::evs::CameraParam in_id, int32_t in_value,
85                  std::vector<int32_t>* _aidl_return),
86                 (override));
87     MOCK_METHOD(::ndk::ScopedAStatus, setPrimaryClient, (), (override));
88     MOCK_METHOD(::ndk::ScopedAStatus, unsetPrimaryClient, (), (override));
89     MOCK_METHOD(bool, startVideoStreamImpl_locked,
90                 (const std::shared_ptr<evs::IEvsCameraStream>& receiver, ndk::ScopedAStatus& status,
91                  std::unique_lock<std::mutex>& lck),
92                 (override));
93     MOCK_METHOD(bool, stopVideoStreamImpl_locked,
94                 (ndk::ScopedAStatus & status, std::unique_lock<std::mutex>& lck), (override));
95 };
96 
TEST(EvsCameraBufferTest,ChangeBufferPoolSize)97 TEST(EvsCameraBufferTest, ChangeBufferPoolSize) {
98     auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
99     EXPECT_TRUE(evsCam->setMaxFramesInFlight(100).isOk());
100     evsCam->checkBufferOrder();
101     EXPECT_TRUE(evsCam->setMaxFramesInFlight(50).isOk());
102     evsCam->checkBufferOrder();
103 
104     // 2 buffers in use.
105     const auto [id1, handle1] = evsCam->useBuffer_unsafe();
106     const auto [id2, handle2] = evsCam->useBuffer_unsafe();
107     std::ignore = evsCam->useBuffer_unsafe();
108 
109     // It allows you to set the buffer pool size to 1, but it will keep the space for the in use
110     // buffers.
111     EXPECT_TRUE(evsCam->setMaxFramesInFlight(1).isOk());
112     evsCam->checkBufferOrder();
113 
114     evsCam->returnBuffer_unsafe(id1);
115     evsCam->checkBufferOrder();
116     evsCam->returnBuffer_unsafe(id2);
117     evsCam->checkBufferOrder();
118 }
119 
TEST(EvsCameraBufferTest,UseAndReturn)120 TEST(EvsCameraBufferTest, UseAndReturn) {
121     constexpr std::size_t kNumOfHandles = 20;
122     auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
123 
124     // Our "fake handles" of this test case is 1 to kNumOfHandles.
125     for (std::size_t i = 1; i <= kNumOfHandles; ++i) {
126         evsCam->increaseAvailableFrames_unsafe(reinterpret_cast<buffer_handle_t>(i));
127     }
128     evsCam->checkBufferOrder();
129 
130     {
131         std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
132         std::unordered_set<std::size_t> inUseIDs;
133         std::unordered_set<std::intptr_t> inUseHandles;
134         for (std::size_t i = 0; i < kNumOfHandles; ++i) {
135             const auto [id, handle] = evsCam->useBuffer_unsafe();
136             const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
137             EXPECT_TRUE(EvsCamera::IsBufferIDValid(id));
138             EXPECT_NE(handle, nullptr);
139             EXPECT_LT(id, kNumOfHandles);
140 
141             // handleInt must be between [1, kNumOfHandles] as we "allocated" above.
142             EXPECT_LT(0u, handleInt);
143             EXPECT_LE(handleInt, kNumOfHandles);
144 
145             inUseIDHandlePairs.push_back({id, handleInt});
146             EXPECT_TRUE(inUseIDs.insert(id).second);
147             EXPECT_TRUE(inUseHandles.insert(handleInt).second);
148             evsCam->checkBufferOrder();
149         }
150         // Return buffers in the order of acquiring.
151         for (const auto [id, handleInt] : inUseIDHandlePairs) {
152             evsCam->returnBuffer_unsafe(id);
153             evsCam->checkBufferOrder();
154         }
155     }
156 
157     {
158         std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
159         std::unordered_set<std::size_t> inUseIDs;
160         std::unordered_set<std::intptr_t> inUseHandles;
161         for (std::size_t i = 0; i < kNumOfHandles; ++i) {
162             const auto [id, handle] = evsCam->useBuffer_unsafe();
163             const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
164             EXPECT_TRUE(EvsCamera::IsBufferIDValid(id));
165             EXPECT_NE(handle, nullptr);
166             EXPECT_LT(id, kNumOfHandles);
167 
168             // handleInt must be between [1, kNumOfHandles] as we "allocated" above.
169             EXPECT_LT(0u, handleInt);
170             EXPECT_LE(handleInt, kNumOfHandles);
171 
172             inUseIDHandlePairs.push_back({id, handleInt});
173             EXPECT_TRUE(inUseIDs.insert(id).second);
174             EXPECT_TRUE(inUseHandles.insert(handleInt).second);
175             evsCam->checkBufferOrder();
176         }
177         // Return buffers in the reverse order of acquiring.
178         std::reverse(inUseIDHandlePairs.begin(), inUseIDHandlePairs.end());
179         for (const auto [id, handleInt] : inUseIDHandlePairs) {
180             evsCam->returnBuffer_unsafe(id);
181             evsCam->checkBufferOrder();
182         }
183     }
184 
185     {
186         // Making sure the handles are still in [1, kNumOfHandles] and IDs are still [0,
187         // kNumOfHandles). The mapping may be different, though.
188         std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
189         std::unordered_set<std::size_t> inUseIDs;
190         std::unordered_set<std::intptr_t> inUseHandles;
191         for (std::size_t i = 0; i < kNumOfHandles; ++i) {
192             const auto [id, handle] = evsCam->useBuffer_unsafe();
193             const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
194             EXPECT_TRUE(EvsCamera::IsBufferIDValid(id));
195             EXPECT_NE(handle, nullptr);
196             EXPECT_LT(id, kNumOfHandles);
197 
198             // handleInt must be between [1, kNumOfHandles] as we "allocated" above.
199             EXPECT_LT(0u, handleInt);
200             EXPECT_LE(handleInt, kNumOfHandles);
201 
202             inUseIDHandlePairs.push_back({id, handleInt});
203             EXPECT_TRUE(inUseIDs.insert(id).second);
204             EXPECT_TRUE(inUseHandles.insert(handleInt).second);
205             evsCam->checkBufferOrder();
206         }
207     }
208 }
209 
210 }  // namespace aidl::android::hardware::automotive::evs::implementation
211