[gbinder] Add support for writing AIDL FMQs. JB#63597

This commit is contained in:
Matti Lehtimäki
2025-03-28 21:46:56 +02:00
parent a700dddad8
commit ce81ff4a66
2 changed files with 172 additions and 12 deletions

View File

@@ -35,6 +35,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"
@@ -300,6 +301,22 @@ gbinder_writer_data_append_int32(
*ptr = value;
}
void
gbinder_writer_data_overwrite_int32(
GBinderWriterData* data,
gsize offset,
gint32 value)
{
GByteArray* buf = data->bytes;
if (buf->len >= offset + sizeof(gint32)) {
*((gint32*)(buf->data + offset)) = value;
} else {
GWARN("Can't overwrite at %lu as buffer is only %u bytes long",
(gulong)offset, buf->len);
}
}
void
gbinder_writer_overwrite_int32(
GBinderWriter* self,
@@ -309,14 +326,7 @@ gbinder_writer_overwrite_int32(
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
GByteArray* buf = data->bytes;
if (buf->len >= offset + sizeof(gint32)) {
*((gint32*)(buf->data + offset)) = value;
} else {
GWARN("Can't overwrite at %lu as buffer is only %u bytes long",
(gulong)offset, buf->len);
}
gbinder_writer_data_overwrite_int32(data, offset, value);
}
}
@@ -960,6 +970,56 @@ gbinder_writer_data_append_parcelable(
}
}
/*
* This is supposed to be used to write aidl parcelables, and is not
* guaranteed to work on 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_data_append_parcelable_start(
GBinderWriterData* data,
gboolean has_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;
}
/*
* 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_data_append_parcelable_finish(
GBinderWriterData* data,
gssize offset)
{
if (offset >= 0) {
/* Replace parcelable size with real value */
gbinder_writer_data_overwrite_int32(data, offset,
data->bytes->len - offset);
}
}
void
gbinder_writer_append_hidl_string(
GBinderWriter* self,
@@ -1282,6 +1342,52 @@ gbinder_writer_data_append_fmq_descriptor(
gbinder_writer_data_append_fds(data, mqdesc->data.fds, &parent);
}
static
void
gbinder_writer_data_append_fmq_descriptor_aidl(
GBinderWriterData* data,
const GBinderFmq* queue)
{
GBinderMQDescriptor* desc = gbinder_fmq_get_descriptor(queue);
gssize size_offset;
int i;
/* Write the grantors */
GBinderFmqGrantorDescriptor *grantors = (GBinderFmqGrantorDescriptor *)desc->grantors.data.ptr;
gbinder_writer_data_append_int32(data, desc->grantors.count);
for (i = 0; i < desc->grantors.count; i++) {
gssize grantors_size_offset = gbinder_writer_data_append_parcelable_start(data, TRUE);
gbinder_writer_data_append_int32(data, grantors[i].fd_index);
gbinder_writer_data_append_int32(data, grantors[i].offset);
gbinder_writer_data_append_int64(data, grantors[i].extent);
gbinder_writer_data_append_parcelable_finish(data, grantors_size_offset);
}
/* Write the native handle */
size_offset = gbinder_writer_data_append_parcelable_start(data, TRUE);
gbinder_writer_data_append_int32(data, desc->data.fds->num_fds);
for (i = 0; i < desc->data.fds->num_fds; i++) {
gbinder_writer_data_append_int32(data, 1);
gbinder_writer_data_append_int32(data, 0);
gbinder_writer_data_append_fd(data, gbinder_fds_get_fd(desc->data.fds, i));
}
gbinder_writer_data_append_int32(data, desc->data.fds->num_ints);
for (i = 0; i < desc->data.fds->num_ints; i++) {
gbinder_writer_data_append_int32(data, gbinder_fds_get_fd(desc->data.fds, desc->data.fds->num_fds + i));
}
gbinder_writer_data_append_parcelable_finish(data, size_offset);
/* Write the quantum */
gbinder_writer_data_append_int32(data, desc->quantum);
/* Write the flagss */
gbinder_writer_data_append_int32(data, desc->flags);
}
void
gbinder_writer_append_fmq_descriptor(
GBinderWriter* self,
@@ -1290,7 +1396,14 @@ 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);
if (g_str_has_prefix(data->protocol->name, "aidl")) {
gssize size_offset = gbinder_writer_data_append_parcelable_start(data,
queue != NULL);
gbinder_writer_data_append_fmq_descriptor_aidl(data, queue);
gbinder_writer_data_append_parcelable_finish(data, size_offset);
} else {
gbinder_writer_data_append_fmq_descriptor(data, queue);
}
}
}

View File

@@ -55,13 +55,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 +87,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 +1482,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 +1498,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 +1656,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 */