1 #include <base/logging.h>
2 #include <gtest/gtest.h>
3 #include <poll.h>
4
5 #include <android/hardware_buffer.h>
6
7 #include <algorithm>
8 #include <set>
9 #include <thread>
10 #include <vector>
11
12 #include <dvr/dvr_deleter.h>
13 #include <dvr/dvr_display_manager.h>
14 #include <dvr/dvr_surface.h>
15
16 #include <pdx/status.h>
17
18 using android::pdx::ErrorStatus;
19 using android::pdx::Status;
20
21 namespace android {
22 namespace dvr {
23
24 namespace {
25
GetAttribute(DvrSurfaceAttributeKey key,bool value)26 DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, bool value) {
27 DvrSurfaceAttribute attribute;
28 attribute.key = key;
29 attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
30 attribute.value.bool_value = value;
31 return attribute;
32 }
33
GetAttribute(DvrSurfaceAttributeKey key,int32_t value)34 DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, int32_t value) {
35 DvrSurfaceAttribute attribute;
36 attribute.key = key;
37 attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
38 attribute.value.bool_value = value;
39 return attribute;
40 }
41
CreateApplicationSurface(bool visible=false,int32_t z_order=0)42 Status<UniqueDvrSurface> CreateApplicationSurface(bool visible = false,
43 int32_t z_order = 0) {
44 DvrSurface* surface = nullptr;
45 DvrSurfaceAttribute attributes[] = {
46 GetAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
47 GetAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
48
49 const int ret = dvrSurfaceCreate(
50 attributes, std::extent<decltype(attributes)>::value, &surface);
51 if (ret < 0)
52 return ErrorStatus(-ret);
53 else
54 return {UniqueDvrSurface(surface)};
55 }
56
CreateSurfaceQueue(const UniqueDvrSurface & surface,uint32_t width,uint32_t height,uint32_t format,uint32_t layer_count,uint64_t usage,size_t capacity)57 Status<UniqueDvrWriteBufferQueue> CreateSurfaceQueue(
58 const UniqueDvrSurface& surface, uint32_t width, uint32_t height,
59 uint32_t format, uint32_t layer_count, uint64_t usage, size_t capacity) {
60 DvrWriteBufferQueue* queue;
61 const int ret =
62 dvrSurfaceCreateWriteBufferQueue(surface.get(), width, height, format,
63 layer_count, usage, capacity, &queue);
64 if (ret < 0)
65 return ErrorStatus(-ret);
66 else
67 return {UniqueDvrWriteBufferQueue(queue)};
68 }
69
70 class TestDisplayManager {
71 public:
TestDisplayManager(UniqueDvrDisplayManager display_manager,UniqueDvrSurfaceState surface_state)72 TestDisplayManager(UniqueDvrDisplayManager display_manager,
73 UniqueDvrSurfaceState surface_state)
74 : display_manager_(std::move(display_manager)),
75 surface_state_(std::move(surface_state)) {
76 const int fd = dvrDisplayManagerGetEventFd(display_manager_.get());
77 LOG_IF(INFO, fd < 0) << "Failed to get event fd: " << strerror(-fd);
78 display_manager_event_fd_ = fd;
79 }
80
GetReadBufferQueue(int surface_id,int queue_id)81 Status<UniqueDvrReadBufferQueue> GetReadBufferQueue(int surface_id,
82 int queue_id) {
83 DvrReadBufferQueue* queue;
84 const int ret = dvrDisplayManagerGetReadBufferQueue(
85 display_manager_.get(), surface_id, queue_id, &queue);
86 if (ret < 0)
87 return ErrorStatus(-ret);
88 else
89 return {UniqueDvrReadBufferQueue(queue)};
90 }
91
UpdateSurfaceState()92 Status<void> UpdateSurfaceState() {
93 const int ret = dvrDisplayManagerGetSurfaceState(display_manager_.get(),
94 surface_state_.get());
95 if (ret < 0)
96 return ErrorStatus(-ret);
97 else
98 return {};
99 }
100
WaitForUpdate()101 Status<void> WaitForUpdate() {
102 if (display_manager_event_fd_ < 0)
103 return ErrorStatus(-display_manager_event_fd_);
104
105 const int kTimeoutMs = 10000; // 10s
106 pollfd pfd = {display_manager_event_fd_, POLLIN, 0};
107 const int count = poll(&pfd, 1, kTimeoutMs);
108 if (count < 0)
109 return ErrorStatus(errno);
110 else if (count == 0)
111 return ErrorStatus(ETIMEDOUT);
112
113 int events;
114 const int ret = dvrDisplayManagerTranslateEpollEventMask(
115 display_manager_.get(), pfd.revents, &events);
116 if (ret < 0)
117 return ErrorStatus(-ret);
118 else if (events & POLLIN)
119 return UpdateSurfaceState();
120 else
121 return ErrorStatus(EPROTO);
122 }
123
GetSurfaceCount()124 Status<size_t> GetSurfaceCount() {
125 size_t count = 0;
126 const int ret =
127 dvrSurfaceStateGetSurfaceCount(surface_state_.get(), &count);
128 if (ret < 0)
129 return ErrorStatus(-ret);
130 else
131 return {count};
132 }
133
GetUpdateFlags(size_t surface_index)134 Status<DvrSurfaceUpdateFlags> GetUpdateFlags(size_t surface_index) {
135 DvrSurfaceUpdateFlags update_flags;
136 const int ret = dvrSurfaceStateGetUpdateFlags(surface_state_.get(),
137 surface_index, &update_flags);
138 if (ret < 0)
139 return ErrorStatus(-ret);
140 else
141 return {update_flags};
142 }
143
GetSurfaceId(size_t surface_index)144 Status<int> GetSurfaceId(size_t surface_index) {
145 int surface_id;
146 const int ret = dvrSurfaceStateGetSurfaceId(surface_state_.get(),
147 surface_index, &surface_id);
148 if (ret < 0)
149 return ErrorStatus(-ret);
150 else
151 return {surface_id};
152 }
153
GetProcessId(size_t surface_index)154 Status<int> GetProcessId(size_t surface_index) {
155 int process_id;
156 const int ret = dvrSurfaceStateGetProcessId(surface_state_.get(),
157 surface_index, &process_id);
158 if (ret < 0)
159 return ErrorStatus(-ret);
160 else
161 return {process_id};
162 }
163
GetAttributes(size_t surface_index)164 Status<std::vector<DvrSurfaceAttribute>> GetAttributes(size_t surface_index) {
165 std::vector<DvrSurfaceAttribute> attributes;
166 size_t count = 0;
167 const int ret = dvrSurfaceStateGetAttributeCount(surface_state_.get(),
168 surface_index, &count);
169 if (ret < 0)
170 return ErrorStatus(-ret);
171
172 attributes.resize(count);
173 const ssize_t return_count = dvrSurfaceStateGetAttributes(
174 surface_state_.get(), surface_index, attributes.data(), count);
175 if (return_count < 0)
176 return ErrorStatus(-return_count);
177
178 attributes.resize(return_count);
179 return {std::move(attributes)};
180 }
181
GetQueueIds(size_t surface_index)182 Status<std::vector<int>> GetQueueIds(size_t surface_index) {
183 std::vector<int> queue_ids;
184 size_t count = 0;
185 const int ret = dvrSurfaceStateGetQueueCount(surface_state_.get(),
186 surface_index, &count);
187 if (ret < 0)
188 return ErrorStatus(-ret);
189
190 if (count > 0) {
191 queue_ids.resize(count);
192 const ssize_t return_count = dvrSurfaceStateGetQueueIds(
193 surface_state_.get(), surface_index, queue_ids.data(), count);
194 if (return_count < 0)
195 return ErrorStatus(-return_count);
196
197 queue_ids.resize(return_count);
198 }
199
200 return {std::move(queue_ids)};
201 }
202
203 private:
204 UniqueDvrDisplayManager display_manager_;
205 UniqueDvrSurfaceState surface_state_;
206
207 // Owned by object in display_manager_, do not explicitly close.
208 int display_manager_event_fd_;
209
210 TestDisplayManager(const TestDisplayManager&) = delete;
211 void operator=(const TestDisplayManager&) = delete;
212 };
213
214 class DvrDisplayManagerTest : public ::testing::Test {
215 protected:
SetUp()216 void SetUp() override {
217 int ret;
218 DvrDisplayManager* display_manager;
219 DvrSurfaceState* surface_state;
220
221 ret = dvrDisplayManagerCreate(&display_manager);
222 ASSERT_EQ(0, ret) << "Failed to create display manager client";
223 ASSERT_NE(nullptr, display_manager);
224
225 ret = dvrSurfaceStateCreate(&surface_state);
226 ASSERT_EQ(0, ret) << "Failed to create surface state object";
227 ASSERT_NE(nullptr, surface_state);
228
229 manager_.reset(
230 new TestDisplayManager(UniqueDvrDisplayManager(display_manager),
231 UniqueDvrSurfaceState(surface_state)));
232 }
TearDown()233 void TearDown() override {}
234
235 std::unique_ptr<TestDisplayManager> manager_;
236 };
237
238 // TODO(eieio): Consider moving these somewhere more central because they are
239 // broadly useful.
240
241 template <typename T>
StatusOk(const char * status_expression,const Status<T> & status)242 testing::AssertionResult StatusOk(const char* status_expression,
243 const Status<T>& status) {
244 if (!status.ok()) {
245 return testing::AssertionFailure()
246 << "(" << status_expression
247 << ") expected to indicate success but actually contains error ("
248 << status.error() << ")";
249 } else {
250 return testing::AssertionSuccess();
251 }
252 }
253
254 template <typename T>
StatusError(const char * status_expression,const Status<T> & status)255 testing::AssertionResult StatusError(const char* status_expression,
256 const Status<T>& status) {
257 if (status.ok()) {
258 return testing::AssertionFailure()
259 << "(" << status_expression
260 << ") expected to indicate error but instead indicates success.";
261 } else {
262 return testing::AssertionSuccess();
263 }
264 }
265
266 template <typename T>
StatusHasError(const char * status_expression,const char *,const Status<T> & status,int error_code)267 testing::AssertionResult StatusHasError(const char* status_expression,
268 const char* /*error_code_expression*/,
269 const Status<T>& status,
270 int error_code) {
271 if (status.ok()) {
272 return StatusError(status_expression, status);
273 } else if (status.error() != error_code) {
274 return testing::AssertionFailure()
275 << "(" << status_expression << ") expected to indicate error ("
276 << error_code << ") but actually indicates error (" << status.error()
277 << ")";
278 } else {
279 return testing::AssertionSuccess();
280 }
281 }
282
283 template <typename T, typename U>
StatusHasValue(const char * status_expression,const char *,const Status<T> & status,const U & value)284 testing::AssertionResult StatusHasValue(const char* status_expression,
285 const char* /*value_expression*/,
286 const Status<T>& status,
287 const U& value) {
288 if (!status.ok()) {
289 return StatusOk(status_expression, status);
290 } else if (status.get() != value) {
291 return testing::AssertionFailure()
292 << "(" << status_expression << ") expected to contain value ("
293 << testing::PrintToString(value) << ") but actually contains value ("
294 << testing::PrintToString(status.get()) << ")";
295 } else {
296 return testing::AssertionSuccess();
297 }
298 }
299
300 template <typename T, typename Op>
StatusPred(const char * status_expression,const char * pred_expression,const Status<T> & status,Op pred)301 testing::AssertionResult StatusPred(const char* status_expression,
302 const char* pred_expression,
303 const Status<T>& status, Op pred) {
304 if (!status.ok()) {
305 return StatusOk(status_expression, status);
306 } else if (!pred(status.get())) {
307 return testing::AssertionFailure()
308 << status_expression << " value ("
309 << testing::PrintToString(status.get())
310 << ") failed to pass predicate " << pred_expression;
311 } else {
312 return testing::AssertionSuccess();
313 }
314 }
315
316 #define ASSERT_STATUS_OK(status) ASSERT_PRED_FORMAT1(StatusOk, status)
317 #define ASSERT_STATUS_ERROR(status) ASSERT_PRED_FORMAT1(StatusError, status)
318
319 #define ASSERT_STATUS_ERROR_VALUE(value, status) \
320 ASSERT_PRED_FORMAT2(StatusHasError, status, value)
321
322 #define ASSERT_STATUS_EQ(value, status) \
323 ASSERT_PRED_FORMAT2(StatusHasValue, status, value)
324
325 #define EXPECT_STATUS_OK(status) EXPECT_PRED_FORMAT1(StatusOk, status)
326 #define EXPECT_STATUS_ERROR(status) EXPECT_PRED_FORMAT1(StatusError, status)
327
328 #define EXPECT_STATUS_ERROR_VALUE(value, status) \
329 EXPECT_PRED_FORMAT2(StatusHasError, status, value)
330
331 #define EXPECT_STATUS_EQ(value, status) \
332 EXPECT_PRED_FORMAT2(StatusHasValue, status, value)
333
334 #define EXPECT_STATUS_PRED(pred, status) \
335 EXPECT_PRED_FORMAT2(StatusPred, status, pred)
336
337 #if 0
338 // Verify utility predicate/macro functionality. This section is commented out
339 // because it is designed to fail in some cases to validate the helpers.
340 TEST_F(DvrDisplayManagerTest, ExpectVoid) {
341 Status<void> status_error{ErrorStatus{EINVAL}};
342 Status<void> status_ok{};
343
344 EXPECT_STATUS_ERROR(status_error);
345 EXPECT_STATUS_ERROR(status_ok);
346 EXPECT_STATUS_OK(status_error);
347 EXPECT_STATUS_OK(status_ok);
348
349 EXPECT_STATUS_ERROR_VALUE(EINVAL, status_error);
350 EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_error);
351 EXPECT_STATUS_ERROR_VALUE(EINVAL, status_ok);
352 EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_ok);
353 }
354
355 TEST_F(DvrDisplayManagerTest, ExpectInt) {
356 Status<int> status_error{ErrorStatus{EINVAL}};
357 Status<int> status_ok{10};
358
359 EXPECT_STATUS_ERROR(status_error);
360 EXPECT_STATUS_ERROR(status_ok);
361 EXPECT_STATUS_OK(status_error);
362 EXPECT_STATUS_OK(status_ok);
363
364 EXPECT_STATUS_ERROR_VALUE(EINVAL, status_error);
365 EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_error);
366 EXPECT_STATUS_ERROR_VALUE(EINVAL, status_ok);
367 EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_ok);
368
369 EXPECT_STATUS_EQ(10, status_error);
370 EXPECT_STATUS_EQ(20, status_error);
371 EXPECT_STATUS_EQ(10, status_ok);
372 EXPECT_STATUS_EQ(20, status_ok);
373
374 auto pred1 = [](const auto& value) { return value < 15; };
375 auto pred2 = [](const auto& value) { return value > 5; };
376 auto pred3 = [](const auto& value) { return value > 15; };
377 auto pred4 = [](const auto& value) { return value < 5; };
378
379 EXPECT_STATUS_PRED(pred1, status_error);
380 EXPECT_STATUS_PRED(pred2, status_error);
381 EXPECT_STATUS_PRED(pred3, status_error);
382 EXPECT_STATUS_PRED(pred4, status_error);
383 EXPECT_STATUS_PRED(pred1, status_ok);
384 EXPECT_STATUS_PRED(pred2, status_ok);
385 EXPECT_STATUS_PRED(pred3, status_ok);
386 EXPECT_STATUS_PRED(pred4, status_ok);
387 }
388 #endif
389
TEST_F(DvrDisplayManagerTest,SurfaceCreateEvent)390 TEST_F(DvrDisplayManagerTest, SurfaceCreateEvent) {
391 // Get surface state and verify there are no surfaces.
392 ASSERT_STATUS_OK(manager_->UpdateSurfaceState());
393 ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount());
394
395 // Get flags for invalid surface index.
396 EXPECT_STATUS_ERROR_VALUE(EINVAL, manager_->GetUpdateFlags(0));
397
398 // Create an application surface.
399 auto surface_status = CreateApplicationSurface();
400 ASSERT_STATUS_OK(surface_status);
401 UniqueDvrSurface surface = surface_status.take();
402 ASSERT_NE(nullptr, surface.get());
403
404 const int surface_id = dvrSurfaceGetId(surface.get());
405 ASSERT_GE(surface_id, 0);
406
407 // Now there should be one new surface.
408 ASSERT_STATUS_OK(manager_->WaitForUpdate());
409 EXPECT_STATUS_EQ(1u, manager_->GetSurfaceCount());
410
411 // Verify the new surface flag is set.
412 auto check_flags = [](const auto& value) {
413 return value & DVR_SURFACE_UPDATE_FLAGS_NEW_SURFACE;
414 };
415 EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
416
417 // Verify the surface id matches.
418 EXPECT_STATUS_EQ(surface_id, manager_->GetSurfaceId(0));
419
420 // Verify the owning process of the surface.
421 EXPECT_STATUS_EQ(getpid(), manager_->GetProcessId(0));
422
423 surface.reset();
424
425 ASSERT_STATUS_OK(manager_->WaitForUpdate());
426 EXPECT_STATUS_EQ(0u, manager_->GetSurfaceCount());
427 }
428
TEST_F(DvrDisplayManagerTest,SurfaceAttributeEvent)429 TEST_F(DvrDisplayManagerTest, SurfaceAttributeEvent) {
430 // Get surface state and verify there are no surfaces.
431 ASSERT_STATUS_OK(manager_->UpdateSurfaceState());
432 ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount());
433
434 // Get attributes for an invalid surface index.
435 EXPECT_STATUS_ERROR_VALUE(EINVAL, manager_->GetAttributes(0));
436
437 const bool kInitialVisibility = true;
438 const int32_t kInitialZOrder = 10;
439 auto surface_status =
440 CreateApplicationSurface(kInitialVisibility, kInitialZOrder);
441 ASSERT_STATUS_OK(surface_status);
442 auto surface = surface_status.take();
443 ASSERT_NE(nullptr, surface.get());
444
445 ASSERT_STATUS_OK(manager_->WaitForUpdate());
446 ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
447
448 // Check the initial attribute values.
449 auto attribute_status = manager_->GetAttributes(0);
450 ASSERT_STATUS_OK(attribute_status);
451 auto attributes = attribute_status.take();
452 EXPECT_GE(attributes.size(), 2u);
453
454 const std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
455 DVR_SURFACE_ATTRIBUTE_VISIBLE};
456
457 // Collect all the keys in attributes that match the expected keys.
458 std::set<int32_t> actual_keys;
459 std::for_each(attributes.begin(), attributes.end(),
460 [&expected_keys, &actual_keys](const auto& attribute) {
461 if (expected_keys.find(attribute.key) != expected_keys.end())
462 actual_keys.emplace(attribute.key);
463 });
464
465 // If the sets match then attributes contained at least the expected keys,
466 // even if other keys were also present.
467 EXPECT_EQ(expected_keys, actual_keys);
468 }
469
TEST_F(DvrDisplayManagerTest,SurfaceQueueEvent)470 TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) {
471 // Create an application surface.
472 auto surface_status = CreateApplicationSurface();
473 ASSERT_STATUS_OK(surface_status);
474 UniqueDvrSurface surface = surface_status.take();
475 ASSERT_NE(nullptr, surface.get());
476
477 const int surface_id = dvrSurfaceGetId(surface.get());
478 ASSERT_GE(surface_id, 0);
479 // Get surface state and verify there is one surface.
480 ASSERT_STATUS_OK(manager_->WaitForUpdate());
481 ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
482
483 // Verify there are no queues for the surface recorded in the state snapshot.
484 EXPECT_STATUS_EQ(std::vector<int>{}, manager_->GetQueueIds(0));
485
486 // Create a new queue in the surface.
487 auto write_queue_status = CreateSurfaceQueue(
488 surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 1,
489 AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1);
490 ASSERT_STATUS_OK(write_queue_status);
491 UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
492 ASSERT_NE(nullptr, write_queue.get());
493
494 const int queue_id = dvrWriteBufferQueueGetId(write_queue.get());
495 ASSERT_GE(queue_id, 0);
496
497 // Update surface state.
498 ASSERT_STATUS_OK(manager_->WaitForUpdate());
499 ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
500
501 // Verify the buffers changed flag is set.
502 auto check_flags = [](const auto& value) {
503 return value & DVR_SURFACE_UPDATE_FLAGS_BUFFERS_CHANGED;
504 };
505 EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
506
507 auto queue_ids_status = manager_->GetQueueIds(0);
508 ASSERT_STATUS_OK(queue_ids_status);
509
510 auto queue_ids = queue_ids_status.take();
511 ASSERT_EQ(1u, queue_ids.size());
512 EXPECT_EQ(queue_id, queue_ids[0]);
513
514 auto read_queue_status = manager_->GetReadBufferQueue(surface_id, queue_id);
515 ASSERT_STATUS_OK(read_queue_status);
516 UniqueDvrReadBufferQueue read_queue = read_queue_status.take();
517 ASSERT_NE(nullptr, read_queue.get());
518 EXPECT_EQ(queue_id, dvrReadBufferQueueGetId(read_queue.get()));
519
520 write_queue.reset();
521
522 // Verify that destroying the queue generates a surface update event.
523 ASSERT_STATUS_OK(manager_->WaitForUpdate());
524 ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
525
526 // Verify that the buffers changed flag is set.
527 EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
528
529 // Verify that the queue ids reflect the change.
530 queue_ids_status = manager_->GetQueueIds(0);
531 ASSERT_STATUS_OK(queue_ids_status);
532
533 queue_ids = queue_ids_status.take();
534 ASSERT_EQ(0u, queue_ids.size());
535 }
536
TEST_F(DvrDisplayManagerTest,MultiLayerBufferQueue)537 TEST_F(DvrDisplayManagerTest, MultiLayerBufferQueue) {
538 // Create an application surface.
539 auto surface_status = CreateApplicationSurface();
540 ASSERT_STATUS_OK(surface_status);
541 UniqueDvrSurface surface = surface_status.take();
542 ASSERT_NE(nullptr, surface.get());
543
544 // Get surface state and verify there is one surface.
545 ASSERT_STATUS_OK(manager_->WaitForUpdate());
546 ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
547
548 // Create a new queue in the surface.
549 const uint32_t kLayerCount = 3;
550 auto write_queue_status = CreateSurfaceQueue(
551 surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, kLayerCount,
552 AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1);
553 ASSERT_STATUS_OK(write_queue_status);
554 UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
555 ASSERT_NE(nullptr, write_queue.get());
556
557 DvrWriteBuffer* buffer = nullptr;
558 dvrWriteBufferCreateEmpty(&buffer);
559 int fence_fd = -1;
560 int error =
561 dvrWriteBufferQueueDequeue(write_queue.get(), 1000, buffer, &fence_fd);
562 ASSERT_EQ(0, error);
563
564 AHardwareBuffer* hardware_buffer = nullptr;
565 error = dvrWriteBufferGetAHardwareBuffer(buffer, &hardware_buffer);
566 ASSERT_EQ(0, error);
567
568 AHardwareBuffer_Desc desc = {};
569 AHardwareBuffer_describe(hardware_buffer, &desc);
570 ASSERT_EQ(kLayerCount, desc.layers);
571
572 AHardwareBuffer_release(hardware_buffer);
573 dvrWriteBufferDestroy(buffer);
574 }
575
576 } // namespace
577
578 } // namespace dvr
579 } // namespace android
580