[gbinder] Support for file descriptors. JB#42956
gbinder_writer_append_fd() duplicates the descriptor and appends the duplicate to the parcel. The caller may immediately close its descriptor. gbinder_reader_read_fd() fetches the descriptor from the parcel without duplicating it. The descrriptor will be closed as soon as the library has finished processing the request. Returns -1 on error. gbinder_reader_read_dup_fd() fetches descriptor from the parcel and dups it. The caller is responsible for closing the returned descriptor. Returns -1 on failure.
This commit is contained in:
parent
5a43b1b091
commit
c39bf4b802
|
@ -95,6 +95,15 @@ gbinder_reader_read_double(
|
||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
gdouble* value);
|
gdouble* value);
|
||||||
|
|
||||||
|
int
|
||||||
|
gbinder_reader_read_fd(
|
||||||
|
GBinderReader* reader); /* Since 1.0.18 */
|
||||||
|
|
||||||
|
int
|
||||||
|
gbinder_reader_read_dup_fd(
|
||||||
|
GBinderReader* reader) /* Since 1.0.18 */
|
||||||
|
G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_reader_read_nullable_object(
|
gbinder_reader_read_nullable_object(
|
||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
|
|
|
@ -114,6 +114,11 @@ gbinder_writer_append_bytes(
|
||||||
const void* data,
|
const void* data,
|
||||||
gsize size);
|
gsize size);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_writer_append_fd(
|
||||||
|
GBinderWriter* writer,
|
||||||
|
int fd); /* Since 1.0.18 */
|
||||||
|
|
||||||
guint
|
guint
|
||||||
gbinder_writer_append_buffer_object_with_parent(
|
gbinder_writer_append_buffer_object_with_parent(
|
||||||
GBinderWriter* writer,
|
GBinderWriter* writer,
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
@ -48,11 +48,33 @@ struct gbinder_cleanup {
|
||||||
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
|
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
|
||||||
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
|
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_cleanup_destroy_func(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GBinderCleanupItem* item = data;
|
||||||
|
|
||||||
|
item->destroy(item->pointer);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
GBinderCleanup*
|
GBinderCleanup*
|
||||||
gbinder_cleanup_new()
|
gbinder_cleanup_new()
|
||||||
{
|
{
|
||||||
return (GBinderCleanup*)g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
|
GArray* array = g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
|
||||||
|
|
||||||
|
g_array_set_clear_func(array, gbinder_cleanup_destroy_func);
|
||||||
|
return (GBinderCleanup*)array;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_cleanup_reset(
|
||||||
|
GBinderCleanup* self)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
g_array_set_size((GArray*)self, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -60,11 +82,6 @@ gbinder_cleanup_free(
|
||||||
GBinderCleanup* self)
|
GBinderCleanup* self)
|
||||||
{
|
{
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
guint i;
|
|
||||||
|
|
||||||
for (i = 0; i < self->count; i++) {
|
|
||||||
self->items[i].destroy(self->items[i].pointer);
|
|
||||||
}
|
|
||||||
g_array_free((GArray*)self, TRUE);
|
g_array_free((GArray*)self, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
@ -39,6 +39,10 @@ void
|
||||||
gbinder_cleanup_free(
|
gbinder_cleanup_free(
|
||||||
GBinderCleanup* cleanup);
|
GBinderCleanup* cleanup);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_cleanup_reset(
|
||||||
|
GBinderCleanup* cleanup);
|
||||||
|
|
||||||
GBinderCleanup*
|
GBinderCleanup*
|
||||||
gbinder_cleanup_add(
|
gbinder_cleanup_add(
|
||||||
GBinderCleanup* cleanup,
|
GBinderCleanup* cleanup,
|
||||||
|
|
|
@ -153,6 +153,21 @@ GBINDER_IO_FN(encode_remote_object)(
|
||||||
return sizeof(*dest);
|
return sizeof(*dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
guint
|
||||||
|
GBINDER_IO_FN(encode_fd_object)(
|
||||||
|
void* out,
|
||||||
|
int fd)
|
||||||
|
{
|
||||||
|
struct flat_binder_object* dest = out;
|
||||||
|
|
||||||
|
memset(dest, 0, sizeof(*dest));
|
||||||
|
dest->hdr.type = BINDER_TYPE_FD;
|
||||||
|
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
||||||
|
dest->handle = fd;
|
||||||
|
return sizeof(*dest);
|
||||||
|
}
|
||||||
|
|
||||||
/* Encodes binder_buffer_object */
|
/* Encodes binder_buffer_object */
|
||||||
static
|
static
|
||||||
guint
|
guint
|
||||||
|
@ -488,6 +503,7 @@ const GBinderIo GBINDER_IO_PREFIX = {
|
||||||
.encode_pointer = GBINDER_IO_FN(encode_pointer),
|
.encode_pointer = GBINDER_IO_FN(encode_pointer),
|
||||||
.encode_local_object = GBINDER_IO_FN(encode_local_object),
|
.encode_local_object = GBINDER_IO_FN(encode_local_object),
|
||||||
.encode_remote_object = GBINDER_IO_FN(encode_remote_object),
|
.encode_remote_object = GBINDER_IO_FN(encode_remote_object),
|
||||||
|
.encode_fd_object = GBINDER_IO_FN(encode_fd_object),
|
||||||
.encode_buffer_object = GBINDER_IO_FN(encode_buffer_object),
|
.encode_buffer_object = GBINDER_IO_FN(encode_buffer_object),
|
||||||
.encode_death_notification = GBINDER_IO_FN(encode_death_notification),
|
.encode_death_notification = GBINDER_IO_FN(encode_death_notification),
|
||||||
.encode_transaction = GBINDER_IO_FN(encode_transaction),
|
.encode_transaction = GBINDER_IO_FN(encode_transaction),
|
||||||
|
|
|
@ -131,6 +131,7 @@ struct gbinder_io {
|
||||||
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
|
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
|
||||||
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
|
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
|
||||||
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
|
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
|
||||||
|
guint (*encode_fd_object)(void* out, int fd);
|
||||||
|
|
||||||
/* Encode binder_buffer_object */
|
/* Encode binder_buffer_object */
|
||||||
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
|
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
|
||||||
|
|
|
@ -38,6 +38,9 @@
|
||||||
|
|
||||||
#include <gutil_macros.h>
|
#include <gutil_macros.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
typedef struct gbinder_reader_priv {
|
typedef struct gbinder_reader_priv {
|
||||||
const guint8* start;
|
const guint8* start;
|
||||||
const guint8* end;
|
const guint8* end;
|
||||||
|
@ -231,16 +234,67 @@ gbinder_reader_read_double(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
gboolean
|
||||||
|
gbinder_reader_can_read_object(
|
||||||
|
GBinderReaderPriv* p)
|
||||||
|
{
|
||||||
|
const GBinderReaderData* data = p->data;
|
||||||
|
|
||||||
|
return data && data->reg &&
|
||||||
|
p->objects && p->objects[0] &&
|
||||||
|
p->ptr == p->objects[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gbinder_reader_read_fd(
|
||||||
|
GBinderReader* reader) /* Since 1.0.18 */
|
||||||
|
{
|
||||||
|
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||||
|
|
||||||
|
if (gbinder_reader_can_read_object(p)) {
|
||||||
|
int fd;
|
||||||
|
const guint eaten = p->data->reg->io->decode_fd_object(p->ptr,
|
||||||
|
gbinder_reader_bytes_remaining(reader), &fd);
|
||||||
|
|
||||||
|
if (eaten) {
|
||||||
|
GASSERT(fd >= 0);
|
||||||
|
p->ptr += eaten;
|
||||||
|
p->objects++;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gbinder_reader_read_dup_fd(
|
||||||
|
GBinderReader* reader) /* Since 1.0.18 */
|
||||||
|
{
|
||||||
|
const int fd = gbinder_reader_read_fd(reader);
|
||||||
|
|
||||||
|
if (fd >= 0) {
|
||||||
|
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||||
|
|
||||||
|
if (dupfd >= 0) {
|
||||||
|
return dupfd;
|
||||||
|
} else {
|
||||||
|
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_reader_read_nullable_object(
|
gbinder_reader_read_nullable_object(
|
||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
GBinderRemoteObject** out)
|
GBinderRemoteObject** out)
|
||||||
{
|
{
|
||||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||||
const GBinderReaderData* data = p->data;
|
|
||||||
|
|
||||||
if (data && data->reg && p->objects && p->objects[0] &&
|
if (gbinder_reader_can_read_object(p)) {
|
||||||
p->ptr == p->objects[0]) {
|
const GBinderReaderData* data = p->data;
|
||||||
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
|
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
|
||||||
gbinder_reader_bytes_remaining(reader), data->reg, out);
|
gbinder_reader_bytes_remaining(reader), data->reg, out);
|
||||||
|
|
||||||
|
@ -271,10 +325,9 @@ gbinder_reader_read_buffer_impl(
|
||||||
GBinderBuffer** out)
|
GBinderBuffer** out)
|
||||||
{
|
{
|
||||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||||
const GBinderReaderData* data = p->data;
|
|
||||||
|
|
||||||
if (data && data->reg && p->objects && p->objects[0] &&
|
if (gbinder_reader_can_read_object(p)) {
|
||||||
p->ptr == p->objects[0]) {
|
const GBinderReaderData* data = p->data;
|
||||||
GBinderBuffer* buf = data->buffer;
|
GBinderBuffer* buf = data->buffer;
|
||||||
const GBinderIo* io = data->reg->io;
|
const GBinderIo* io = data->reg->io;
|
||||||
const gsize offset = p->ptr - (guint8*)buf->data;
|
const gsize offset = p->ptr - (guint8*)buf->data;
|
||||||
|
|
|
@ -39,7 +39,10 @@
|
||||||
#include <gutil_macros.h>
|
#include <gutil_macros.h>
|
||||||
#include <gutil_strv.h>
|
#include <gutil_strv.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
typedef struct gbinder_writer_priv {
|
typedef struct gbinder_writer_priv {
|
||||||
GBinderWriterData* data;
|
GBinderWriterData* data;
|
||||||
|
@ -74,6 +77,7 @@ gbinder_writer_data_set_contents(
|
||||||
g_byte_array_set_size(data->bytes, 0);
|
g_byte_array_set_size(data->bytes, 0);
|
||||||
gutil_int_array_set_count(data->offsets, 0);
|
gutil_int_array_set_count(data->offsets, 0);
|
||||||
data->buffers_size = 0;
|
data->buffers_size = 0;
|
||||||
|
gbinder_cleanup_reset(data->cleanup);
|
||||||
|
|
||||||
g_byte_array_append(data->bytes, bufdata, bufsize);
|
g_byte_array_append(data->bytes, bufdata, bufsize);
|
||||||
if (contents) {
|
if (contents) {
|
||||||
|
@ -521,6 +525,60 @@ gbinder_writer_data_prepare(
|
||||||
return data->offsets->count;
|
return data->offsets->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_writer_data_close_fd(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
const int fd = GPOINTER_TO_INT(data);
|
||||||
|
|
||||||
|
if (close(fd) < 0) {
|
||||||
|
GWARN("Error closing fd %d: %s", fd, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_writer_data_append_fd(
|
||||||
|
GBinderWriterData* data,
|
||||||
|
int fd)
|
||||||
|
{
|
||||||
|
GByteArray* buf = data->bytes;
|
||||||
|
const guint offset = buf->len;
|
||||||
|
/* Duplicate the descriptor so that caller can do whatever with
|
||||||
|
* the one it passed in. */
|
||||||
|
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||||
|
guint written;
|
||||||
|
|
||||||
|
/* Preallocate enough space */
|
||||||
|
g_byte_array_set_size(buf, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
|
||||||
|
/* Write the original fd if we failed to dup it */
|
||||||
|
if (dupfd < 0) {
|
||||||
|
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
|
||||||
|
written = data->io->encode_fd_object(buf->data + offset, fd);
|
||||||
|
} else {
|
||||||
|
written = data->io->encode_fd_object(buf->data + offset, dupfd);
|
||||||
|
data->cleanup = gbinder_cleanup_add(data->cleanup,
|
||||||
|
gbinder_writer_data_close_fd, GINT_TO_POINTER(dupfd));
|
||||||
|
}
|
||||||
|
/* Fix the data size */
|
||||||
|
g_byte_array_set_size(buf, offset + written);
|
||||||
|
/* Record the offset */
|
||||||
|
gbinder_writer_data_record_offset(data, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_writer_append_fd(
|
||||||
|
GBinderWriter* self,
|
||||||
|
int fd) /* Since 1.0.18 */
|
||||||
|
{
|
||||||
|
GBinderWriterData* data = gbinder_writer_data(self);
|
||||||
|
|
||||||
|
if (G_LIKELY(data)) {
|
||||||
|
gbinder_writer_data_append_fd(data, fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
guint
|
guint
|
||||||
gbinder_writer_append_buffer_object_with_parent(
|
gbinder_writer_append_buffer_object_with_parent(
|
||||||
GBinderWriter* self,
|
GBinderWriter* self,
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
|
|
||||||
#include <glib-unix.h>
|
#include <glib-unix.h>
|
||||||
|
|
||||||
|
#define BINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
|
||||||
|
#define BINDER_DUMP_TRANSACTION BINDER_TRANSACTION('D','M','P')
|
||||||
|
|
||||||
#define RET_OK (0)
|
#define RET_OK (0)
|
||||||
#define RET_NOTFOUND (1)
|
#define RET_NOTFOUND (1)
|
||||||
#define RET_INVARG (2)
|
#define RET_INVARG (2)
|
||||||
|
@ -83,12 +86,15 @@ app_reply(
|
||||||
int* status,
|
int* status,
|
||||||
void* user_data)
|
void* user_data)
|
||||||
{
|
{
|
||||||
|
App* app = user_data;
|
||||||
|
GBinderReader reader;
|
||||||
|
|
||||||
|
gbinder_remote_request_init_reader(req, &reader);
|
||||||
if (code == GBINDER_FIRST_CALL_TRANSACTION) {
|
if (code == GBINDER_FIRST_CALL_TRANSACTION) {
|
||||||
App* app = user_data;
|
|
||||||
const char* iface = gbinder_remote_request_interface(req);
|
const char* iface = gbinder_remote_request_interface(req);
|
||||||
|
|
||||||
if (!g_strcmp0(iface, app->opt->iface)) {
|
if (!g_strcmp0(iface, app->opt->iface)) {
|
||||||
char* str = gbinder_remote_request_read_string16(req);
|
char* str = gbinder_reader_read_string16(&reader);
|
||||||
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
|
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
|
||||||
|
|
||||||
GVERBOSE("\"%s\" %u", iface, code);
|
GVERBOSE("\"%s\" %u", iface, code);
|
||||||
|
@ -100,6 +106,17 @@ app_reply(
|
||||||
} else {
|
} else {
|
||||||
GDEBUG("Unexpected interface \"%s\"", iface);
|
GDEBUG("Unexpected interface \"%s\"", iface);
|
||||||
}
|
}
|
||||||
|
} else if (code == BINDER_DUMP_TRANSACTION) {
|
||||||
|
int fd = gbinder_reader_read_fd(&reader);
|
||||||
|
const char* dump = "Sorry, I've got nothing to dump...\n";
|
||||||
|
const gssize dump_len = strlen(dump);
|
||||||
|
|
||||||
|
GDEBUG("Dump request from %d", gbinder_remote_request_sender_pid(req));
|
||||||
|
if (write(fd, dump, dump_len) != dump_len) {
|
||||||
|
GERR("Failed to write dump: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
*status = 0;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
*status = -1;
|
*status = -1;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
all:
|
all:
|
||||||
%:
|
%:
|
||||||
@$(MAKE) -C unit_buffer $*
|
@$(MAKE) -C unit_buffer $*
|
||||||
|
@$(MAKE) -C unit_cleanup $*
|
||||||
@$(MAKE) -C unit_client $*
|
@$(MAKE) -C unit_client $*
|
||||||
@$(MAKE) -C unit_driver $*
|
@$(MAKE) -C unit_driver $*
|
||||||
@$(MAKE) -C unit_ipc $*
|
@$(MAKE) -C unit_ipc $*
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
TESTS="\
|
TESTS="\
|
||||||
unit_buffer \
|
unit_buffer \
|
||||||
|
unit_cleanup \
|
||||||
unit_client \
|
unit_client \
|
||||||
unit_driver \
|
unit_driver \
|
||||||
unit_ipc \
|
unit_ipc \
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- Mode: makefile-gmake -*-
|
||||||
|
|
||||||
|
EXE = unit_cleanup
|
||||||
|
|
||||||
|
include ../common/Makefile
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Jolla Ltd.
|
||||||
|
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||||
|
*
|
||||||
|
* You may use this file under the terms of BSD license as follows:
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 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 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
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test_binder.h"
|
||||||
|
|
||||||
|
#include "gbinder_cleanup.h"
|
||||||
|
|
||||||
|
static TestOpt test_opt;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_cleanup_inc(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
(*((int*)data))++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* null
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_null(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
g_assert(!gbinder_cleanup_add(NULL, NULL, NULL));
|
||||||
|
gbinder_cleanup_free(NULL);
|
||||||
|
gbinder_cleanup_reset(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* basic
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_basic(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
int n1 = 0, n2 =0;
|
||||||
|
GBinderCleanup* cleanup = gbinder_cleanup_add(NULL, test_cleanup_inc, &n1);
|
||||||
|
|
||||||
|
g_assert(cleanup);
|
||||||
|
g_assert(gbinder_cleanup_add(cleanup, test_cleanup_inc, &n2) == cleanup);
|
||||||
|
gbinder_cleanup_free(cleanup);
|
||||||
|
g_assert(n1 == 1);
|
||||||
|
g_assert(n2 == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* reset
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_reset(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
int n1 = 0, n2 =0;
|
||||||
|
GBinderCleanup* cleanup = gbinder_cleanup_add(NULL, test_cleanup_inc, &n1);
|
||||||
|
|
||||||
|
g_assert(cleanup);
|
||||||
|
g_assert(gbinder_cleanup_add(cleanup, test_cleanup_inc, &n2) == cleanup);
|
||||||
|
gbinder_cleanup_reset(cleanup);
|
||||||
|
g_assert(n1 == 1);
|
||||||
|
g_assert(n2 == 1);
|
||||||
|
|
||||||
|
gbinder_cleanup_free(cleanup);
|
||||||
|
g_assert(n1 == 1);
|
||||||
|
g_assert(n2 == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* Common
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
#define TEST_PREFIX "/cleanup/"
|
||||||
|
#define TEST_(t) TEST_PREFIX t
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
g_test_add_func(TEST_("null"), test_null);
|
||||||
|
g_test_add_func(TEST_("basic"), test_basic);
|
||||||
|
g_test_add_func(TEST_("reset"), test_reset);
|
||||||
|
test_init(&test_opt, argc, argv);
|
||||||
|
return g_test_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* End:
|
||||||
|
*/
|
|
@ -39,6 +39,9 @@
|
||||||
#include "gbinder_remote_object_p.h"
|
#include "gbinder_remote_object_p.h"
|
||||||
#include "gbinder_io.h"
|
#include "gbinder_io.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
static TestOpt test_opt;
|
static TestOpt test_opt;
|
||||||
|
|
||||||
typedef struct binder_buffer_object_64 {
|
typedef struct binder_buffer_object_64 {
|
||||||
|
@ -53,9 +56,12 @@ typedef struct binder_buffer_object_64 {
|
||||||
guint64 parent_offset;
|
guint64 parent_offset;
|
||||||
} BinderObject64;
|
} BinderObject64;
|
||||||
|
|
||||||
#define BINDER_TYPE_HANDLE GBINDER_FOURCC('s','h','*',0x85)
|
#define BINDER_TYPE_(c1,c2,c3) GBINDER_FOURCC(c1,c2,c3,0x85)
|
||||||
#define BINDER_TYPE_PTR GBINDER_FOURCC('p','t','*',0x85)
|
#define BINDER_TYPE_HANDLE BINDER_TYPE_('s','h','*')
|
||||||
|
#define BINDER_TYPE_PTR BINDER_TYPE_('p','t','*')
|
||||||
|
#define BINDER_TYPE_FD BINDER_TYPE_('f', 'd', '*')
|
||||||
#define BINDER_BUFFER_FLAG_HAS_PARENT 0x01
|
#define BINDER_BUFFER_FLAG_HAS_PARENT 0x01
|
||||||
|
#define BINDER_FLAG_ACCEPTS_FDS 0x100
|
||||||
#define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE)
|
#define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE)
|
||||||
G_STATIC_ASSERT(sizeof(BinderObject64) == BUFFER_OBJECT_SIZE_64);
|
G_STATIC_ASSERT(sizeof(BinderObject64) == BUFFER_OBJECT_SIZE_64);
|
||||||
|
|
||||||
|
@ -933,6 +939,256 @@ test_hidl_string_err(
|
||||||
gbinder_ipc_unref(ipc);
|
gbinder_ipc_unref(ipc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* fd_ok
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd_ok(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
/* Using 64-bit I/O */
|
||||||
|
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
|
||||||
|
const guint8 input[] = {
|
||||||
|
TEST_INT32_BYTES(BINDER_TYPE_FD),
|
||||||
|
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
|
||||||
|
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
|
||||||
|
TEST_INT64_BYTES(0)
|
||||||
|
};
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
|
||||||
|
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
|
||||||
|
g_memdup(input, sizeof(input)), sizeof(input), NULL);
|
||||||
|
GBinderReaderData data;
|
||||||
|
GBinderReader reader;
|
||||||
|
|
||||||
|
g_assert(ipc);
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
data.buffer = buf;
|
||||||
|
data.reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
data.objects = g_new(void*, 2);
|
||||||
|
data.objects[0] = buf->data;
|
||||||
|
data.objects[1] = NULL;
|
||||||
|
gbinder_reader_init(&reader, &data, 0, buf->size);
|
||||||
|
|
||||||
|
g_assert(gbinder_reader_read_fd(&reader) == fd);
|
||||||
|
gbinder_driver_close_fds(ipc->driver, data.objects,
|
||||||
|
(guint8*)buf->data + buf->size);
|
||||||
|
/* The above call must have closed the descriptor */
|
||||||
|
g_assert(close(fd) < 0);
|
||||||
|
|
||||||
|
g_free(data.objects);
|
||||||
|
gbinder_buffer_free(buf);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* fd_shortbuf
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd_shortbuf(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
/* Using 64-bit I/O */
|
||||||
|
const guint8 input[] = {
|
||||||
|
TEST_INT32_BYTES(BINDER_TYPE_FD),
|
||||||
|
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS)
|
||||||
|
};
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
|
||||||
|
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
|
||||||
|
g_memdup(input, sizeof(input)), sizeof(input), NULL);
|
||||||
|
GBinderReaderData data;
|
||||||
|
GBinderReader reader;
|
||||||
|
|
||||||
|
g_assert(ipc);
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
data.buffer = buf;
|
||||||
|
data.reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
gbinder_reader_init(&reader, &data, 0, buf->size);
|
||||||
|
|
||||||
|
g_assert(gbinder_reader_read_fd(&reader) < 0);
|
||||||
|
gbinder_buffer_free(buf);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* fd_badtype
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd_badtype(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
/* Using 64-bit I/O */
|
||||||
|
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
|
||||||
|
const guint8 input[] = {
|
||||||
|
TEST_INT32_BYTES(BINDER_TYPE_PTR),
|
||||||
|
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
|
||||||
|
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
|
||||||
|
TEST_INT64_BYTES(0)
|
||||||
|
};
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
|
||||||
|
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
|
||||||
|
g_memdup(input, sizeof(input)), sizeof(input), NULL);
|
||||||
|
GBinderReaderData data;
|
||||||
|
GBinderReader reader;
|
||||||
|
|
||||||
|
g_assert(ipc);
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
data.buffer = buf;
|
||||||
|
data.reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
data.objects = g_new(void*, 2);
|
||||||
|
data.objects[0] = buf->data;
|
||||||
|
data.objects[1] = NULL;
|
||||||
|
gbinder_reader_init(&reader, &data, 0, buf->size);
|
||||||
|
|
||||||
|
g_assert(gbinder_reader_read_fd(&reader) < 0);
|
||||||
|
gbinder_driver_close_fds(ipc->driver, data.objects,
|
||||||
|
(guint8*)buf->data + buf->size);
|
||||||
|
/* The above call doesn't close the descriptor */
|
||||||
|
g_assert(close(fd) == 0);
|
||||||
|
|
||||||
|
g_free(data.objects);
|
||||||
|
gbinder_buffer_free(buf);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* dupfd_ok
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_dupfd_ok(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
/* Using 64-bit I/O */
|
||||||
|
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
|
||||||
|
const guint8 input[] = {
|
||||||
|
TEST_INT32_BYTES(BINDER_TYPE_FD),
|
||||||
|
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
|
||||||
|
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
|
||||||
|
TEST_INT64_BYTES(0)
|
||||||
|
};
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
|
||||||
|
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
|
||||||
|
g_memdup(input, sizeof(input)), sizeof(input), NULL);
|
||||||
|
GBinderReaderData data;
|
||||||
|
GBinderReader reader;
|
||||||
|
int fd2;
|
||||||
|
|
||||||
|
g_assert(ipc);
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
data.buffer = buf;
|
||||||
|
data.reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
data.objects = g_new(void*, 2);
|
||||||
|
data.objects[0] = buf->data;
|
||||||
|
data.objects[1] = NULL;
|
||||||
|
gbinder_reader_init(&reader, &data, 0, buf->size);
|
||||||
|
|
||||||
|
fd2 = gbinder_reader_read_dup_fd(&reader);
|
||||||
|
g_assert(fd2 >= 0);
|
||||||
|
g_assert(fd2 != fd);
|
||||||
|
gbinder_driver_close_fds(ipc->driver, data.objects,
|
||||||
|
(guint8*)buf->data + buf->size);
|
||||||
|
/* The above call closes fd*/
|
||||||
|
g_assert(close(fd) < 0);
|
||||||
|
g_assert(close(fd2) == 0);
|
||||||
|
|
||||||
|
g_free(data.objects);
|
||||||
|
gbinder_buffer_free(buf);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* dupfd_badtype
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_dupfd_badtype(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
/* Using 64-bit I/O */
|
||||||
|
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
|
||||||
|
const guint8 input[] = {
|
||||||
|
TEST_INT32_BYTES(BINDER_TYPE_PTR),
|
||||||
|
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
|
||||||
|
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
|
||||||
|
TEST_INT64_BYTES(0)
|
||||||
|
};
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
|
||||||
|
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
|
||||||
|
g_memdup(input, sizeof(input)), sizeof(input), NULL);
|
||||||
|
GBinderReaderData data;
|
||||||
|
GBinderReader reader;
|
||||||
|
|
||||||
|
g_assert(ipc);
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
data.buffer = buf;
|
||||||
|
data.reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
data.objects = g_new(void*, 2);
|
||||||
|
data.objects[0] = buf->data;
|
||||||
|
data.objects[1] = NULL;
|
||||||
|
gbinder_reader_init(&reader, &data, 0, buf->size);
|
||||||
|
|
||||||
|
g_assert(gbinder_reader_read_dup_fd(&reader) < 0);
|
||||||
|
gbinder_driver_close_fds(ipc->driver, data.objects,
|
||||||
|
(guint8*)buf->data + buf->size);
|
||||||
|
/* The above call doesn't close fd*/
|
||||||
|
g_assert(close(fd) == 0);
|
||||||
|
|
||||||
|
g_free(data.objects);
|
||||||
|
gbinder_buffer_free(buf);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* dupfd_badfd
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_dupfd_badfd(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
/* Using 64-bit I/O */
|
||||||
|
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
|
||||||
|
const guint8 input[] = {
|
||||||
|
TEST_INT32_BYTES(BINDER_TYPE_FD),
|
||||||
|
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
|
||||||
|
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
|
||||||
|
TEST_INT64_BYTES(0)
|
||||||
|
};
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
|
||||||
|
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
|
||||||
|
g_memdup(input, sizeof(input)), sizeof(input), NULL);
|
||||||
|
GBinderReaderData data;
|
||||||
|
GBinderReader reader;
|
||||||
|
|
||||||
|
g_assert(ipc);
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
data.buffer = buf;
|
||||||
|
data.reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
data.objects = g_new(void*, 2);
|
||||||
|
data.objects[0] = buf->data;
|
||||||
|
data.objects[1] = NULL;
|
||||||
|
gbinder_reader_init(&reader, &data, 0, buf->size);
|
||||||
|
|
||||||
|
/* Invalidate the descriptor by closing it */
|
||||||
|
g_assert(close(fd) == 0);
|
||||||
|
g_assert(gbinder_reader_read_dup_fd(&reader) < 0);
|
||||||
|
gbinder_driver_close_fds(ipc->driver, data.objects,
|
||||||
|
(guint8*)buf->data + buf->size);
|
||||||
|
|
||||||
|
g_free(data.objects);
|
||||||
|
gbinder_buffer_free(buf);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* object
|
* object
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
@ -1294,6 +1550,12 @@ int main(int argc, char* argv[])
|
||||||
g_free(path);
|
g_free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_test_add_func(TEST_("fd/ok"), test_fd_ok);
|
||||||
|
g_test_add_func(TEST_("fd/shortbuf"), test_fd_shortbuf);
|
||||||
|
g_test_add_func(TEST_("fd/badtype"), test_fd_badtype);
|
||||||
|
g_test_add_func(TEST_("dupfd/ok"), test_dupfd_ok);
|
||||||
|
g_test_add_func(TEST_("dupfd/badtype"), test_dupfd_badtype);
|
||||||
|
g_test_add_func(TEST_("dupfd/badfd"), test_dupfd_badfd);
|
||||||
g_test_add_func(TEST_("object/valid"), test_object);
|
g_test_add_func(TEST_("object/valid"), test_object);
|
||||||
g_test_add_func(TEST_("object/invalid"), test_object_invalid);
|
g_test_add_func(TEST_("object/invalid"), test_object_invalid);
|
||||||
g_test_add_func(TEST_("object/no_reg"), test_object_no_reg);
|
g_test_add_func(TEST_("object/no_reg"), test_object_no_reg);
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
|
|
||||||
#include <gutil_intarray.h>
|
#include <gutil_intarray.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
static TestOpt test_opt;
|
static TestOpt test_opt;
|
||||||
|
|
||||||
#define BUFFER_OBJECT_SIZE_32 (24)
|
#define BUFFER_OBJECT_SIZE_32 (24)
|
||||||
|
@ -77,6 +79,7 @@ test_null(
|
||||||
gbinder_writer_append_string16_utf16(NULL, NULL, 0);
|
gbinder_writer_append_string16_utf16(NULL, NULL, 0);
|
||||||
gbinder_writer_append_bool(NULL, FALSE);
|
gbinder_writer_append_bool(NULL, FALSE);
|
||||||
gbinder_writer_append_bool(&writer, FALSE);
|
gbinder_writer_append_bool(&writer, FALSE);
|
||||||
|
gbinder_writer_append_fd(NULL, 0);
|
||||||
gbinder_writer_append_bytes(NULL, NULL, 0);
|
gbinder_writer_append_bytes(NULL, NULL, 0);
|
||||||
gbinder_writer_append_bytes(&writer, NULL, 0);
|
gbinder_writer_append_bytes(&writer, NULL, 0);
|
||||||
gbinder_writer_append_hidl_vec(NULL, NULL, 0, 0);
|
gbinder_writer_append_hidl_vec(NULL, NULL, 0, 0);
|
||||||
|
@ -706,6 +709,76 @@ test_parent(
|
||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* fd
|
||||||
|
* fd_invalid
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd2(
|
||||||
|
int fd)
|
||||||
|
{
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GUtilIntArray* offsets;
|
||||||
|
GBinderWriter writer;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
gbinder_writer_append_fd(&writer, fd);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
offsets = gbinder_output_data_offsets(data);
|
||||||
|
g_assert(offsets);
|
||||||
|
g_assert(offsets->count == 1);
|
||||||
|
g_assert(offsets->data[0] == 0);
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
|
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
test_fd2(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd_invalid(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
test_fd2(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* fd_close_error
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd_close_error(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const GBinderIo* io = &gbinder_io_32;
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GBinderWriter writer;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
gbinder_writer_append_fd(&writer, STDOUT_FILENO);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
|
||||||
|
|
||||||
|
/* Fetch duplicated fd and close it. That makes the second close
|
||||||
|
* done by gbinder_writer_data_close_fd() fail. */
|
||||||
|
g_assert(io->decode_fd_object(data->bytes->data, data->bytes->len, &fd));
|
||||||
|
g_assert(close(fd) == 0);
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* local_object
|
* local_object
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
@ -874,6 +947,9 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
g_test_add_func(TEST_("buffer"), test_buffer);
|
g_test_add_func(TEST_("buffer"), test_buffer);
|
||||||
g_test_add_func(TEST_("parent"), test_parent);
|
g_test_add_func(TEST_("parent"), test_parent);
|
||||||
|
g_test_add_func(TEST_("fd"), test_fd);
|
||||||
|
g_test_add_func(TEST_("fd_invalid"), test_fd_invalid);
|
||||||
|
g_test_add_func(TEST_("fd_close_error"), test_fd_close_error);
|
||||||
g_test_add_func(TEST_("local_object"), test_local_object);
|
g_test_add_func(TEST_("local_object"), test_local_object);
|
||||||
g_test_add_func(TEST_("remote_object"), test_remote_object);
|
g_test_add_func(TEST_("remote_object"), test_remote_object);
|
||||||
g_test_add_func(TEST_("byte_array"), test_byte_array);
|
g_test_add_func(TEST_("byte_array"), test_byte_array);
|
||||||
|
|
Loading…
Reference in New Issue