libbinder_ndk: read/write string array
Bug: 111445392
Test: atest android.binder.cts
Change-Id: I75fd01d8e1c170aac2063b5c466767e111e5787a
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index d9f469ba..3b44a62 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -273,8 +273,8 @@
return STATUS_OK;
}
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringAllocator allocator,
- void* stringData) {
+binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
+ AParcel_stringAllocator allocator) {
size_t len16;
const char16_t* str16 = parcel->get()->readString16Inplace(&len16);
@@ -291,7 +291,7 @@
len8 = utf16_to_utf8_length(str16, len16) + 1;
}
- if (len8 <= 0 || len8 >= std::numeric_limits<int32_t>::max()) {
+ if (len8 <= 0 || len8 > std::numeric_limits<int32_t>::max()) {
LOG(WARNING) << __func__ << ": Invalid string length: " << len8;
return STATUS_BAD_VALUE;
}
@@ -308,6 +308,68 @@
return STATUS_OK;
}
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length,
+ AParcel_stringArrayElementGetter getter) {
+ if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
+
+ Parcel* rawParcel = parcel->get();
+
+ status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
+ if (status != STATUS_OK) return PruneStatusT(status);
+
+ for (size_t i = 0; i < length; i++) {
+ size_t length = 0;
+ const char* str = getter(arrayData, i, &length);
+ if (str == nullptr) return STATUS_BAD_VALUE;
+
+ binder_status_t status = AParcel_writeString(parcel, str, length);
+ if (status != STATUS_OK) return status;
+ }
+
+ return STATUS_OK;
+}
+
+// This implements AParcel_stringAllocator for a string using an array, index, and element
+// allocator.
+struct StringArrayElementAllocationAdapter {
+ void* arrayData; // stringData from the NDK
+ size_t index; // index into the string array
+ AParcel_stringArrayElementAllocator elementAllocator;
+
+ static char* Allocator(void* stringData, size_t length) {
+ StringArrayElementAllocationAdapter* adapter =
+ static_cast<StringArrayElementAllocationAdapter*>(stringData);
+ return adapter->elementAllocator(adapter->arrayData, adapter->index, length);
+ }
+};
+
+binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
+ AParcel_stringArrayAllocator allocator,
+ AParcel_stringArrayElementAllocator elementAllocator) {
+ const Parcel* rawParcel = parcel->get();
+
+ int32_t length;
+ status_t status = rawParcel->readInt32(&length);
+
+ if (status != STATUS_OK) return PruneStatusT(status);
+ if (length < 0) return STATUS_UNEXPECTED_NULL;
+
+ if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+ StringArrayElementAllocationAdapter adapter{
+ .arrayData = arrayData,
+ .index = 0,
+ .elementAllocator = elementAllocator,
+ };
+
+ for (; adapter.index < length; adapter.index++) {
+ AParcel_readString(parcel, static_cast<void*>(&adapter),
+ StringArrayElementAllocationAdapter::Allocator);
+ }
+
+ return STATUS_OK;
+}
+
// See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
// libbinder and this library.
// @START