Use std::string in DeviceProductInfo and serialize it as Flattenable

Use std::string instead of fixed size char arrays. Serialize
DeviceProductInfo and DisplayInfo as Flattenable instead of using
memcpy().

Bug: 145299597
Test: 1. m
      2. adb shell dumpsys display
      3. check that DeviceProductInfo is correctly populated
Change-Id: Id21186138b39d7bb167c41ff7ee9387081ac6285
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 9f7f36f..3965cf0 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -46,7 +46,7 @@
 
     apex_available: [
         "//apex_available:anyapex",
-	"//apex_available:platform",
+        "//apex_available:platform",
     ],
     shared_libs: [
         "libutils",
@@ -97,6 +97,8 @@
         "BufferHubEventFd.cpp",
         "BufferHubMetadata.cpp",
         "DebugUtils.cpp",
+        "DeviceProductInfo.cpp",
+        "DisplayInfo.cpp",
         "Fence.cpp",
         "FenceTime.cpp",
         "FrameStats.cpp",
diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp
new file mode 100644
index 0000000..efd61b6
--- /dev/null
+++ b/libs/ui/DeviceProductInfo.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/DeviceProductInfo.h>
+
+#include <ui/FlattenableHelpers.h>
+
+namespace android {
+
+size_t DeviceProductInfo::getFlattenedSize() const {
+    return FlattenableHelpers::getFlattenedSize(name) + sizeof(manufacturerPnpId) +
+            FlattenableHelpers::getFlattenedSize(productId) + sizeof(manufactureOrModelDate);
+}
+
+status_t DeviceProductInfo::flatten(void* buffer, size_t size) const {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+    FlattenableHelpers::write(buffer, size, name);
+    FlattenableUtils::write(buffer, size, manufacturerPnpId);
+    FlattenableHelpers::write(buffer, size, productId);
+    FlattenableUtils::write(buffer, size, manufactureOrModelDate);
+    return NO_ERROR;
+}
+
+status_t DeviceProductInfo::unflatten(void const* buffer, size_t size) {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+    FlattenableHelpers::read(buffer, size, &name);
+    FlattenableUtils::read(buffer, size, manufacturerPnpId);
+    FlattenableHelpers::read(buffer, size, &productId);
+    FlattenableUtils::read(buffer, size, manufactureOrModelDate);
+    return NO_ERROR;
+}
+
+} // namespace android
diff --git a/libs/ui/DisplayInfo.cpp b/libs/ui/DisplayInfo.cpp
new file mode 100644
index 0000000..6ed7e19
--- /dev/null
+++ b/libs/ui/DisplayInfo.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/DisplayInfo.h>
+
+#include <cstdint>
+
+#include <ui/FlattenableHelpers.h>
+
+namespace android {
+
+size_t DisplayInfo::getFlattenedSize() const {
+    return sizeof(connectionType) + sizeof(density) + sizeof(secure) +
+            FlattenableHelpers::getFlattenedSize(deviceProductInfo);
+}
+
+status_t DisplayInfo::flatten(void* buffer, size_t size) const {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+    FlattenableUtils::write(buffer, size, connectionType);
+    FlattenableUtils::write(buffer, size, density);
+    FlattenableUtils::write(buffer, size, secure);
+    FlattenableHelpers::write(buffer, size, deviceProductInfo);
+
+    return NO_ERROR;
+}
+
+status_t DisplayInfo::unflatten(void const* buffer, size_t size) {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+    FlattenableUtils::read(buffer, size, connectionType);
+    FlattenableUtils::read(buffer, size, density);
+    FlattenableUtils::read(buffer, size, secure);
+    FlattenableHelpers::read(buffer, size, &deviceProductInfo);
+
+    return NO_ERROR;
+}
+
+} // namespace android
diff --git a/libs/ui/include/ui/DeviceProductInfo.h b/libs/ui/include/ui/DeviceProductInfo.h
index c396e73..cc5ebe4 100644
--- a/libs/ui/include/ui/DeviceProductInfo.h
+++ b/libs/ui/include/ui/DeviceProductInfo.h
@@ -19,8 +19,12 @@
 #include <array>
 #include <cstdint>
 #include <optional>
+#include <string>
+#include <type_traits>
 #include <variant>
 
+#include <utils/Flattenable.h>
+
 namespace android {
 
 // NUL-terminated plug and play ID.
@@ -29,9 +33,7 @@
 // Product-specific information about the display or the directly connected device on the
 // display chain. For example, if the display is transitively connected, this field may contain
 // product information about the intermediate device.
-struct DeviceProductInfo {
-    static constexpr size_t TEXT_BUFFER_SIZE = 20;
-
+struct DeviceProductInfo : LightFlattenable<DeviceProductInfo> {
     struct ModelYear {
         uint32_t year;
     };
@@ -44,16 +46,22 @@
     };
 
     // Display name.
-    std::array<char, TEXT_BUFFER_SIZE> name;
+    std::string name;
 
     // Manufacturer Plug and Play ID.
     PnpId manufacturerPnpId;
 
     // Manufacturer product ID.
-    std::array<char, TEXT_BUFFER_SIZE> productId;
+    std::string productId;
 
     using ManufactureOrModelDate = std::variant<ModelYear, ManufactureYear, ManufactureWeekAndYear>;
+    static_assert(std::is_trivially_copyable_v<ManufactureOrModelDate>);
     ManufactureOrModelDate manufactureOrModelDate;
+
+    bool isFixedSize() const { return false; }
+    size_t getFlattenedSize() const;
+    status_t flatten(void* buffer, size_t size) const;
+    status_t unflatten(void const* buffer, size_t size);
 };
 
 } // namespace android
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 897060c..03e0a38 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -20,19 +20,23 @@
 #include <type_traits>
 
 #include <ui/DeviceProductInfo.h>
+#include <utils/Flattenable.h>
 
 namespace android {
 
 enum class DisplayConnectionType { Internal, External };
 
 // Immutable information about physical display.
-struct DisplayInfo {
+struct DisplayInfo : LightFlattenable<DisplayInfo> {
     DisplayConnectionType connectionType = DisplayConnectionType::Internal;
     float density = 0.f;
     bool secure = false;
     std::optional<DeviceProductInfo> deviceProductInfo;
-};
 
-static_assert(std::is_trivially_copyable_v<DisplayInfo>);
+    bool isFixedSize() const { return false; }
+    size_t getFlattenedSize() const;
+    status_t flatten(void* buffer, size_t size) const;
+    status_t unflatten(void const* buffer, size_t size);
+};
 
 } // namespace android
diff --git a/libs/ui/include_private/ui/FlattenableHelpers.h b/libs/ui/include_private/ui/FlattenableHelpers.h
new file mode 100644
index 0000000..bdf4804
--- /dev/null
+++ b/libs/ui/include_private/ui/FlattenableHelpers.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+#include <type_traits>
+
+#include <utils/Flattenable.h>
+
+namespace android {
+
+struct FlattenableHelpers {
+    // Flattenable helpers for reading and writing std::string
+    static size_t getFlattenedSize(const std::string& str) { return str.length() + 1; }
+
+    static void write(void*& buffer, size_t& size, const std::string& str) {
+        strcpy(reinterpret_cast<char*>(buffer), str.c_str());
+        FlattenableUtils::advance(buffer, size, getFlattenedSize(str));
+    }
+
+    static void read(void const*& buffer, size_t& size, std::string* str) {
+        str->assign(reinterpret_cast<const char*>(buffer));
+        FlattenableUtils::advance(buffer, size, getFlattenedSize(*str));
+    }
+
+    // Flattenable utils for reading and writing std::optional
+    template <class T, typename = std::enable_if_t<std::is_base_of_v<LightFlattenable<T>, T>>>
+    static size_t getFlattenedSize(const std::optional<T>& value) {
+        return sizeof(bool) + (value ? value->getFlattenedSize() : 0);
+    }
+
+    template <class T, typename = std::enable_if_t<std::is_base_of_v<LightFlattenable<T>, T>>>
+    static void write(void*& buffer, size_t& size, const std::optional<T>& value) {
+        if (value) {
+            FlattenableUtils::write(buffer, size, true);
+            value->flatten(buffer, size);
+            FlattenableUtils::advance(buffer, size, value->getFlattenedSize());
+        } else {
+            FlattenableUtils::write(buffer, size, false);
+        }
+    }
+
+    template <class T, typename = std::enable_if_t<std::is_base_of_v<LightFlattenable<T>, T>>>
+    static void read(void const*& buffer, size_t& size, std::optional<T>* value) {
+        bool isPresent;
+        FlattenableUtils::read(buffer, size, isPresent);
+        if (isPresent) {
+            *value = T();
+            (*value)->unflatten(buffer, size);
+            FlattenableUtils::advance(buffer, size, (*value)->getFlattenedSize());
+        } else {
+            value->reset();
+        }
+    }
+};
+
+} // namespace android