1 /*
2 * Copyright (C) 2019 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 #define LOG_TAG "StreamBufferCacheManagerTests"
18 #include <cutils/properties.h>
19 #include <gtest/gtest.h>
20 #include <log/log.h>
21
22 #include <chrono>
23 #include <map>
24 #include <string>
25 #include <thread>
26 #include <unordered_set>
27 #include <vector>
28
29 #include "stream_buffer_cache_manager.h"
30
31 namespace android {
32 namespace google_camera_hal {
33
34 using namespace std::chrono_literals;
35
36 class StreamBufferCacheManagerTests : public ::testing::Test {
37 protected:
38 // This is used to mock the framework callback latency
39 static constexpr auto kAllocateBufferFuncLatency = 10ms;
40 // The minimum interval two successful buffer acquisition must have, this
41 // should be close to kAllocateBufferFuncLatency, but leave a safe gap(1ms)
42 // in case of timing fluctuation.
43 static constexpr auto kBufferAcquireMinLatency = 9ms;
44 // The maximum latency that the cached buffer is returned to the framework
45 static constexpr auto kBufferReturnMaxLatency = 5ms;
46 static const uint32_t kDefaultRemainingFulfillment = 2;
47
AllocateBufferFunc(uint32_t num_buffer,std::vector<StreamBuffer> * buffers,StreamBufferRequestError * status)48 status_t AllocateBufferFunc(uint32_t num_buffer,
49 std::vector<StreamBuffer>* buffers,
50 StreamBufferRequestError* status) {
51 *status = StreamBufferRequestError::kOk;
52 buffers->clear();
53 if (remaining_number_of_fulfillment_ != 0) {
54 buffers->resize(num_buffer);
55 } else {
56 *status = StreamBufferRequestError::kStreamDisconnected;
57 return OK;
58 }
59
60 // Mocking the framework callback latency
61 std::this_thread::sleep_for(kAllocateBufferFuncLatency);
62 remaining_number_of_fulfillment_--;
63 return OK;
64 }
65
ReturnBufferFunc(const std::vector<StreamBuffer> &)66 status_t ReturnBufferFunc(const std::vector<StreamBuffer>& /*buffers*/) {
67 num_return_buffer_func_called++;
68 return OK;
69 }
70
71 const StreamBufferCacheRegInfo kTestCacheRegInfo{
72 .request_func =
73 [this](uint32_t num_buffer, std::vector<StreamBuffer>* buffers,
__anon388cceac0102() 74 StreamBufferRequestError* status) {
75 return this->AllocateBufferFunc(num_buffer, buffers, status);
76 },
77 .return_func =
__anon388cceac0202() 78 [this](const std::vector<StreamBuffer>& buffers) {
79 return this->ReturnBufferFunc(buffers);
80 },
81 .stream_id = 1,
82 .width = 640,
83 .height = 480,
84 .format = HAL_PIXEL_FORMAT_RAW10,
85 .producer_flags = 0,
86 .consumer_flags = 0,
87 .num_buffers_to_cache = 1};
88
SetUp()89 void SetUp() override {
90 // Skip test if product is unsupported.
91 char product_name[PROPERTY_VALUE_MAX];
92 // TODO(b/142732212): Flacky occurred,
93 // Remove "blueline", "crosshatch", "flame", "coral"
94 // from supported_product_list first.
95 std::unordered_set<std::string> const supported_product_list{""};
96 property_get("ro.build.product", product_name, "");
97 bool product_support_test =
98 supported_product_list.find(std::string{product_name}) !=
99 supported_product_list.end();
100 if (!product_support_test) {
101 GTEST_SKIP();
102 }
103 hal_buffer_managed_stream_ids_.insert(kTestCacheRegInfo.stream_id);
104 cache_manager_ =
105 StreamBufferCacheManager::Create(hal_buffer_managed_stream_ids_);
106 ASSERT_NE(cache_manager_, nullptr)
107 << " Creating StreamBufferCacheManager failed";
108 }
109
110 // Set remaining_number_of_fulfillment_. This should be called before any
111 // other operations if the test needs to control this.
SetRemainingFulfillment(uint32_t remaining_num)112 void SetRemainingFulfillment(uint32_t remaining_num) {
113 remaining_number_of_fulfillment_ = remaining_num;
114 }
115
116 // StreamBufferCacheManager created by this test fixture
117 std::unique_ptr<StreamBufferCacheManager> cache_manager_;
118
119 // Counts the total number of buffers acquired by each stream id
120 std::map<int32_t, uint32_t> buffer_allocation_cnt_;
121
122 // Counts the total number of buffers returned by each stream id
123 std::map<int32_t, uint32_t> buffer_return_cnt_;
124
125 // Max number of requests that AllocateBufferFunc can fulfill. This is used to
126 // mock the failure of buffer provider from the framework.
127 uint32_t remaining_number_of_fulfillment_ = kDefaultRemainingFulfillment;
128
129 // Number of times the ReturnBufferFunc is called.
130 int32_t num_return_buffer_func_called = 0;
131
132 // Set of hal buffer managed stream ids
133 std::set<int32_t> hal_buffer_managed_stream_ids_;
134 };
135
136 // Test RegisterStream
TEST_F(StreamBufferCacheManagerTests,RegisterStream)137 TEST_F(StreamBufferCacheManagerTests, RegisterStream) {
138 // RegisterStream should succeed
139 status_t res = cache_manager_->RegisterStream(kTestCacheRegInfo);
140 ASSERT_EQ(res, OK) << " RegisterStream failed!" << strerror(res);
141
142 // RegisterStream should fail when registering the same stream twice
143 res = cache_manager_->RegisterStream(kTestCacheRegInfo);
144 ASSERT_NE(res, OK) << " RegisterStream succeeded when registering the same "
145 "stream for more than once!";
146
147 // RegisterStream should succeed when registering another stream
148 StreamBufferCacheRegInfo another_reg_info = kTestCacheRegInfo;
149 another_reg_info.stream_id = kTestCacheRegInfo.stream_id + 1;
150 res = cache_manager_->RegisterStream(another_reg_info);
151 ASSERT_EQ(res, OK) << " RegisterStream another stream failed!"
152 << strerror(res);
153 }
154
155 // Test NotifyProviderReadiness
TEST_F(StreamBufferCacheManagerTests,NotifyProviderReadiness)156 TEST_F(StreamBufferCacheManagerTests, NotifyProviderReadiness) {
157 // Need to register stream before notifying provider readiness
158 status_t res =
159 cache_manager_->NotifyProviderReadiness(kTestCacheRegInfo.stream_id);
160 ASSERT_NE(res, OK) << " NotifyProviderReadiness succeeded without reigstering"
161 " the stream.";
162
163 res = cache_manager_->RegisterStream(kTestCacheRegInfo);
164 ASSERT_EQ(res, OK) << " RegisterStream failed!" << strerror(res);
165
166 // Notify ProviderReadiness should succeed after the stream is registered
167 res = cache_manager_->NotifyProviderReadiness(kTestCacheRegInfo.stream_id);
168 ASSERT_EQ(res, OK) << " NotifyProviderReadiness failed!" << strerror(res);
169 }
170
171 // Test the correct order of calling GetStreamBuffer
TEST_F(StreamBufferCacheManagerTests,BasicGetStreamBuffer)172 TEST_F(StreamBufferCacheManagerTests, BasicGetStreamBuffer) {
173 StreamBufferRequestResult req_result;
174 // GetStreamBuffer should fail before the stream is registered.
175 status_t res =
176 cache_manager_->GetStreamBuffer(kTestCacheRegInfo.stream_id, &req_result);
177 ASSERT_NE(res, OK) << " GetStreamBuffer should fail before stream is "
178 "registered and provider readiness is notified.";
179
180 res = cache_manager_->RegisterStream(kTestCacheRegInfo);
181 ASSERT_EQ(res, OK) << " RegisterStream failed!" << strerror(res);
182
183 // GetStreamBuffer should fail before the stream's provider is notified for
184 // readiness.
185 res =
186 cache_manager_->GetStreamBuffer(kTestCacheRegInfo.stream_id, &req_result);
187 ASSERT_NE(res, OK) << " GetStreamBuffer should fail before stream is "
188 "registered and provider readiness is notified.";
189
190 res = cache_manager_->NotifyProviderReadiness(kTestCacheRegInfo.stream_id);
191 ASSERT_EQ(res, OK) << " NotifyProviderReadiness failed!" << strerror(res);
192
193 // GetStreamBuffer should succeed after the stream is registered and its
194 // provider's readiness is notified.
195 res =
196 cache_manager_->GetStreamBuffer(kTestCacheRegInfo.stream_id, &req_result);
197 ASSERT_EQ(res, OK) << " Getting stream buffer failed!" << strerror(res);
198 }
199
200 // Test sequence of function call to GetStreamBuffer
TEST_F(StreamBufferCacheManagerTests,SequenceOfGetStreamBuffer)201 TEST_F(StreamBufferCacheManagerTests, SequenceOfGetStreamBuffer) {
202 const uint32_t kValidBufferRequests = 2;
203 SetRemainingFulfillment(kValidBufferRequests);
204 status_t res = cache_manager_->RegisterStream(kTestCacheRegInfo);
205 ASSERT_EQ(res, OK) << " RegisterStream failed!" << strerror(res);
206
207 res = cache_manager_->NotifyProviderReadiness(kTestCacheRegInfo.stream_id);
208 ASSERT_EQ(res, OK) << " NotifyProviderReadiness failed!" << strerror(res);
209
210 // Allow enough time for the buffer allocator to refill the cache
211 std::this_thread::sleep_for(kAllocateBufferFuncLatency);
212
213 // First GetStreamBuffer should succeed immediately with a non-placeholder buffer
214 StreamBufferRequestResult req_result;
215 auto t_start = std::chrono::high_resolution_clock::now();
216 res =
217 cache_manager_->GetStreamBuffer(kTestCacheRegInfo.stream_id, &req_result);
218 auto t_end = std::chrono::high_resolution_clock::now();
219 ASSERT_EQ(res, OK) << " GetStreamBuffer failed!" << strerror(res);
220 ASSERT_EQ(true, t_end - t_start < kBufferAcquireMinLatency)
221 << " First buffer request should be fulfilled immediately.";
222 ASSERT_EQ(req_result.is_placeholder_buffer, false)
223 << " First buffer request got placeholder buffer.";
224
225 // Second GetStreamBuffer should succeed with a non-placeholder buffer, but
226 // should happen after a gap longer than kBufferAcquireMinLatency.
227 t_start = std::chrono::high_resolution_clock::now();
228 res =
229 cache_manager_->GetStreamBuffer(kTestCacheRegInfo.stream_id, &req_result);
230 t_end = std::chrono::high_resolution_clock::now();
231 ASSERT_EQ(res, OK) << " GetStreamBuffer failed!" << strerror(res);
232 ASSERT_EQ(true, t_end - t_start > kBufferAcquireMinLatency)
233 << " Buffer acquisition gap between two consecutive reqs is too small.";
234 ASSERT_EQ(req_result.is_placeholder_buffer, false)
235 << " Second buffer request got placeholder buffer.";
236
237 // Allow enough time for the buffer allocator to refill the cache
238 std::this_thread::sleep_for(kAllocateBufferFuncLatency);
239 // No more remaining fulfilment so StreamBufferCache should be either deactive
240 // or inactive.
241 bool is_active = false;
242 res = cache_manager_->IsStreamActive(kTestCacheRegInfo.stream_id, &is_active);
243 ASSERT_EQ(res, OK) << " IsStreamActive failed!" << strerror(res);
244 ASSERT_EQ(is_active, false)
245 << " StreamBufferCache should be either deactive or inactive!";
246
247 // Third GetStreamBuffer should succeed with a placeholder buffer immediately
248 t_start = std::chrono::high_resolution_clock::now();
249 res =
250 cache_manager_->GetStreamBuffer(kTestCacheRegInfo.stream_id, &req_result);
251 t_end = std::chrono::high_resolution_clock::now();
252 ASSERT_EQ(res, OK) << " GetStreamBuffer failed!" << strerror(res);
253 ASSERT_EQ(true, t_end - t_start < kBufferAcquireMinLatency)
254 << " Buffer acquisition gap for a placeholder return should be "
255 "negligible.";
256 ASSERT_EQ(req_result.is_placeholder_buffer, true)
257 << " Third buffer request did not get placeholder buffer.";
258 }
259
260 // Test NotifyFlushingAll
TEST_F(StreamBufferCacheManagerTests,NotifyFlushingAll)261 TEST_F(StreamBufferCacheManagerTests, NotifyFlushingAll) {
262 // One before the first GetStreamBuffer. One after that. One for the
263 // GetStreamBuffer happens after the NotifyFlushingAll.
264 const uint32_t kValidBufferRequests = 3;
265 SetRemainingFulfillment(kValidBufferRequests);
266 status_t res = cache_manager_->RegisterStream(kTestCacheRegInfo);
267 ASSERT_EQ(res, OK) << " RegisterStream failed!" << strerror(res);
268
269 res = cache_manager_->NotifyProviderReadiness(kTestCacheRegInfo.stream_id);
270 ASSERT_EQ(res, OK) << " NotifyProviderReadiness failed!" << strerror(res);
271
272 // Allow enough time for the buffer allocator to refill the cache
273 std::this_thread::sleep_for(kAllocateBufferFuncLatency);
274
275 // First GetStreamBuffer should succeed immediately with a non-placeholder buffer
276 StreamBufferRequestResult req_result;
277 auto t_start = std::chrono::high_resolution_clock::now();
278 res =
279 cache_manager_->GetStreamBuffer(kTestCacheRegInfo.stream_id, &req_result);
280 auto t_end = std::chrono::high_resolution_clock::now();
281 ASSERT_EQ(res, OK) << " GetStreamBuffer failed!" << strerror(res);
282 ASSERT_EQ(true, t_end - t_start < kBufferAcquireMinLatency)
283 << " First buffer request should be fulfilled immediately.";
284 ASSERT_EQ(req_result.is_placeholder_buffer, false)
285 << " First buffer request got placeholder buffer.";
286
287 // Allow enough time for the buffer allocator to refill the cache
288 std::this_thread::sleep_for(kAllocateBufferFuncLatency);
289 // NotifyFlushingAll should succeed
290 ASSERT_EQ(num_return_buffer_func_called, 0)
291 << " ReturnBufferFunc should not be called before NotifyFlushingAll!";
292 res = cache_manager_->NotifyFlushingAll();
293 ASSERT_EQ(res, OK) << " NotifyFlushingAll failed!" << strerror(res);
294 std::this_thread::sleep_for(kBufferReturnMaxLatency);
295 ASSERT_EQ(num_return_buffer_func_called, 1)
296 << " ReturnBufferFunc was not called after NotifyFlushingAll is invoked!";
297
298 // GetStreamBuffer should still be able to re-trigger cache to refill after
299 // NotifyFlushingAll is called.
300 res =
301 cache_manager_->GetStreamBuffer(kTestCacheRegInfo.stream_id, &req_result);
302 ASSERT_EQ(res, OK) << " GetStreamBuffer failed!" << strerror(res);
303 ASSERT_EQ(req_result.is_placeholder_buffer, false)
304 << " Buffer request got placeholder buffer.";
305 }
306
307 // Test IsStreamActive
TEST_F(StreamBufferCacheManagerTests,IsStreamActive)308 TEST_F(StreamBufferCacheManagerTests, IsStreamActive) {
309 const uint32_t kValidBufferRequests = 1;
310 SetRemainingFulfillment(kValidBufferRequests);
311 status_t res = cache_manager_->RegisterStream(kTestCacheRegInfo);
312 ASSERT_EQ(res, OK) << " RegisterStream failed!" << strerror(res);
313
314 res = cache_manager_->NotifyProviderReadiness(kTestCacheRegInfo.stream_id);
315 ASSERT_EQ(res, OK) << " NotifyProviderReadiness failed!" << strerror(res);
316
317 // Allow enough time for the buffer allocator to refill the cache
318 std::this_thread::sleep_for(kAllocateBufferFuncLatency);
319
320 // StreamBufferCache should be valid before placeholder buffer is used.
321 bool is_active = false;
322 res = cache_manager_->IsStreamActive(kTestCacheRegInfo.stream_id, &is_active);
323 ASSERT_EQ(res, OK) << " IsStreamActive failed!" << strerror(res);
324 ASSERT_EQ(is_active, true) << " StreamBufferCache should be active!";
325
326 StreamBufferRequestResult req_result;
327 res =
328 cache_manager_->GetStreamBuffer(kTestCacheRegInfo.stream_id, &req_result);
329
330 // Allow enough time for buffer provider to finish its job
331 std::this_thread::sleep_for(kAllocateBufferFuncLatency);
332 // There is only one valid buffer request. So the stream will be deactive
333 // after the GetStreamBuffer(when the cache tries the second buffer request).
334 res = cache_manager_->IsStreamActive(kTestCacheRegInfo.stream_id, &is_active);
335 ASSERT_EQ(res, OK) << " IsStreamActive failed!" << strerror(res);
336 ASSERT_EQ(is_active, false) << " StreamBufferCache should be deactived!";
337 }
338
339 } // namespace google_camera_hal
340 } // namespace android
341