Serialize LightFlattenable trivially copyable objects as LightFlattenable
Currently if an object is LightFlattenable and trivially copyable
FlattenableHelpers serialize it as a trivially copyable. Instead
the overloaded methods should be used.
Bug: 180539476
Test: atest FlattenableHelpersTest
Change-Id: I37d9c207db6bf7be869d919e3d96b85dc3a6cd16
diff --git a/libs/ui/include_private/ui/FlattenableHelpers.h b/libs/ui/include_private/ui/FlattenableHelpers.h
index 8e316d8..378f37f 100644
--- a/libs/ui/include_private/ui/FlattenableHelpers.h
+++ b/libs/ui/include_private/ui/FlattenableHelpers.h
@@ -29,20 +29,29 @@
namespace android {
struct FlattenableHelpers {
- // Helpers for reading and writing POD structures
- template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+ // Helpers for reading and writing POD structures which are not LightFlattenable.
+ template <class T,
+ typename = std::enable_if_t<
+ std::conjunction_v<std::is_trivially_copyable<T>,
+ std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
static constexpr size_t getFlattenedSize(const T&) {
return sizeof(T);
}
- template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+ template <class T,
+ typename = std::enable_if_t<
+ std::conjunction_v<std::is_trivially_copyable<T>,
+ std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
static status_t flatten(void** buffer, size_t* size, const T& value) {
if (*size < sizeof(T)) return NO_MEMORY;
FlattenableUtils::write(*buffer, *size, value);
return OK;
}
- template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+ template <class T,
+ typename = std::enable_if_t<
+ std::conjunction_v<std::is_trivially_copyable<T>,
+ std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
static status_t unflatten(const void** buffer, size_t* size, T* value) {
if (*size < sizeof(T)) return NO_MEMORY;
FlattenableUtils::read(*buffer, *size, *value);
diff --git a/libs/ui/tests/FlattenableHelpers_test.cpp b/libs/ui/tests/FlattenableHelpers_test.cpp
index db32bc7..44e20b5 100644
--- a/libs/ui/tests/FlattenableHelpers_test.cpp
+++ b/libs/ui/tests/FlattenableHelpers_test.cpp
@@ -42,7 +42,7 @@
}
status_t unflatten(void const* buffer, size_t size) {
- int value;
+ int32_t value;
FlattenableUtils::read(buffer, size, value);
ptr = std::make_unique<int32_t>(value);
return OK;
@@ -132,5 +132,66 @@
ASSERT_FALSE(valueRead.has_value());
}
+// If a struct is both trivially copyable and light flattenable we should treat it
+// as LigthFlattenable.
+TEST_F(FlattenableHelpersTest, TriviallyCopyableAndLightFlattenableIsFlattenedAsLightFlattenable) {
+ static constexpr int32_t kSizeTag = 1234567;
+ static constexpr int32_t kFlattenTag = 987654;
+ static constexpr int32_t kUnflattenTag = 5926582;
+
+ struct LightFlattenableAndTriviallyCopyable
+ : LightFlattenable<LightFlattenableAndTriviallyCopyable> {
+ int32_t value;
+
+ bool isFixedSize() const { return true; }
+ size_t getFlattenedSize() const { return kSizeTag; }
+
+ status_t flatten(void* buffer, size_t size) const {
+ FlattenableUtils::write(buffer, size, kFlattenTag);
+ return OK;
+ }
+
+ status_t unflatten(void const*, size_t) {
+ value = kUnflattenTag;
+ return OK;
+ }
+ };
+
+ {
+ // Verify that getFlattenedSize uses the LightFlattenable overload
+ LightFlattenableAndTriviallyCopyable foo;
+ EXPECT_EQ(kSizeTag, FlattenableHelpers::getFlattenedSize(foo));
+ }
+
+ {
+ // Verify that flatten uses the LightFlattenable overload
+ std::vector<int8_t> buffer(sizeof(int32_t));
+ auto rawBuffer = reinterpret_cast<void*>(buffer.data());
+ size_t size = buffer.size();
+ LightFlattenableAndTriviallyCopyable foo;
+ ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, foo));
+
+ auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+ int32_t value;
+ FlattenableHelpers::unflatten(&rawReadBuffer, &size, &value);
+ EXPECT_EQ(kFlattenTag, value);
+ }
+
+ {
+ // Verify that unflatten uses the LightFlattenable overload
+ std::vector<int8_t> buffer(sizeof(int32_t));
+ auto rawBuffer = reinterpret_cast<void*>(buffer.data());
+ size_t size = buffer.size();
+ int32_t value = 4;
+ ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
+
+ auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+
+ LightFlattenableAndTriviallyCopyable foo;
+ FlattenableHelpers::unflatten(&rawReadBuffer, &size, &foo);
+ EXPECT_EQ(kUnflattenTag, foo.value);
+ }
+}
+
} // namespace
} // namespace android