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