Add ParcelableHolder for NDK backend

Test: atest CtsNdkBinderTest
Bug: 146611855
Change-Id: I8dd5074d7c35dce0ac425cdeacd687c32244736d
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 6701518..5f2f382 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -25,6 +25,8 @@
  */
 
 #pragma once
+#include <android/binder_parcel_utils.h>
+#include <optional>
 
 namespace ndk {
 // Also see Parcelable.h in libbinder.
@@ -33,6 +35,95 @@
     STABILITY_LOCAL,
     STABILITY_VINTF,  // corresponds to @VintfStability
 };
+#define RETURN_ON_FAILURE(expr)                   \
+    do {                                          \
+        binder_status_t _status = (expr);         \
+        if (_status != STATUS_OK) return _status; \
+    } while (false)
+
+class AParcelableHolder {
+   public:
+    AParcelableHolder() = delete;
+    explicit AParcelableHolder(parcelable_stability_t stability)
+        : mParcel(AParcel_create()), mStability(stability) {}
+
+    virtual ~AParcelableHolder() = default;
+
+    binder_status_t writeToParcel(AParcel* parcel) const {
+        std::lock_guard<std::mutex> l(mMutex);
+        RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
+        RETURN_ON_FAILURE(AParcel_writeInt32(parcel, AParcel_getDataSize(this->mParcel.get())));
+        RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0,
+                                             AParcel_getDataSize(this->mParcel.get())));
+        return STATUS_OK;
+    }
+
+    binder_status_t readFromParcel(const AParcel* parcel) {
+        std::lock_guard<std::mutex> l(mMutex);
+
+        AParcel_reset(mParcel.get());
+
+        RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
+        int32_t dataSize;
+        binder_status_t status = AParcel_readInt32(parcel, &dataSize);
+
+        if (status != STATUS_OK || dataSize < 0) {
+            return status != STATUS_OK ? status : STATUS_BAD_VALUE;
+        }
+
+        int32_t dataStartPos = AParcel_getDataPosition(parcel);
+
+        if (dataStartPos > INT32_MAX - dataSize) {
+            return STATUS_BAD_VALUE;
+        }
+
+        status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
+        if (status != STATUS_OK) {
+            return status;
+        }
+        return AParcel_setDataPosition(parcel, dataStartPos + dataSize);
+    }
+
+    template <typename T>
+    bool setParcelable(T* p) {
+        std::lock_guard<std::mutex> l(mMutex);
+        if (p && this->mStability > T::_aidl_stability) {
+            return false;
+        }
+        AParcel_reset(mParcel.get());
+        AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
+        p->writeToParcel(mParcel.get());
+        return true;
+    }
+
+    template <typename T>
+    std::unique_ptr<T> getParcelable() const {
+        std::lock_guard<std::mutex> l(mMutex);
+        const std::string parcelableDesc(T::descriptor);
+        AParcel_setDataPosition(mParcel.get(), 0);
+        if (AParcel_getDataSize(mParcel.get()) == 0) {
+            return nullptr;
+        }
+        std::string parcelableDescInParcel;
+        binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
+        if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
+            return nullptr;
+        }
+        std::unique_ptr<T> ret = std::make_unique<T>();
+        status = ret->readFromParcel(this->mParcel.get());
+        if (status != STATUS_OK) {
+            return nullptr;
+        }
+        return std::move(ret);
+    }
+
+   private:
+    mutable ndk::ScopedAParcel mParcel;
+    mutable std::mutex mMutex;
+    parcelable_stability_t mStability;
+};
+
+#undef RETURN_ON_FAILURE
 }  // namespace ndk
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index a031e29..93c3f32 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1120,6 +1120,53 @@
 // @END-PRIMITIVE-READ-WRITE
 
 #endif  //__ANDROID_API__ >= 29
+#if __ANDROID_API__ >= 31
+/**
+ * Reset the parcel to the initial status.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to be reset.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_reset(AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Gets the size of the parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to get the size.
+ *
+ * \return The size of the parcel.
+ */
+int32_t AParcel_getDataSize(const AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Copy the data of a parcel to other parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param from The source
+ * \param to The detination
+ * \param start The position where the copied data starts.
+ * \param size The amount of data which will be copied.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size)
+        __INTRODUCED_IN(31);
+
+/**
+ * Creates a parcel.
+ *
+ * Available since API level 31.
+ *
+ * \return A parcel which is not related to any IBinder objects.
+ */
+AParcel* AParcel_create() __INTRODUCED_IN(31);
+#endif  //__ANDROID_API__ >= 31
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 1701fb5..947cc98 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -120,6 +120,11 @@
     AServiceManager_isDeclared; # apex llndk
     AServiceManager_registerLazyService; # llndk
     AServiceManager_waitForService; # apex llndk
+
+    AParcel_reset;
+    AParcel_getDataSize;
+    AParcel_appendFrom;
+    AParcel_create;
 };
 
 LIBBINDER_NDK_PLATFORM {
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 722ae23..2f95318 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -647,4 +647,22 @@
     return parcel->get()->allowFds();
 }
 
+binder_status_t AParcel_reset(AParcel* parcel) {
+    parcel->get()->freeData();
+    return STATUS_OK;
+}
+
+int32_t AParcel_getDataSize(const AParcel* parcel) {
+    return parcel->get()->dataSize();
+}
+
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size) {
+    status_t status = to->get()->appendFrom(from->get(), start, size);
+    return PruneStatusT(status);
+}
+
+AParcel* AParcel_create() {
+    return new AParcel(nullptr);
+}
+
 // @END