Merge pull request #144 from mer-hybris/jb61406

Add support for writing AIDL FMQs
This commit is contained in:
Slava Monich
2025-09-17 03:55:52 +03:00
committed by GitHub
6 changed files with 249 additions and 56 deletions

View File

@@ -236,7 +236,7 @@ void
gbinder_writer_append_fds(
GBinderWriter* writer,
const GBinderFds* fds,
const GBinderParent* parent); /* Since 1.1.14 */
const GBinderParent* parent); /* Since 1.1.43 */
guint
gbinder_writer_append_buffer_object_with_parent(

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2025 Jolla Mobile Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
@@ -30,13 +31,16 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_fmq_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_reader.h"
#include "gbinder_writer.h"
#include "gbinder_writer_p.h"
#include "gbinder_config.h"
#include "gbinder_log.h"
#include "gbinder_local_object_p.h"
#include <gutil_misc.h>
#include <string.h>
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
@@ -78,6 +82,61 @@ static const GBinderRpcProtocol DEFAULT_PROTOCOL;
static const GBinderRpcProtocol* gbinder_rpc_protocol_default =
&DEFAULT_PROTOCOL;
/*==========================================================================*
* Common AIDL protocol
*==========================================================================*/
void
gbinder_rpc_protocol_aidl_write_fmq_descriptor(
GBinderWriter* writer, const GBinderFmq* queue)
{
GBinderMQDescriptor* desc = gbinder_fmq_get_descriptor(queue);
gssize size_offset;
int i;
gssize fmq_size_offset = gbinder_writer_append_parcelable_start(writer,
queue != NULL);
/* Write the grantors */
GBinderFmqGrantorDescriptor *grantors =
(GBinderFmqGrantorDescriptor *)desc->grantors.data.ptr;
gbinder_writer_append_int32(writer, desc->grantors.count);
for (i = 0; i < desc->grantors.count; i++) {
gssize grantors_size_offset =
gbinder_writer_append_parcelable_start(writer, TRUE);
gbinder_writer_append_int32(writer, grantors[i].fd_index);
gbinder_writer_append_int32(writer, grantors[i].offset);
gbinder_writer_append_int64(writer, grantors[i].extent);
gbinder_writer_append_parcelable_finish(writer, grantors_size_offset);
}
/* Write the native handle */
size_offset = gbinder_writer_append_parcelable_start(writer, TRUE);
gbinder_writer_append_int32(writer, desc->data.fds->num_fds);
for (i = 0; i < desc->data.fds->num_fds; i++) {
gbinder_writer_append_int32(writer, 1);
gbinder_writer_append_int32(writer, 0);
gbinder_writer_append_fd(writer, gbinder_fds_get_fd(desc->data.fds, i));
}
gbinder_writer_append_int32(writer, desc->data.fds->num_ints);
for (i = 0; i < desc->data.fds->num_ints; i++) {
gbinder_writer_append_int32(writer, gbinder_fds_get_fd(desc->data.fds, desc->data.fds->num_fds + i));
}
gbinder_writer_append_parcelable_finish(writer, size_offset);
/* Write the quantum */
gbinder_writer_append_int32(writer, desc->quantum);
/* Write the flags */
gbinder_writer_append_int32(writer, desc->flags);
gbinder_writer_append_parcelable_finish(writer, fmq_size_offset);
}
/*==========================================================================*
* The original AIDL protocol.
*==========================================================================*/
@@ -128,7 +187,8 @@ static const GBinderRpcProtocol gbinder_rpc_protocol_aidl = {
.ping_tx = GBINDER_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_aidl_write_ping,
.write_rpc_header = gbinder_rpc_protocol_aidl_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_aidl_read_rpc_header
.read_rpc_header = gbinder_rpc_protocol_aidl_read_rpc_header,
.write_fmq_descriptor = gbinder_rpc_protocol_aidl_write_fmq_descriptor,
};
/*==========================================================================*
@@ -176,7 +236,8 @@ static const GBinderRpcProtocol gbinder_rpc_protocol_aidl2 = {
.ping_tx = GBINDER_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_aidl_write_ping, /* no payload */
.write_rpc_header = gbinder_rpc_protocol_aidl2_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_aidl2_read_rpc_header
.read_rpc_header = gbinder_rpc_protocol_aidl2_read_rpc_header,
.write_fmq_descriptor = gbinder_rpc_protocol_aidl_write_fmq_descriptor,
};
/*==========================================================================*
@@ -235,7 +296,8 @@ static const GBinderRpcProtocol gbinder_rpc_protocol_aidl3 = {
.write_rpc_header = gbinder_rpc_protocol_aidl3_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_aidl3_read_rpc_header,
.flat_binder_object_extra = 4,
.finish_flatten_binder = gbinder_rpc_protocol_aidl3_finish_flatten_binder
.finish_flatten_binder = gbinder_rpc_protocol_aidl3_finish_flatten_binder,
.write_fmq_descriptor = gbinder_rpc_protocol_aidl_write_fmq_descriptor,
};
/*==========================================================================*
@@ -273,7 +335,8 @@ static const GBinderRpcProtocol gbinder_rpc_protocol_aidl4 = {
.write_rpc_header = gbinder_rpc_protocol_aidl3_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_aidl3_read_rpc_header,
.flat_binder_object_extra = 4,
.finish_flatten_binder = gbinder_rpc_protocol_aidl4_finish_flatten_binder
.finish_flatten_binder = gbinder_rpc_protocol_aidl4_finish_flatten_binder,
.write_fmq_descriptor = gbinder_rpc_protocol_aidl_write_fmq_descriptor,
};
/*==========================================================================*
@@ -312,12 +375,56 @@ gbinder_rpc_protocol_hidl_read_rpc_header(
return gbinder_reader_read_string8(reader);
}
void
gbinder_rpc_protocol_hidl_write_fmq_descriptor(
GBinderWriter* writer, const GBinderFmq* queue)
{
GBinderParent parent;
GBinderMQDescriptor* desc = gbinder_fmq_get_descriptor(queue);
GBinderMQDescriptor* mqdesc = gutil_memdup(desc,
sizeof(GBinderMQDescriptor));
const gsize vec_total =
desc->grantors.count * sizeof(GBinderFmqGrantorDescriptor);
void* vec_buf = gutil_memdup(desc->grantors.data.ptr, vec_total);
const gsize fds_total = sizeof(GBinderFds) +
sizeof(int) * (desc->data.fds->num_fds + desc->data.fds->num_ints);
GBinderFds* fds = gutil_memdup(desc->data.fds, fds_total);
mqdesc->data.fds = fds;
gbinder_writer_add_cleanup(writer, g_free, fds);
/* Fill in the grantor vector descriptor */
if (vec_buf) {
mqdesc->grantors.count = desc->grantors.count;
mqdesc->grantors.data.ptr = vec_buf;
mqdesc->grantors.owns_buffer = TRUE;
gbinder_writer_add_cleanup(writer, g_free, vec_buf);
}
gbinder_writer_add_cleanup(writer, g_free, mqdesc);
/* Write the FMQ descriptor object */
parent.index = gbinder_writer_append_buffer_object(writer,
mqdesc, sizeof(*mqdesc));
/* Write the vector data buffer */
parent.offset = GBINDER_MQ_DESCRIPTOR_GRANTORS_OFFSET;
gbinder_writer_append_buffer_object_with_parent(writer, vec_buf, vec_total,
&parent);
/* Write the fds */
parent.offset = GBINDER_MQ_DESCRIPTOR_FDS_OFFSET;
gbinder_writer_append_fds(writer, mqdesc->data.fds, &parent);
}
static const GBinderRpcProtocol gbinder_rpc_protocol_hidl = {
.name = "hidl",
.ping_tx = HIDL_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_hidl_write_ping,
.write_rpc_header = gbinder_rpc_protocol_hidl_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_hidl_read_rpc_header
.read_rpc_header = gbinder_rpc_protocol_hidl_read_rpc_header,
.write_fmq_descriptor = gbinder_rpc_protocol_hidl_write_fmq_descriptor,
};
/*==========================================================================*

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2025 Jolla Mobile Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
@@ -58,6 +59,7 @@ struct gbinder_rpc_protocol {
gsize flat_binder_object_extra;
void (*finish_flatten_binder)(void* out, GBinderLocalObject* obj);
void (*finish_unflatten_binder)(const void* in, GBinderRemoteObject* obj);
void (*write_fmq_descriptor)(GBinderWriter* writer, const GBinderFmq* queue);
};
const GBinderRpcProtocol*

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2018-2024 Jolla Ltd.
* Copyright (C) 2025 Jolla Mobile Ltd.
* Copyright (C) 2018-2024 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of the BSD license as follows:
@@ -35,6 +36,7 @@
#include "gbinder_fmq_p.h"
#include "gbinder_local_object.h"
#include "gbinder_object_converter.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_io.h"
#include "gbinder_log.h"
@@ -732,6 +734,19 @@ gbinder_writer_data_append_fds(
}
}
void
gbinder_writer_append_fds(
GBinderWriter* self,
const GBinderFds *fds,
const GBinderParent* parent) /* Since 1.0.43 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_fds(data, fds, parent);
}
}
guint
gbinder_writer_append_buffer_object_with_parent(
GBinderWriter* self,
@@ -960,6 +975,61 @@ gbinder_writer_data_append_parcelable(
}
}
/*
* This is compatible with aidl parcelables, and is not guaranteed to work
* with any other kind of parcelable.
* Returns offset needed for overwriting size of parcelable or -1
* if no data is to be written for the parcel.
*/
gssize
gbinder_writer_append_parcelable_start(
GBinderWriter* self,
gboolean has_data)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gssize size_offset = -1;
if (has_data) {
/* Non-null */
gbinder_writer_data_append_int32(data, 1);
size_offset = data->bytes->len;
/*
* Write the dummy parcelable size which is later fixed using
* gbinder_writer_data_append_parcelable_finish.
*/
gbinder_writer_data_append_int32(data, 0);
} else {
/* Null */
gbinder_writer_data_append_int32(data, 0);
}
return size_offset;
}
return -1;
}
/*
* This is compatible with aidl parcelables, and is not guaranteed to work
* with any other kind of parcelable.
* Fixes size of parcelable using offset obtained from
* gbinder_writer_append_parcelable_start. Do nothing if no data was written
* to parceable, i.e. offset is -1.
*/
void
gbinder_writer_append_parcelable_finish(
GBinderWriter* self,
gssize offset)
{
if (offset >= 0) {
/* Replace parcelable size with real value */
gbinder_writer_overwrite_int32(self, offset,
gbinder_writer_bytes_written(self) - offset);
}
}
void
gbinder_writer_append_hidl_string(
GBinderWriter* self,
@@ -1237,51 +1307,6 @@ gbinder_writer_append_byte_array(
#if GBINDER_FMQ_SUPPORTED
static
void
gbinder_writer_data_append_fmq_descriptor(
GBinderWriterData* data,
const GBinderFmq* queue)
{
GBinderParent parent;
GBinderMQDescriptor* desc = gbinder_fmq_get_descriptor(queue);
GBinderMQDescriptor* mqdesc = gutil_memdup(desc,
sizeof(GBinderMQDescriptor));
const gsize vec_total =
desc->grantors.count * sizeof(GBinderFmqGrantorDescriptor);
void* vec_buf = gutil_memdup(desc->grantors.data.ptr, vec_total);
const gsize fds_total = sizeof(GBinderFds) +
sizeof(int) * (desc->data.fds->num_fds + desc->data.fds->num_ints);
GBinderFds* fds = gutil_memdup(desc->data.fds, fds_total);
mqdesc->data.fds = fds;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, fds);
/* Fill in the grantor vector descriptor */
if (vec_buf) {
mqdesc->grantors.count = desc->grantors.count;
mqdesc->grantors.data.ptr = vec_buf;
mqdesc->grantors.owns_buffer = TRUE;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, vec_buf);
}
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, mqdesc);
/* Write the FMQ descriptor object */
parent.index = gbinder_writer_data_append_buffer_object(data,
mqdesc, sizeof(*mqdesc), NULL);
/* Write the vector data buffer */
parent.offset = GBINDER_MQ_DESCRIPTOR_GRANTORS_OFFSET;
gbinder_writer_data_append_buffer_object(data, vec_buf, vec_total,
&parent);
/* Write the fds */
parent.offset = GBINDER_MQ_DESCRIPTOR_FDS_OFFSET;
gbinder_writer_data_append_fds(data, mqdesc->data.fds, &parent);
}
void
gbinder_writer_append_fmq_descriptor(
GBinderWriter* self,
@@ -1290,7 +1315,7 @@ gbinder_writer_append_fmq_descriptor(
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data) && G_LIKELY(queue)) {
gbinder_writer_data_append_fmq_descriptor(data, queue);
data->protocol->write_fmq_descriptor(self, queue);
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2025 Jolla Mobile Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
@@ -177,6 +178,16 @@ gbinder_writer_data_append_fd(
int fd)
GBINDER_INTERNAL;
gssize
gbinder_writer_append_parcelable_start(
GBinderWriter* writer,
gboolean has_data);
void
gbinder_writer_append_parcelable_finish(
GBinderWriter* writer,
gssize offset);
#endif /* GBINDER_WRITER_PRIVATE_H */
/*

View File

@@ -1,6 +1,7 @@
/*
* Copyright (C) 2018-2024 Slava Monich <slava@monich.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2025 Jolla Mobile Ltd.
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -55,13 +56,22 @@
static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-writer-XXXXXX";
static
GBinderLocalRequest*
test_local_request_new_with_io_dev(
const GBinderIo* io,
const char *dev)
{
return gbinder_local_request_new(io,
gbinder_rpc_protocol_for_device(dev), NULL);
}
static
GBinderLocalRequest*
test_local_request_new_with_io(
const GBinderIo* io)
{
return gbinder_local_request_new(io,
gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER), NULL);
return test_local_request_new_with_io_dev(io, GBINDER_DEFAULT_BINDER);
}
static
@@ -78,6 +88,13 @@ test_local_request_new_64()
return test_local_request_new_with_io(&gbinder_io_64);
}
static
GBinderLocalRequest*
test_local_request_new_64_hidl()
{
return test_local_request_new_with_io_dev(&gbinder_io_64, GBINDER_DEFAULT_HWBINDER);
}
/*==========================================================================*
* Test context
*==========================================================================*/
@@ -1466,7 +1483,7 @@ test_fmq_descriptor(
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0);
g_assert(fmq);
req = test_local_request_new_64();
req = test_local_request_new_64_hidl();
gbinder_local_request_init_writer(req, &writer);
gbinder_writer_append_fmq_descriptor(&writer, fmq);
data = gbinder_local_request_data(req);
@@ -1482,6 +1499,36 @@ test_fmq_descriptor(
gbinder_fmq_unref(fmq);
}
static
void
test_fmq_descriptor_aidl(
void)
{
GBinderLocalRequest* req;
GBinderOutputData* data;
GBinderWriter writer;
const gint32 len = 2 * sizeof(gint32) /* FMQ decriptor parcelable header */
+ sizeof(gint32) + 4 * (4 * sizeof(gint32) + sizeof(gint64)) /* grantors + parcelable headers */
+ 2 * sizeof(gint32) /* Native handle parcelable header */
+ sizeof(gint32) + 2 * sizeof(gint32) + 3 * sizeof(gint64) /* fds (1 fd array) */
+ sizeof(gint32) /* ints (0 int array) */
+ sizeof(gint32) /* quantum */
+ sizeof(gint32); /* flags */
GBinderFmq* fmq = gbinder_fmq_new(sizeof(guint32), 5,
GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0);
g_assert(fmq);
req = test_local_request_new_64();
gbinder_local_request_init_writer(req, &writer);
gbinder_writer_append_fmq_descriptor(&writer, fmq);
data = gbinder_local_request_data(req);
g_assert_cmpuint(data->bytes->len, == ,len);
gbinder_local_request_unref(req);
gbinder_fmq_unref(fmq);
}
#endif /* GBINDER_FMQ_SUPPORTED */
/*==========================================================================*
@@ -1610,6 +1657,7 @@ int main(int argc, char* argv[])
} else {
close(test_fd);
g_test_add_func(TEST_("fmq_descriptor"), test_fmq_descriptor);
g_test_add_func(TEST_("fmq_descriptor_aidl"), test_fmq_descriptor_aidl);
}
}
#endif /* GBINDER_FMQ_SUPPORTED */