Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a324ee1 authored by Steven Moreland's avatar Steven Moreland Committed by android-build-merger
Browse files

libbinder_ndk: add read/write string methods.

am: 7b06f592

Change-Id: Idf86f7dd6b5280f9c416730de701cb8cf84b7e78
parents 9a61015c 7b06f592
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -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.
+71 −0
Original line number Diff line number Diff line
/*
 * 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

/** @} */
+2 −0
Original line number Diff line number Diff line
@@ -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;
+65 −0
Original line number Diff line number Diff line
@@ -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