Add marshal() and unmarshal() APIs.

Expose marshal/unmarshal APIs from binder_ndk because we need
to pass large data that exceeds binder memory limitation across
binder for auto use case. We need to serialize parcel to a shared
memory file and unmarshal it into a parcel. We would only marshal
stable AIDL generated parcelable.

Test: Add a unit test to CTS.
Bug: 197781220
Change-Id: I774663d619ad0ca04f23044d2245021b265b32c1
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 527b151..a2f5c93 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1163,6 +1163,41 @@
  * \return A parcel which is not related to any IBinder objects.
  */
 AParcel* AParcel_create() __INTRODUCED_IN(31);
+
+/**
+ * Marshals the raw bytes of the Parcel to a buffer.
+ *
+ * The parcel must not contain any binders or file descriptors.
+ *
+ * The data you retrieve here must not be placed in any kind of persistent storage. (on local disk,
+ * across a network, etc). For that, you should use standard serialization or another kind of
+ * general serialization mechanism. The Parcel marshalled representation is highly optimized for
+ * local IPC, and as such does not attempt to maintain compatibility with data created in different
+ * versions of the platform.
+ *
+ * \param parcel The parcel of which to get the data.
+ * \param buffer The buffer to copy the raw bytes to.
+ * \param start The start position in the buffer to copy from.
+ * \param len The size of the data to copy, buffer size must be larger or equal to this.
+ *
+ * \return STATUS_OK on success, STATUS_INVALID_OPERATION if parcel contains binders or file
+ * descriptors. STATUS_BAD_VALUE if the buffer size is less than parcel size.
+ */
+binder_status_t AParcel_marshal(const AParcel* parcel, uint8_t* buffer, size_t start, size_t len)
+        __INTRODUCED_IN(33);
+
+/**
+ * Set the data in the parcel to the raw bytes from the buffer.
+ *
+ * \param parcel The parcel to set data.
+ * \param buffer The data buffer to set.
+ * \param len The size of the data to set.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_unmarshal(AParcel* parcel, const uint8_t* buffer, size_t len)
+        __INTRODUCED_IN(33);
+
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 4eb51c4..ac892db 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -144,6 +144,8 @@
 LIBBINDER_NDK33 { # introduced=33
   global:
     AIBinder_Class_disableInterfaceTokenHeader;
+    AParcel_marshal;
+    AParcel_unmarshal;
 };
 
 LIBBINDER_NDK_PLATFORM {
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index b2f21c7..c320e8d 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -673,4 +673,32 @@
     return new AParcel(nullptr);
 }
 
+binder_status_t AParcel_marshal(const AParcel* parcel, uint8_t* buffer, size_t start, size_t len) {
+    if (parcel->get()->objectsCount()) {
+        return STATUS_INVALID_OPERATION;
+    }
+    int32_t dataSize = AParcel_getDataSize(parcel);
+    if (len > static_cast<size_t>(dataSize) || start > static_cast<size_t>(dataSize) - len) {
+        return STATUS_BAD_VALUE;
+    }
+    const uint8_t* internalBuffer = parcel->get()->data();
+    memcpy(buffer, internalBuffer + start, len);
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_unmarshal(AParcel* parcel, const uint8_t* buffer, size_t len) {
+    status_t status = parcel->get()->setDataSize(len);
+    if (status != ::android::OK) {
+        return PruneStatusT(status);
+    }
+    parcel->get()->setDataPosition(0);
+
+    void* raw = parcel->get()->writeInplace(len);
+    if (raw == nullptr) {
+        return STATUS_NO_MEMORY;
+    }
+    memcpy(raw, buffer, len);
+    return STATUS_OK;
+}
+
 // @END