diff options
author | Steven Moreland <smoreland@google.com> | 2018-10-03 19:25:32 -0700 |
---|---|---|
committer | Steven Moreland <smoreland@google.com> | 2018-10-08 11:23:42 -0700 |
commit | 7b06f592bbf9beb1239a211faa14541ad0d5176b (patch) | |
tree | ab8dc0bf876aa20cb55c263d45f3d330b44c05c1 | |
parent | cd1ce760e8109eb91ce9d3e91fdaabb866262045 (diff) | |
download | native-7b06f592bbf9beb1239a211faa14541ad0d5176b.tar.gz |
libbinder_ndk: add read/write string methods.
utf16 is left on the wire, but utf8 is exposed in the NDK.
Bug: 111445392
Test: atest android.binder.cts
Change-Id: Ie4f19ba52dc2323b1c6cf0c4b5e60c7bf2802cf8
-rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel.h | 37 | ||||
-rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_parcel_utils.h | 71 | ||||
-rw-r--r-- | libs/binder/ndk/libbinder_ndk.map.txt | 2 | ||||
-rw-r--r-- | libs/binder/ndk/parcel.cpp | 65 |
4 files changed, 175 insertions, 0 deletions
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h index a3800da160..0e97b507c5 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -88,6 +88,43 @@ binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) __INTRODUCED_IN(29); +/** + * Writes string value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) + __INTRODUCED_IN(29); + +/** + * This is called to allocate a buffer + * + * The length here includes the space required to insert a '\0' for a properly formed c-str. If the + * buffer returned from this function is retStr, it will be filled by AParcel_readString with the + * data from the remote process, and it will be filled such that retStr[length] == '\0'. + * + * If allocation fails, null should be returned. + */ +typedef void* (*AParcel_string_reallocator)(void* stringData, size_t length); + +/** + * This is called to get the buffer from a stringData object. + */ +typedef char* (*AParcel_string_getter)(void* stringData); + +/** + * Reads and allocates string value from the next location in a non-null parcel. + * + * Data is passed to the string allocator once the string size is known. This data should be used to + * point to some kind of string data. For instance, it could be a char*, and the string allocator + * could be realloc. Then the getter would simply be a cast to char*. In more complicated cases, + * stringData could be a structure containing additional string data. + * + * If this function returns a success, the buffer returned by allocator when passed stringData will + * contain a null-terminated c-str read from the binder. + */ +binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator, + AParcel_string_getter getter, void** stringData) + __INTRODUCED_IN(29); + // @START /** * Writes int32_t value to the next location in a non-null parcel. diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h new file mode 100644 index 0000000000..7b261d6f98 --- /dev/null +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 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. + */ + +/** + * @addtogroup NdkBinder + * @{ + */ + +/** + * @file binder_parcel_utils.h + * @brief A collection of helper wrappers for AParcel. + */ + +#pragma once + +#include <android/binder_parcel.h> + +#ifdef __cplusplus + +#include <string> + +/** + * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString. + * See use below in AParcel_readString. + */ +static inline void* AParcel_std_string_reallocator(void* stringData, size_t length) { + std::string* str = static_cast<std::string*>(stringData); + str->resize(length - 1); + return stringData; +} + +/** + * Takes a std::string and returns the inner char*. + */ +static inline char* AParcel_std_string_getter(void* stringData) { + std::string* str = static_cast<std::string*>(stringData); + return &(*str)[0]; +} + +/** + * Convenience API for writing a std::string. + */ +static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) { + return AParcel_writeString(parcel, str.c_str(), str.size()); +} + +/** + * Convenience API for reading a std::string. + */ +static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) { + void* stringData = static_cast<void*>(str); + return AParcel_readString(parcel, AParcel_std_string_reallocator, AParcel_std_string_getter, + &stringData); +} + +#endif // __cplusplus + +/** @} */ diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 4f486c99ba..2a1bff131c 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -32,6 +32,7 @@ LIBBINDER_NDK { # introduced=29 AParcel_readInt64; AParcel_readNullableStrongBinder; AParcel_readStatusHeader; + AParcel_readString; AParcel_readStrongBinder; AParcel_readUint32; AParcel_readUint64; @@ -43,6 +44,7 @@ LIBBINDER_NDK { # introduced=29 AParcel_writeInt32; AParcel_writeInt64; AParcel_writeStatusHeader; + AParcel_writeString; AParcel_writeStrongBinder; AParcel_writeUint32; AParcel_writeUint64; diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index 385e898aeb..3e03e907bb 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -20,7 +20,11 @@ #include "ibinder_internal.h" #include "status_internal.h" +#include <limits> + +#include <android-base/logging.h> #include <binder/Parcel.h> +#include <utils/Unicode.h> using ::android::IBinder; using ::android::Parcel; @@ -69,6 +73,67 @@ binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status return ret; } +binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) { + const uint8_t* str8 = (uint8_t*)string; + + const ssize_t len16 = utf8_to_utf16_length(str8, length); + + if (len16 < 0 || len16 >= std::numeric_limits<int32_t>::max()) { + LOG(WARNING) << __func__ << ": Invalid string length: " << len16; + return STATUS_BAD_VALUE; + } + + status_t err = parcel->get()->writeInt32(len16); + if (err) { + return PruneStatusT(err); + } + + void* str16 = parcel->get()->writeInplace((len16 + 1) * sizeof(char16_t)); + if (str16 == nullptr) { + return STATUS_NO_MEMORY; + } + + utf8_to_utf16(str8, length, (char16_t*)str16, (size_t)len16 + 1); + + return STATUS_OK; +} + +binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator, + AParcel_string_getter getter, void** stringData) { + size_t len16; + const char16_t* str16 = parcel->get()->readString16Inplace(&len16); + + if (str16 == nullptr) { + LOG(WARNING) << __func__ << ": Failed to read string in place."; + return STATUS_UNEXPECTED_NULL; + } + + ssize_t len8; + + if (len16 == 0) { + len8 = 1; + } else { + len8 = utf16_to_utf8_length(str16, len16) + 1; + } + + if (len8 <= 0 || len8 >= std::numeric_limits<int32_t>::max()) { + LOG(WARNING) << __func__ << ": Invalid string length: " << len8; + return STATUS_BAD_VALUE; + } + + *stringData = reallocator(*stringData, len8); + char* str8 = getter(*stringData); + + if (str8 == nullptr) { + LOG(WARNING) << __func__ << ": AParcel_string_allocator failed to allocate."; + return STATUS_NO_MEMORY; + } + + utf16_to_utf8(str16, len16, str8, len8); + + return STATUS_OK; +} + // See gen_parcel_helper.py. These auto-generated read/write methods use the same types for // libbinder and this library. // @START |