Merge pull request #7 from monich/hidl_vec

Add gbinder_writer_append_hidl_vec() and gbinder_reader_read_hidl_vec()
This commit is contained in:
Slava Monich
2018-09-25 01:05:39 +03:00
committed by GitHub
7 changed files with 425 additions and 16 deletions

View File

@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -113,6 +113,12 @@ gbinder_reader_read_buffer(
GBinderReader* reader)
G_GNUC_WARN_UNUSED_RESULT;
const void*
gbinder_reader_read_hidl_vec(
GBinderReader* reader,
gsize* count,
gsize* elemsize);
char*
gbinder_reader_read_hidl_string(
GBinderReader* reader)

View File

@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -121,6 +121,13 @@ gbinder_writer_append_buffer_object(
const void* buf,
gsize len);
void
gbinder_writer_append_hidl_vec(
GBinderWriter* writer,
const void* base,
guint count,
guint elemsize); /* since 1.0.8 */
void
gbinder_writer_append_hidl_string(
GBinderWriter* writer,

View File

@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -305,6 +305,46 @@ gbinder_reader_skip_buffer(
return gbinder_reader_read_buffer_impl(reader, NULL);
}
/* Doesn't copy the data */
const void*
gbinder_reader_read_hidl_vec(
GBinderReader* reader,
gsize* count,
gsize* elemsize)
{
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
gsize out_count = 0, out_elemsize = 0;
const void* out = NULL;
if (buf && buf->size == sizeof(HidlVec)) {
const HidlVec* vec = buf->data;
const void* next = vec->data.ptr;
if (next) {
GBinderBuffer* vbuf = gbinder_reader_read_buffer(reader);
if (vbuf && vbuf->data == next && ((!vec->count && !vbuf->size) ||
(vec->count && vbuf->size && !(vbuf->size % vec->count)))) {
out_elemsize = vec->count ? (vbuf->size / vec->count) : 0;
out_count = vec->count;
out = vbuf->data;
}
gbinder_buffer_free(vbuf);
} else if (!vec->count) {
/* Any non-NULL pointer just to indicate success */
out = vec;
}
}
gbinder_buffer_free(buf);
if (elemsize) {
*elemsize = out_elemsize;
}
if (count) {
*count = out_count;
}
return out;
}
char*
gbinder_reader_read_hidl_string(
GBinderReader* reader)

View File

@@ -490,6 +490,54 @@ gbinder_writer_append_hidl_string(
}
}
void
gbinder_writer_data_append_hidl_vec(
GBinderWriterData* data,
const void* base,
guint count,
guint elemsize)
{
GBinderParent vec_parent;
HidlVec* vec = g_new0(HidlVec, 1);
const gsize total = count * elemsize;
void* buf = g_memdup(base, total);
/* Prepare parent descriptor for the string data */
vec_parent.index = gbinder_writer_data_prepare(data);
vec_parent.offset = HIDL_VEC_BUFFER_OFFSET;
/* Fill in the vector descriptor */
if (buf) {
vec->data.ptr = buf;
vec->count = count;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, buf);
}
vec->owns_buffer = TRUE;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, vec);
/* Write the buffer object pointing to the vector descriptor */
gbinder_writer_data_write_buffer_object(data, vec, sizeof(*vec), NULL);
/* Not sure what's the right way to deal with NULL vectors... */
if (buf) {
gbinder_writer_data_write_buffer_object(data, buf, total, &vec_parent);
}
}
void
gbinder_writer_append_hidl_vec(
GBinderWriter* self,
const void* base,
guint count,
guint elemsize)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_hidl_vec(data, base, count, elemsize);
}
}
void
gbinder_writer_data_append_hidl_string(
GBinderWriterData* data,

View File

@@ -110,6 +110,13 @@ gbinder_writer_data_append_buffer_object(
gsize size,
const GBinderParent* parent);
void
gbinder_writer_data_append_hidl_vec(
GBinderWriterData* data,
const void* base,
guint count,
guint elemsize);
void
gbinder_writer_data_append_hidl_string(
GBinderWriterData* data,

View File

@@ -37,13 +37,17 @@
#include "gbinder_ipc.h"
#include "gbinder_reader_p.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_io.h"
static TestOpt test_opt;
typedef struct binder_buffer_object_64 {
guint32 type;
guint32 flags;
guint64 buffer;
union {
const void* ptr;
guint64 value;
} buffer;
guint64 length;
guint64 parent;
guint64 parent_offset;
@@ -51,6 +55,9 @@ typedef struct binder_buffer_object_64 {
#define BINDER_TYPE_HANDLE GBINDER_FOURCC('s','h','*',0x85)
#define BINDER_TYPE_PTR GBINDER_FOURCC('p','t','*',0x85)
#define BINDER_BUFFER_FLAG_HAS_PARENT 0x01
#define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE)
G_STATIC_ASSERT(sizeof(BinderObject64) == BUFFER_OBJECT_SIZE_64);
/*==========================================================================*
* empty
@@ -62,6 +69,7 @@ test_empty(
void)
{
GBinderReader reader;
gsize count = 1, elemsize = 1;
gbinder_reader_init(&reader, NULL, 0, 0);
g_assert(gbinder_reader_at_end(&reader));
@@ -78,6 +86,10 @@ test_empty(
g_assert(!gbinder_reader_read_object(&reader));
g_assert(!gbinder_reader_read_nullable_object(&reader, NULL));
g_assert(!gbinder_reader_read_buffer(&reader));
g_assert(!gbinder_reader_read_hidl_vec(&reader, NULL, NULL));
g_assert(!gbinder_reader_read_hidl_vec(&reader, &count, &elemsize));
g_assert(!count);
g_assert(!elemsize);
g_assert(!gbinder_reader_read_hidl_string(&reader));
g_assert(!gbinder_reader_read_hidl_string_vec(&reader));
g_assert(!gbinder_reader_skip_buffer(&reader));
@@ -503,6 +515,216 @@ test_string16(
gbinder_driver_unref(driver);
}
/*==========================================================================*
* hidl_vec
*==========================================================================*/
typedef struct test_hidl_vec {
const char* name;
const void* in;
guint in_size;
const guint* offset;
guint offset_count;
const void* data;
guint count;
guint elemsize;
} TestHidlVec;
static const guint test_hidl_vec_2offsets [] = { 0, BUFFER_OBJECT_SIZE_64 };
static const guint8 test_hidl_vec_2bytes_data [] = { 0x01, 0x02 };
static const HidlVec test_hidl_vec_2bytes = {
.data.ptr = test_hidl_vec_2bytes_data,
sizeof(test_hidl_vec_2bytes_data),
TRUE
};
static const BinderObject64 test_hidl_vec_2bytes_buf [] = {
{
BINDER_TYPE_PTR, 0,
{ &test_hidl_vec_2bytes },
sizeof(HidlVec), 0, 0
},{
BINDER_TYPE_PTR, 0,
{ test_hidl_vec_2bytes_data },
sizeof(test_hidl_vec_2bytes_data), 0, 0
}
};
static const HidlVec test_hidl_vec_empty = {
.data.ptr = test_hidl_vec_2bytes_data, 0, TRUE
};
static const BinderObject64 test_hidl_vec_empty_buf [] = {
{
BINDER_TYPE_PTR, 0,
{ &test_hidl_vec_empty },
sizeof(HidlVec), 0, 0
},{
BINDER_TYPE_PTR, BINDER_BUFFER_FLAG_HAS_PARENT,
{ test_hidl_vec_2bytes_data },
0, 0, 0
}
};
static const guint test_hidl_vec_1offset [] = {0};
static const HidlVec test_hidl_vec_null = {{0}, 0, TRUE};
static const BinderObject64 test_hidl_vec_null_buf [] = {
{
BINDER_TYPE_PTR, 0,
{ &test_hidl_vec_null },
sizeof(HidlVec), 0, 0
}
};
/* Buffer smaller than HidlVec */
static const BinderObject64 test_hidl_vec_short_buf [] = {
{
BINDER_TYPE_PTR, 0,
{ &test_hidl_vec_empty },
sizeof(HidlVec) - 1, 0, 0
}
};
/* NULL buffer with size 1 */
static const guint test_hidl_vec_badnull_offsets [] = {0};
static const HidlVec test_hidl_vec_badnull = {{0}, 1, TRUE};
static const BinderObject64 test_hidl_vec_badnull_buf [] = {
{
BINDER_TYPE_PTR, 0,
{ &test_hidl_vec_badnull },
sizeof(HidlVec), 0, 0
}
};
/* Buffer size not divisible by count */
static const guint8 test_hidl_vec_badsize_data [] = { 0x01, 0x02, 0x03 };
static const HidlVec test_hidl_vec_badsize = {
.data.ptr = test_hidl_vec_badsize_data, 2, TRUE
};
static const BinderObject64 test_hidl_vec_badsize_buf [] = {
{
BINDER_TYPE_PTR, 0,
{ &test_hidl_vec_badsize },
sizeof(HidlVec), 0, 0
},{
BINDER_TYPE_PTR, BINDER_BUFFER_FLAG_HAS_PARENT,
{ test_hidl_vec_badsize_data },
sizeof(test_hidl_vec_badsize_data), 0, 0
}
};
/* Bad buffer address */
static const guint8 test_hidl_vec_badbuf_data [] = { 0x01, 0x02, 0x03 };
static const HidlVec test_hidl_vec_badbuf = {
.data.ptr = test_hidl_vec_badbuf_data,
sizeof(test_hidl_vec_badbuf_data), TRUE
};
static const BinderObject64 test_hidl_vec_badbuf_buf [] = {
{
BINDER_TYPE_PTR, 0,
{ &test_hidl_vec_badbuf },
sizeof(HidlVec), 0, 0
},{
BINDER_TYPE_PTR, BINDER_BUFFER_FLAG_HAS_PARENT,
{ test_hidl_vec_badsize_data },
sizeof(test_hidl_vec_badsize_data), 0, 0
}
};
/* Non-zero count and zero size */
static const HidlVec test_hidl_vec_badcount1 = {
.data.ptr = test_hidl_vec_badsize_data, 1, TRUE
};
static const BinderObject64 test_hidl_vec_badcount1_buf [] = {
{
BINDER_TYPE_PTR, 0,
{ &test_hidl_vec_badcount1 },
sizeof(HidlVec), 0, 0
},{
BINDER_TYPE_PTR, BINDER_BUFFER_FLAG_HAS_PARENT,
{ test_hidl_vec_badsize_data },
0, 0, 0
}
};
/* Zero count0 and non-zero size */
static const HidlVec test_hidl_vec_badcount2 = {
.data.ptr = test_hidl_vec_badsize_data, 0, TRUE
};
static const BinderObject64 test_hidl_vec_badcount2_buf [] = {
{
BINDER_TYPE_PTR, 0,
{ &test_hidl_vec_badcount2 },
sizeof(HidlVec), 0, 0
},{
BINDER_TYPE_PTR, BINDER_BUFFER_FLAG_HAS_PARENT,
{ test_hidl_vec_badsize_data },
sizeof(test_hidl_vec_badsize_data), 0, 0
}
};
static const TestHidlVec test_hidl_vec_tests[] = {
{ "2bytes", TEST_ARRAY_AND_SIZE(test_hidl_vec_2bytes_buf),
TEST_ARRAY_AND_SIZE(test_hidl_vec_2offsets),
TEST_ARRAY_AND_SIZE(test_hidl_vec_2bytes_data), 1 },
{ "empty", TEST_ARRAY_AND_SIZE(test_hidl_vec_empty_buf),
TEST_ARRAY_AND_SIZE(test_hidl_vec_2offsets),
test_hidl_vec_2bytes_data, 0, 0 },
{ "null", TEST_ARRAY_AND_SIZE(test_hidl_vec_null_buf),
TEST_ARRAY_AND_SIZE(test_hidl_vec_1offset),
&test_hidl_vec_null, 0, 0 },
{ "missingbuf", test_hidl_vec_2bytes_buf,
sizeof(test_hidl_vec_2bytes_buf[0]),
TEST_ARRAY_AND_SIZE(test_hidl_vec_1offset), NULL, 0, 0 },
{ "shortbuf", TEST_ARRAY_AND_SIZE(test_hidl_vec_short_buf),
TEST_ARRAY_AND_SIZE(test_hidl_vec_1offset), NULL, 0, 0 },
{ "badnull", TEST_ARRAY_AND_SIZE(test_hidl_vec_badnull_buf),
TEST_ARRAY_AND_SIZE(test_hidl_vec_1offset), NULL, 0, 0 },
{ "badsize", TEST_ARRAY_AND_SIZE(test_hidl_vec_badsize_buf),
TEST_ARRAY_AND_SIZE(test_hidl_vec_2offsets), NULL, 0, 0 },
{ "badbuf", TEST_ARRAY_AND_SIZE(test_hidl_vec_badbuf_buf),
TEST_ARRAY_AND_SIZE(test_hidl_vec_2offsets), NULL, 0, 0 },
{ "badcount1", TEST_ARRAY_AND_SIZE(test_hidl_vec_badcount1_buf),
TEST_ARRAY_AND_SIZE(test_hidl_vec_2offsets), NULL, 0, 0 },
{ "badcount2", TEST_ARRAY_AND_SIZE(test_hidl_vec_badcount2_buf),
TEST_ARRAY_AND_SIZE(test_hidl_vec_2offsets), NULL, 0, 0 }
};
static
void
test_hidl_vec(
gconstpointer test_data)
{
const TestHidlVec* test = test_data;
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size);
GBinderReaderData data;
GBinderReader reader;
gsize n = 0, elem = 0;
g_assert(ipc);
memset(&data, 0, sizeof(data));
data.buffer = buf;
data.reg = gbinder_ipc_object_registry(ipc);
if (test->offset) {
guint i;
data.objects = g_new(void*, test->offset_count + 1);
for (i = 0; i < test->offset_count; i++) {
data.objects[i] = (guint8*)buf->data + test->offset[i];
}
data.objects[i] = NULL;
}
gbinder_reader_init(&reader, &data, 0, test->in_size);
g_assert(gbinder_reader_read_hidl_vec(&reader, &n, &elem) == test->data);
g_assert(n == test->count);
g_assert(elem == test->elemsize);
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* hidl_string_err
*==========================================================================*/
@@ -517,7 +739,7 @@ typedef struct test_hidl_string_err {
static const guint8 test_hidl_string_err_short [] = { 0x00 };
static const guint8 test_hidl_string_err_empty [] = {
TEST_INT32_BYTES(GBINDER_FOURCC('p', 't', '*', 0x85)),
TEST_INT32_BYTES(BINDER_TYPE_PTR),
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -693,7 +915,7 @@ test_vec(
memset(&vec, 0, sizeof(vec));
memset(&obj, 0, sizeof(obj));
obj.type = BINDER_TYPE_PTR;
obj.buffer = (gsize)&vec;
obj.buffer.ptr = &vec;
/* This one will fail because the buffer is one byte short */
obj.length = sizeof(vec) - 1;
@@ -759,6 +981,15 @@ int main(int argc, char* argv[])
g_free(path);
}
for (i = 0; i < G_N_ELEMENTS(test_hidl_vec_tests); i++) {
const TestHidlVec* test = test_hidl_vec_tests + i;
char* path = g_strconcat(TEST_PREFIX "/hidl_vec/", test->name,
NULL);
g_test_add_data_func(path, test, test_hidl_vec);
g_free(path);
}
for (i = 0; i < G_N_ELEMENTS(test_hidl_string_err_tests); i++) {
const TestHidlStringErr* test = test_hidl_string_err_tests + i;
char* path = g_strconcat(TEST_PREFIX "/hidl_string/err-", test->name,

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -78,6 +78,7 @@ test_null(
gbinder_writer_append_bool(&writer, FALSE);
gbinder_writer_append_bytes(NULL, NULL, 0);
gbinder_writer_append_bytes(&writer, NULL, 0);
gbinder_writer_append_hidl_vec(NULL, NULL, 0, 0);
gbinder_writer_append_hidl_string(NULL, NULL);
gbinder_writer_append_hidl_string(&writer, NULL);
gbinder_writer_append_hidl_string_vec(NULL, NULL, 0);
@@ -339,6 +340,67 @@ test_string16(
gbinder_local_request_unref(req);
}
/*==========================================================================*
* hidl_vec
*==========================================================================*/
typedef struct test_hidl_vec_data {
const char* name;
const GBinderIo* io;
const void* data;
const gsize count;
const gsize elemsize;
const guint* offsets;
guint offsets_count;
guint buffers_size;
} TestHidlVecData;
static guint test_hidl_vec_offsets_0[] =
{ 0 };
static guint test_hidl_vec_offsets_32[] =
{ 0, BUFFER_OBJECT_SIZE_32 };
static guint test_hidl_vec_offsets_64[] =
{ 0, BUFFER_OBJECT_SIZE_64 };
static const TestHidlVecData test_hidl_vec_tests[] = {
{ "32/null", &gbinder_io_32, NULL, 0, 0,
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(HidlVec) },
{ "32/2x1", &gbinder_io_32, "xy", 2, 1,
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_32),
sizeof(HidlVec) + 8 /* vec data aligned at 8 bytes boundary */ },
{ "64/null", &gbinder_io_64, NULL, 0, 0,
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(HidlVec) },
{ "64/2x2", &gbinder_io_64, "xxyy", 2, 2,
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_64),
sizeof(HidlVec) + 8 /* vec data aligned at 8 bytes boundary */ }
};
static
void
test_hidl_vec(
gconstpointer test_data)
{
const TestHidlVecData* test = test_data;
GBinderLocalRequest* req = gbinder_local_request_new(test->io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
GUtilIntArray* offsets;
guint i;
gbinder_local_request_init_writer(req, &writer);
gbinder_writer_append_hidl_vec(&writer, test->data,
test->count, test->elemsize);
data = gbinder_local_request_data(req);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets);
g_assert(offsets->count == test->offsets_count);
for (i = 0; i < offsets->count; i++) {
g_assert(offsets->data[i] == test->offsets[i]);
}
g_assert(gbinder_output_data_buffers_size(data) == test->buffers_size);
gbinder_local_request_unref(req);
}
/*==========================================================================*
* hidl_string
*==========================================================================*/
@@ -649,6 +711,14 @@ int main(int argc, char* argv[])
g_free(path);
}
for (i = 0; i < G_N_ELEMENTS(test_hidl_vec_tests); i++) {
const TestHidlVecData* test = test_hidl_vec_tests + i;
char* path = g_strconcat(TEST_PREFIX "hidl_vec/", test->name, NULL);
g_test_add_data_func(path, test, test_hidl_vec);
g_free(path);
}
g_test_add_func(TEST_PREFIX "hidl_string/2strings", test_hidl_string2);
for (i = 0; i < G_N_ELEMENTS(test_hidl_string_tests); i++) {
const TestHidlStringData* test = test_hidl_string_tests + i;