| #include <android-base/properties.h> |
| #include <base/logging.h> |
| #include <gtest/gtest.h> |
| #include <log/log.h> |
| #include <poll.h> |
| |
| #include <android/hardware_buffer.h> |
| |
| #include <algorithm> |
| #include <array> |
| #include <set> |
| #include <thread> |
| #include <vector> |
| |
| #include <dvr/dvr_configuration_data.h> |
| #include <dvr/dvr_deleter.h> |
| #include <dvr/dvr_display_manager.h> |
| #include <dvr/dvr_surface.h> |
| |
| #include <pdx/status.h> |
| |
| using android::pdx::ErrorStatus; |
| using android::pdx::Status; |
| |
| namespace android { |
| namespace dvr { |
| |
| namespace { |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, nullptr_t) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE; |
| return attribute; |
| } |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int32_t value) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32; |
| attribute.value.int32_value = value; |
| return attribute; |
| } |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int64_t value) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64; |
| attribute.value.int64_value = value; |
| return attribute; |
| } |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, bool value) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL; |
| attribute.value.bool_value = value; |
| return attribute; |
| } |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, float value) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT; |
| attribute.value.float_value = value; |
| return attribute; |
| } |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, |
| const std::array<float, 2>& value) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2; |
| std::copy(value.begin(), value.end(), attribute.value.float2_value); |
| return attribute; |
| } |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, |
| const std::array<float, 3>& value) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3; |
| std::copy(value.begin(), value.end(), attribute.value.float3_value); |
| return attribute; |
| } |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, |
| const std::array<float, 4>& value) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4; |
| std::copy(value.begin(), value.end(), attribute.value.float4_value); |
| return attribute; |
| } |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, |
| const std::array<float, 8>& value) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8; |
| std::copy(value.begin(), value.end(), attribute.value.float8_value); |
| return attribute; |
| } |
| |
| DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, |
| const std::array<float, 16>& value) { |
| DvrSurfaceAttribute attribute; |
| attribute.key = key; |
| attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16; |
| std::copy(value.begin(), value.end(), attribute.value.float16_value); |
| return attribute; |
| } |
| |
| Status<UniqueDvrSurface> CreateApplicationSurface(bool visible = false, |
| int32_t z_order = 0) { |
| DvrSurface* surface = nullptr; |
| DvrSurfaceAttribute attributes[] = { |
| MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order), |
| MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)}; |
| |
| const int ret = dvrSurfaceCreate( |
| attributes, std::extent<decltype(attributes)>::value, &surface); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| else |
| return {UniqueDvrSurface(surface)}; |
| } |
| |
| Status<UniqueDvrWriteBufferQueue> CreateSurfaceQueue( |
| const UniqueDvrSurface& surface, uint32_t width, uint32_t height, |
| uint32_t format, uint32_t layer_count, uint64_t usage, size_t capacity, |
| size_t metadata_size) { |
| DvrWriteBufferQueue* queue; |
| const int ret = dvrSurfaceCreateWriteBufferQueue( |
| surface.get(), width, height, format, layer_count, usage, capacity, |
| metadata_size, &queue); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| else |
| return {UniqueDvrWriteBufferQueue(queue)}; |
| } |
| |
| class TestDisplayManager { |
| public: |
| TestDisplayManager(UniqueDvrDisplayManager display_manager, |
| UniqueDvrSurfaceState surface_state) |
| : display_manager_(std::move(display_manager)), |
| surface_state_(std::move(surface_state)) { |
| const int fd = dvrDisplayManagerGetEventFd(display_manager_.get()); |
| LOG_IF(INFO, fd < 0) << "Failed to get event fd: " << strerror(-fd); |
| display_manager_event_fd_ = fd; |
| } |
| |
| Status<UniqueDvrReadBufferQueue> GetReadBufferQueue(int surface_id, |
| int queue_id) { |
| DvrReadBufferQueue* queue; |
| const int ret = dvrDisplayManagerGetReadBufferQueue( |
| display_manager_.get(), surface_id, queue_id, &queue); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| else |
| return {UniqueDvrReadBufferQueue(queue)}; |
| } |
| |
| Status<void> UpdateSurfaceState() { |
| const int ret = dvrDisplayManagerGetSurfaceState(display_manager_.get(), |
| surface_state_.get()); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| else |
| return {}; |
| } |
| |
| enum : int { kTimeoutMs = 10000 }; // 10s |
| |
| Status<void> WaitForUpdate(int timeout_ms = kTimeoutMs) { |
| if (display_manager_event_fd_ < 0) |
| return ErrorStatus(-display_manager_event_fd_); |
| |
| pollfd pfd = {display_manager_event_fd_, POLLIN, 0}; |
| const int count = poll(&pfd, 1, timeout_ms); |
| if (count < 0) |
| return ErrorStatus(errno); |
| else if (count == 0) |
| return ErrorStatus(ETIMEDOUT); |
| |
| int events; |
| const int ret = dvrDisplayManagerTranslateEpollEventMask( |
| display_manager_.get(), pfd.revents, &events); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| else if (events & POLLIN) |
| return UpdateSurfaceState(); |
| else |
| return ErrorStatus(EPROTO); |
| } |
| |
| Status<size_t> GetSurfaceCount() { |
| size_t count = 0; |
| const int ret = |
| dvrSurfaceStateGetSurfaceCount(surface_state_.get(), &count); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| else |
| return {count}; |
| } |
| |
| Status<DvrSurfaceUpdateFlags> GetUpdateFlags(size_t surface_index) { |
| DvrSurfaceUpdateFlags update_flags; |
| const int ret = dvrSurfaceStateGetUpdateFlags(surface_state_.get(), |
| surface_index, &update_flags); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| else |
| return {update_flags}; |
| } |
| |
| Status<int> GetSurfaceId(size_t surface_index) { |
| int surface_id; |
| const int ret = dvrSurfaceStateGetSurfaceId(surface_state_.get(), |
| surface_index, &surface_id); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| else |
| return {surface_id}; |
| } |
| |
| Status<int> GetProcessId(size_t surface_index) { |
| int process_id; |
| const int ret = dvrSurfaceStateGetProcessId(surface_state_.get(), |
| surface_index, &process_id); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| else |
| return {process_id}; |
| } |
| |
| Status<std::vector<DvrSurfaceAttribute>> GetAttributes(size_t surface_index) { |
| std::vector<DvrSurfaceAttribute> attributes; |
| size_t count = 0; |
| const int ret = dvrSurfaceStateGetAttributeCount(surface_state_.get(), |
| surface_index, &count); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| |
| attributes.resize(count); |
| const ssize_t return_count = dvrSurfaceStateGetAttributes( |
| surface_state_.get(), surface_index, attributes.data(), count); |
| if (return_count < 0) |
| return ErrorStatus(-return_count); |
| |
| attributes.resize(return_count); |
| return {std::move(attributes)}; |
| } |
| |
| Status<std::vector<int>> GetQueueIds(size_t surface_index) { |
| std::vector<int> queue_ids; |
| size_t count = 0; |
| const int ret = dvrSurfaceStateGetQueueCount(surface_state_.get(), |
| surface_index, &count); |
| if (ret < 0) |
| return ErrorStatus(-ret); |
| |
| if (count > 0) { |
| queue_ids.resize(count); |
| const ssize_t return_count = dvrSurfaceStateGetQueueIds( |
| surface_state_.get(), surface_index, queue_ids.data(), count); |
| if (return_count < 0) |
| return ErrorStatus(-return_count); |
| |
| queue_ids.resize(return_count); |
| } |
| |
| return {std::move(queue_ids)}; |
| } |
| |
| Status<std::vector<uint8_t>> GetConfigData(int config_type) { |
| uint8_t* data = nullptr; |
| size_t data_size = 0; |
| int error = dvrConfigurationDataGet(config_type, &data, &data_size); |
| if (error < 0) { |
| return ErrorStatus(-error); |
| } |
| |
| if (!data || data_size == 0) { |
| return ErrorStatus(EINVAL); |
| } |
| std::vector<uint8_t> data_result(data, data + data_size); |
| dvrConfigurationDataDestroy(data); |
| std::string s(data, data + data_size); |
| return {std::move(data_result)}; |
| } |
| |
| private: |
| UniqueDvrDisplayManager display_manager_; |
| UniqueDvrSurfaceState surface_state_; |
| |
| // Owned by object in display_manager_, do not explicitly close. |
| int display_manager_event_fd_; |
| |
| TestDisplayManager(const TestDisplayManager&) = delete; |
| void operator=(const TestDisplayManager&) = delete; |
| }; |
| |
| class DvrDisplayManagerTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| int ret; |
| DvrDisplayManager* display_manager; |
| DvrSurfaceState* surface_state; |
| |
| ret = dvrDisplayManagerCreate(&display_manager); |
| ASSERT_EQ(0, ret) << "Failed to create display manager client"; |
| ASSERT_NE(nullptr, display_manager); |
| |
| ret = dvrSurfaceStateCreate(&surface_state); |
| ASSERT_EQ(0, ret) << "Failed to create surface state object"; |
| ASSERT_NE(nullptr, surface_state); |
| |
| manager_.reset( |
| new TestDisplayManager(UniqueDvrDisplayManager(display_manager), |
| UniqueDvrSurfaceState(surface_state))); |
| } |
| void TearDown() override {} |
| |
| std::unique_ptr<TestDisplayManager> manager_; |
| }; |
| |
| // TODO(eieio): Consider moving these somewhere more central because they are |
| // broadly useful. |
| |
| template <typename T> |
| testing::AssertionResult StatusOk(const char* status_expression, |
| const Status<T>& status) { |
| if (!status.ok()) { |
| return testing::AssertionFailure() |
| << "(" << status_expression |
| << ") expected to indicate success but actually contains error (" |
| << status.error() << ")"; |
| } else { |
| return testing::AssertionSuccess(); |
| } |
| } |
| |
| template <typename T> |
| testing::AssertionResult StatusError(const char* status_expression, |
| const Status<T>& status) { |
| if (status.ok()) { |
| return testing::AssertionFailure() |
| << "(" << status_expression |
| << ") expected to indicate error but instead indicates success."; |
| } else { |
| return testing::AssertionSuccess(); |
| } |
| } |
| |
| template <typename T> |
| testing::AssertionResult StatusHasError(const char* status_expression, |
| const char* /*error_code_expression*/, |
| const Status<T>& status, |
| int error_code) { |
| if (status.ok()) { |
| return StatusError(status_expression, status); |
| } else if (status.error() != error_code) { |
| return testing::AssertionFailure() |
| << "(" << status_expression << ") expected to indicate error (" |
| << error_code << ") but actually indicates error (" << status.error() |
| << ")"; |
| } else { |
| return testing::AssertionSuccess(); |
| } |
| } |
| |
| template <typename T, typename U> |
| testing::AssertionResult StatusHasValue(const char* status_expression, |
| const char* /*value_expression*/, |
| const Status<T>& status, |
| const U& value) { |
| if (!status.ok()) { |
| return StatusOk(status_expression, status); |
| } else if (status.get() != value) { |
| return testing::AssertionFailure() |
| << "(" << status_expression << ") expected to contain value (" |
| << testing::PrintToString(value) << ") but actually contains value (" |
| << testing::PrintToString(status.get()) << ")"; |
| } else { |
| return testing::AssertionSuccess(); |
| } |
| } |
| |
| template <typename T, typename Op> |
| testing::AssertionResult StatusPred(const char* status_expression, |
| const char* pred_expression, |
| const Status<T>& status, Op pred) { |
| if (!status.ok()) { |
| return StatusOk(status_expression, status); |
| } else if (!pred(status.get())) { |
| return testing::AssertionFailure() |
| << status_expression << " value (" |
| << testing::PrintToString(status.get()) |
| << ") failed to pass predicate " << pred_expression; |
| } else { |
| return testing::AssertionSuccess(); |
| } |
| } |
| |
| #define ASSERT_STATUS_OK(status) ASSERT_PRED_FORMAT1(StatusOk, status) |
| #define ASSERT_STATUS_ERROR(status) ASSERT_PRED_FORMAT1(StatusError, status) |
| |
| #define ASSERT_STATUS_ERROR_VALUE(value, status) \ |
| ASSERT_PRED_FORMAT2(StatusHasError, status, value) |
| |
| #define ASSERT_STATUS_EQ(value, status) \ |
| ASSERT_PRED_FORMAT2(StatusHasValue, status, value) |
| |
| #define EXPECT_STATUS_OK(status) EXPECT_PRED_FORMAT1(StatusOk, status) |
| #define EXPECT_STATUS_ERROR(status) EXPECT_PRED_FORMAT1(StatusError, status) |
| |
| #define EXPECT_STATUS_ERROR_VALUE(value, status) \ |
| EXPECT_PRED_FORMAT2(StatusHasError, status, value) |
| |
| #define EXPECT_STATUS_EQ(value, status) \ |
| EXPECT_PRED_FORMAT2(StatusHasValue, status, value) |
| |
| #define EXPECT_STATUS_PRED(pred, status) \ |
| EXPECT_PRED_FORMAT2(StatusPred, status, pred) |
| |
| #if 0 |
| // Verify utility predicate/macro functionality. This section is commented out |
| // because it is designed to fail in some cases to validate the helpers. |
| TEST_F(DvrDisplayManagerTest, ExpectVoid) { |
| Status<void> status_error{ErrorStatus{EINVAL}}; |
| Status<void> status_ok{}; |
| |
| EXPECT_STATUS_ERROR(status_error); |
| EXPECT_STATUS_ERROR(status_ok); |
| EXPECT_STATUS_OK(status_error); |
| EXPECT_STATUS_OK(status_ok); |
| |
| EXPECT_STATUS_ERROR_VALUE(EINVAL, status_error); |
| EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_error); |
| EXPECT_STATUS_ERROR_VALUE(EINVAL, status_ok); |
| EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_ok); |
| } |
| |
| TEST_F(DvrDisplayManagerTest, ExpectInt) { |
| Status<int> status_error{ErrorStatus{EINVAL}}; |
| Status<int> status_ok{10}; |
| |
| EXPECT_STATUS_ERROR(status_error); |
| EXPECT_STATUS_ERROR(status_ok); |
| EXPECT_STATUS_OK(status_error); |
| EXPECT_STATUS_OK(status_ok); |
| |
| EXPECT_STATUS_ERROR_VALUE(EINVAL, status_error); |
| EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_error); |
| EXPECT_STATUS_ERROR_VALUE(EINVAL, status_ok); |
| EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_ok); |
| |
| EXPECT_STATUS_EQ(10, status_error); |
| EXPECT_STATUS_EQ(20, status_error); |
| EXPECT_STATUS_EQ(10, status_ok); |
| EXPECT_STATUS_EQ(20, status_ok); |
| |
| auto pred1 = [](const auto& value) { return value < 15; }; |
| auto pred2 = [](const auto& value) { return value > 5; }; |
| auto pred3 = [](const auto& value) { return value > 15; }; |
| auto pred4 = [](const auto& value) { return value < 5; }; |
| |
| EXPECT_STATUS_PRED(pred1, status_error); |
| EXPECT_STATUS_PRED(pred2, status_error); |
| EXPECT_STATUS_PRED(pred3, status_error); |
| EXPECT_STATUS_PRED(pred4, status_error); |
| EXPECT_STATUS_PRED(pred1, status_ok); |
| EXPECT_STATUS_PRED(pred2, status_ok); |
| EXPECT_STATUS_PRED(pred3, status_ok); |
| EXPECT_STATUS_PRED(pred4, status_ok); |
| } |
| #endif |
| |
| TEST_F(DvrDisplayManagerTest, SurfaceCreateEvent) { |
| // Get surface state and verify there are no surfaces. |
| ASSERT_STATUS_OK(manager_->UpdateSurfaceState()); |
| ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount()); |
| |
| // Get flags for invalid surface index. |
| EXPECT_STATUS_ERROR_VALUE(EINVAL, manager_->GetUpdateFlags(0)); |
| |
| // Create an application surface. |
| auto surface_status = CreateApplicationSurface(); |
| ASSERT_STATUS_OK(surface_status); |
| UniqueDvrSurface surface = surface_status.take(); |
| ASSERT_NE(nullptr, surface.get()); |
| |
| const int surface_id = dvrSurfaceGetId(surface.get()); |
| ASSERT_GE(surface_id, 0); |
| |
| // Now there should be one new surface. |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| EXPECT_STATUS_EQ(1u, manager_->GetSurfaceCount()); |
| |
| // Verify the new surface flag is set. |
| auto check_flags = [](const auto& value) { |
| return value & DVR_SURFACE_UPDATE_FLAGS_NEW_SURFACE; |
| }; |
| EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0)); |
| |
| // Verify the surface id matches. |
| EXPECT_STATUS_EQ(surface_id, manager_->GetSurfaceId(0)); |
| |
| // Verify the owning process of the surface. |
| EXPECT_STATUS_EQ(getpid(), manager_->GetProcessId(0)); |
| |
| surface.reset(); |
| |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| EXPECT_STATUS_EQ(0u, manager_->GetSurfaceCount()); |
| } |
| |
| TEST_F(DvrDisplayManagerTest, SurfaceAttributeEvent) { |
| // Get surface state and verify there are no surfaces. |
| ASSERT_STATUS_OK(manager_->UpdateSurfaceState()); |
| ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount()); |
| |
| // Get attributes for an invalid surface index. |
| EXPECT_STATUS_ERROR_VALUE(EINVAL, manager_->GetAttributes(0)); |
| |
| const bool kInitialVisibility = true; |
| const int32_t kInitialZOrder = 10; |
| auto surface_status = |
| CreateApplicationSurface(kInitialVisibility, kInitialZOrder); |
| ASSERT_STATUS_OK(surface_status); |
| auto surface = surface_status.take(); |
| ASSERT_NE(nullptr, surface.get()); |
| |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount()); |
| |
| // Check the initial attribute values. |
| auto attribute_status = manager_->GetAttributes(0); |
| ASSERT_STATUS_OK(attribute_status); |
| auto attributes = attribute_status.take(); |
| EXPECT_GE(attributes.size(), 2u); |
| |
| std::set<int32_t> actual_keys; |
| std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, |
| DVR_SURFACE_ATTRIBUTE_VISIBLE}; |
| |
| // Collect all the keys in attributes that match the expected keys. |
| auto compare_keys = [](const auto& attributes, const auto& expected_keys) { |
| std::set<int32_t> keys; |
| for (const auto& attribute : attributes) { |
| if (expected_keys.find(attribute.key) != expected_keys.end()) |
| keys.emplace(attribute.key); |
| } |
| return keys; |
| }; |
| |
| // If the sets match then attributes contained at least the expected keys, |
| // even if other keys were also present. |
| actual_keys = compare_keys(attributes, expected_keys); |
| EXPECT_EQ(expected_keys, actual_keys); |
| |
| std::vector<DvrSurfaceAttribute> attributes_to_set = { |
| MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, 0)}; |
| |
| // Test invalid args. |
| EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(nullptr, attributes_to_set.data(), |
| attributes_to_set.size())); |
| EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(surface.get(), nullptr, |
| attributes_to_set.size())); |
| |
| // Test attribute change events. |
| ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(), |
| attributes_to_set.size())); |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| |
| // Verify the attributes changed flag is set. |
| auto check_flags = [](const auto& value) { |
| return value & DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED; |
| }; |
| EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0)); |
| |
| attribute_status = manager_->GetAttributes(0); |
| ASSERT_STATUS_OK(attribute_status); |
| attributes = attribute_status.take(); |
| EXPECT_GE(attributes.size(), 2u); |
| |
| expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, |
| DVR_SURFACE_ATTRIBUTE_VISIBLE}; |
| |
| actual_keys.clear(); |
| actual_keys = compare_keys(attributes, expected_keys); |
| EXPECT_EQ(expected_keys, actual_keys); |
| |
| // Test setting and then deleting an attribute. |
| const DvrSurfaceAttributeKey kUserKey = 1; |
| attributes_to_set = {MakeAttribute(kUserKey, 1024)}; |
| |
| ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(), |
| attributes_to_set.size())); |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0)); |
| |
| attribute_status = manager_->GetAttributes(0); |
| ASSERT_STATUS_OK(attribute_status); |
| attributes = attribute_status.take(); |
| EXPECT_GE(attributes.size(), 2u); |
| |
| expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE, |
| kUserKey}; |
| |
| actual_keys.clear(); |
| actual_keys = compare_keys(attributes, expected_keys); |
| EXPECT_EQ(expected_keys, actual_keys); |
| |
| // Delete the attribute. |
| attributes_to_set = {MakeAttribute(kUserKey, nullptr)}; |
| |
| ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(), |
| attributes_to_set.size())); |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0)); |
| |
| attribute_status = manager_->GetAttributes(0); |
| ASSERT_STATUS_OK(attribute_status); |
| attributes = attribute_status.take(); |
| EXPECT_GE(attributes.size(), 2u); |
| |
| expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE, |
| kUserKey}; |
| |
| actual_keys.clear(); |
| actual_keys = compare_keys(attributes, expected_keys); |
| EXPECT_NE(expected_keys, actual_keys); |
| |
| // Test deleting a reserved attribute. |
| attributes_to_set = {MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, nullptr)}; |
| |
| EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(), |
| attributes_to_set.size())); |
| |
| // Failed attribute operations should not trigger update events. |
| const int kTimeoutMs = 100; // 0.1s |
| EXPECT_STATUS_ERROR_VALUE(ETIMEDOUT, manager_->WaitForUpdate(kTimeoutMs)); |
| |
| attribute_status = manager_->GetAttributes(0); |
| ASSERT_STATUS_OK(attribute_status); |
| attributes = attribute_status.take(); |
| EXPECT_GE(attributes.size(), 2u); |
| |
| expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, |
| DVR_SURFACE_ATTRIBUTE_VISIBLE}; |
| |
| actual_keys.clear(); |
| actual_keys = compare_keys(attributes, expected_keys); |
| EXPECT_EQ(expected_keys, actual_keys); |
| } |
| |
| TEST_F(DvrDisplayManagerTest, SurfaceAttributeTypes) { |
| // Create an application surface. |
| auto surface_status = CreateApplicationSurface(); |
| ASSERT_STATUS_OK(surface_status); |
| UniqueDvrSurface surface = surface_status.take(); |
| ASSERT_NE(nullptr, surface.get()); |
| |
| enum : std::int32_t { |
| kInt32Key = 1, |
| kInt64Key, |
| kBoolKey, |
| kFloatKey, |
| kFloat2Key, |
| kFloat3Key, |
| kFloat4Key, |
| kFloat8Key, |
| kFloat16Key, |
| }; |
| |
| const std::vector<DvrSurfaceAttribute> attributes_to_set = { |
| MakeAttribute(kInt32Key, int32_t{0}), |
| MakeAttribute(kInt64Key, int64_t{0}), |
| MakeAttribute(kBoolKey, false), |
| MakeAttribute(kFloatKey, 0.0f), |
| MakeAttribute(kFloat2Key, std::array<float, 2>{{1.0f, 2.0f}}), |
| MakeAttribute(kFloat3Key, std::array<float, 3>{{3.0f, 4.0f, 5.0f}}), |
| MakeAttribute(kFloat4Key, std::array<float, 4>{{6.0f, 7.0f, 8.0f, 9.0f}}), |
| MakeAttribute(kFloat8Key, |
| std::array<float, 8>{{10.0f, 11.0f, 12.0f, 13.0f, 14.0f, |
| 15.0f, 16.0f, 17.0f}}), |
| MakeAttribute(kFloat16Key, std::array<float, 16>{ |
| {18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f, |
| 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, |
| 30.0f, 31.0f, 32.0f, 33.0f}})}; |
| |
| EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(), |
| attributes_to_set.size())); |
| |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| auto attribute_status = manager_->GetAttributes(0); |
| ASSERT_STATUS_OK(attribute_status); |
| auto attributes = attribute_status.take(); |
| EXPECT_GE(attributes.size(), attributes_to_set.size()); |
| |
| auto HasAttribute = [](const auto& attributes, |
| DvrSurfaceAttributeKey key) -> bool { |
| for (const auto& attribute : attributes) { |
| if (attribute.key == key) |
| return true; |
| } |
| return false; |
| }; |
| auto AttributeType = |
| [](const auto& attributes, |
| DvrSurfaceAttributeKey key) -> DvrSurfaceAttributeType { |
| for (const auto& attribute : attributes) { |
| if (attribute.key == key) |
| return attribute.value.type; |
| } |
| return DVR_SURFACE_ATTRIBUTE_TYPE_NONE; |
| }; |
| |
| ASSERT_TRUE(HasAttribute(attributes, kInt32Key)); |
| EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT32, |
| AttributeType(attributes, kInt32Key)); |
| |
| ASSERT_TRUE(HasAttribute(attributes, kInt64Key)); |
| EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT64, |
| AttributeType(attributes, kInt64Key)); |
| |
| ASSERT_TRUE(HasAttribute(attributes, kBoolKey)); |
| EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_BOOL, |
| AttributeType(attributes, kBoolKey)); |
| |
| ASSERT_TRUE(HasAttribute(attributes, kFloatKey)); |
| EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT, |
| AttributeType(attributes, kFloatKey)); |
| |
| ASSERT_TRUE(HasAttribute(attributes, kFloat2Key)); |
| EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2, |
| AttributeType(attributes, kFloat2Key)); |
| |
| ASSERT_TRUE(HasAttribute(attributes, kFloat3Key)); |
| EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3, |
| AttributeType(attributes, kFloat3Key)); |
| |
| ASSERT_TRUE(HasAttribute(attributes, kFloat4Key)); |
| EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4, |
| AttributeType(attributes, kFloat4Key)); |
| |
| ASSERT_TRUE(HasAttribute(attributes, kFloat8Key)); |
| EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8, |
| AttributeType(attributes, kFloat8Key)); |
| |
| ASSERT_TRUE(HasAttribute(attributes, kFloat16Key)); |
| EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16, |
| AttributeType(attributes, kFloat16Key)); |
| } |
| |
| TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) { |
| // Create an application surface. |
| auto surface_status = CreateApplicationSurface(); |
| ASSERT_STATUS_OK(surface_status); |
| UniqueDvrSurface surface = surface_status.take(); |
| ASSERT_NE(nullptr, surface.get()); |
| |
| const int surface_id = dvrSurfaceGetId(surface.get()); |
| ASSERT_GE(surface_id, 0); |
| // Get surface state and verify there is one surface. |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount()); |
| |
| // Verify there are no queues for the surface recorded in the state |
| // snapshot. |
| EXPECT_STATUS_EQ(std::vector<int>{}, manager_->GetQueueIds(0)); |
| |
| // Create a new queue in the surface. |
| auto write_queue_status = CreateSurfaceQueue( |
| surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 1, |
| AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0); |
| ASSERT_STATUS_OK(write_queue_status); |
| UniqueDvrWriteBufferQueue write_queue = write_queue_status.take(); |
| ASSERT_NE(nullptr, write_queue.get()); |
| |
| const int queue_id = dvrWriteBufferQueueGetId(write_queue.get()); |
| ASSERT_GE(queue_id, 0); |
| |
| // Update surface state. |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount()); |
| |
| // Verify the buffers changed flag is set. |
| auto check_flags = [](const auto& value) { |
| return value & DVR_SURFACE_UPDATE_FLAGS_BUFFERS_CHANGED; |
| }; |
| EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0)); |
| |
| auto queue_ids_status = manager_->GetQueueIds(0); |
| ASSERT_STATUS_OK(queue_ids_status); |
| |
| auto queue_ids = queue_ids_status.take(); |
| ASSERT_EQ(1u, queue_ids.size()); |
| EXPECT_EQ(queue_id, queue_ids[0]); |
| |
| auto read_queue_status = manager_->GetReadBufferQueue(surface_id, queue_id); |
| ASSERT_STATUS_OK(read_queue_status); |
| UniqueDvrReadBufferQueue read_queue = read_queue_status.take(); |
| ASSERT_NE(nullptr, read_queue.get()); |
| EXPECT_EQ(queue_id, dvrReadBufferQueueGetId(read_queue.get())); |
| |
| write_queue.reset(); |
| |
| // Verify that destroying the queue generates a surface update event. |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount()); |
| |
| // Verify that the buffers changed flag is set. |
| EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0)); |
| |
| // Verify that the queue ids reflect the change. |
| queue_ids_status = manager_->GetQueueIds(0); |
| ASSERT_STATUS_OK(queue_ids_status); |
| |
| queue_ids = queue_ids_status.take(); |
| ASSERT_EQ(0u, queue_ids.size()); |
| } |
| |
| TEST_F(DvrDisplayManagerTest, MultiLayerBufferQueue) { |
| // Create an application surface. |
| auto surface_status = CreateApplicationSurface(); |
| ASSERT_STATUS_OK(surface_status); |
| UniqueDvrSurface surface = surface_status.take(); |
| ASSERT_NE(nullptr, surface.get()); |
| |
| // Get surface state and verify there is one surface. |
| ASSERT_STATUS_OK(manager_->WaitForUpdate()); |
| ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount()); |
| |
| // Create a new queue in the surface. |
| const uint32_t kLayerCount = 3; |
| auto write_queue_status = CreateSurfaceQueue( |
| surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, kLayerCount, |
| AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0); |
| ASSERT_STATUS_OK(write_queue_status); |
| UniqueDvrWriteBufferQueue write_queue = write_queue_status.take(); |
| ASSERT_NE(nullptr, write_queue.get()); |
| |
| DvrWriteBuffer* buffer = nullptr; |
| dvrWriteBufferCreateEmpty(&buffer); |
| int fence_fd = -1; |
| int error = |
| dvrWriteBufferQueueDequeue(write_queue.get(), 1000, buffer, &fence_fd); |
| ASSERT_EQ(0, error); |
| |
| AHardwareBuffer* hardware_buffer = nullptr; |
| error = dvrWriteBufferGetAHardwareBuffer(buffer, &hardware_buffer); |
| ASSERT_EQ(0, error); |
| |
| AHardwareBuffer_Desc desc = {}; |
| AHardwareBuffer_describe(hardware_buffer, &desc); |
| ASSERT_EQ(kLayerCount, desc.layers); |
| |
| AHardwareBuffer_release(hardware_buffer); |
| dvrWriteBufferDestroy(buffer); |
| } |
| |
| TEST_F(DvrDisplayManagerTest, ConfigurationData) { |
| // TODO(hendrikw): Move this out of the display manager tests. |
| auto data1 = manager_->GetConfigData(-1); |
| ASSERT_STATUS_ERROR(data1); |
| |
| const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics"; |
| |
| // This should be run on devices with and without built in metrics. |
| bool has_metric = !base::GetProperty(kDvrLensMetricsProperty, "").empty(); |
| auto data2 = manager_->GetConfigData(DVR_CONFIGURATION_DATA_LENS_METRICS); |
| if (has_metric) { |
| ASSERT_STATUS_OK(data2); |
| ASSERT_NE(0u, data2.get().size()); |
| } else { |
| ASSERT_STATUS_ERROR(data2); |
| } |
| } |
| |
| } // namespace |
| |
| } // namespace dvr |
| } // namespace android |