[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,
|
||||
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
|
||||
gbinder_reader_read_nullable_object(
|
||||
GBinderReader* reader,
|
||||
|
|
|
@ -114,6 +114,11 @@ gbinder_writer_append_bytes(
|
|||
const void* data,
|
||||
gsize size);
|
||||
|
||||
void
|
||||
gbinder_writer_append_fd(
|
||||
GBinderWriter* writer,
|
||||
int fd); /* Since 1.0.18 */
|
||||
|
||||
guint
|
||||
gbinder_writer_append_buffer_object_with_parent(
|
||||
GBinderWriter* writer,
|
||||
|
|
|
@ -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
|
||||
|
@ -48,11 +48,33 @@ struct gbinder_cleanup {
|
|||
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
|
||||
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_cleanup_destroy_func(
|
||||
gpointer data)
|
||||
{
|
||||
GBinderCleanupItem* item = data;
|
||||
|
||||
item->destroy(item->pointer);
|
||||
}
|
||||
|
||||
static
|
||||
GBinderCleanup*
|
||||
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
|
||||
|
@ -60,11 +82,6 @@ gbinder_cleanup_free(
|
|||
GBinderCleanup* 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -39,6 +39,10 @@ void
|
|||
gbinder_cleanup_free(
|
||||
GBinderCleanup* cleanup);
|
||||
|
||||
void
|
||||
gbinder_cleanup_reset(
|
||||
GBinderCleanup* cleanup);
|
||||
|
||||
GBinderCleanup*
|
||||
gbinder_cleanup_add(
|
||||
GBinderCleanup* cleanup,
|
||||
|
|
|
@ -153,6 +153,21 @@ GBINDER_IO_FN(encode_remote_object)(
|
|||
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 */
|
||||
static
|
||||
guint
|
||||
|
@ -488,6 +503,7 @@ const GBinderIo GBINDER_IO_PREFIX = {
|
|||
.encode_pointer = GBINDER_IO_FN(encode_pointer),
|
||||
.encode_local_object = GBINDER_IO_FN(encode_local_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_death_notification = GBINDER_IO_FN(encode_death_notification),
|
||||
.encode_transaction = GBINDER_IO_FN(encode_transaction),
|
||||
|
|
|
@ -131,6 +131,7 @@ struct gbinder_io {
|
|||
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
|
||||
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
|
||||
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
|
||||
guint (*encode_fd_object)(void* out, int fd);
|
||||
|
||||
/* Encode binder_buffer_object */
|
||||
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
typedef struct gbinder_reader_priv {
|
||||
const guint8* start;
|
||||
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
|
||||
gbinder_reader_read_nullable_object(
|
||||
GBinderReader* reader,
|
||||
GBinderRemoteObject** out)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderData* data = p->data;
|
||||
|
||||
if (data && data->reg && p->objects && p->objects[0] &&
|
||||
p->ptr == p->objects[0]) {
|
||||
if (gbinder_reader_can_read_object(p)) {
|
||||
const GBinderReaderData* data = p->data;
|
||||
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
|
||||
gbinder_reader_bytes_remaining(reader), data->reg, out);
|
||||
|
||||
|
@ -271,10 +325,9 @@ gbinder_reader_read_buffer_impl(
|
|||
GBinderBuffer** out)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderData* data = p->data;
|
||||
|
||||
if (data && data->reg && p->objects && p->objects[0] &&
|
||||
p->ptr == p->objects[0]) {
|
||||
if (gbinder_reader_can_read_object(p)) {
|
||||
const GBinderReaderData* data = p->data;
|
||||
GBinderBuffer* buf = data->buffer;
|
||||
const GBinderIo* io = data->reg->io;
|
||||
const gsize offset = p->ptr - (guint8*)buf->data;
|
||||
|
|
|
@ -39,7 +39,10 @@
|
|||
#include <gutil_macros.h>
|
||||
#include <gutil_strv.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
typedef struct gbinder_writer_priv {
|
||||
GBinderWriterData* data;
|
||||
|
@ -74,6 +77,7 @@ gbinder_writer_data_set_contents(
|
|||
g_byte_array_set_size(data->bytes, 0);
|
||||
gutil_int_array_set_count(data->offsets, 0);
|
||||
data->buffers_size = 0;
|
||||
gbinder_cleanup_reset(data->cleanup);
|
||||
|
||||
g_byte_array_append(data->bytes, bufdata, bufsize);
|
||||
if (contents) {
|
||||
|
@ -521,6 +525,60 @@ gbinder_writer_data_prepare(
|
|||
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
|
||||
gbinder_writer_append_buffer_object_with_parent(
|
||||
GBinderWriter* self,
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
|
||||
#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_NOTFOUND (1)
|
||||
#define RET_INVARG (2)
|
||||
|
@ -83,12 +86,15 @@ app_reply(
|
|||
int* status,
|
||||
void* user_data)
|
||||
{
|
||||
App* app = user_data;
|
||||
GBinderReader reader;
|
||||
|
||||
gbinder_remote_request_init_reader(req, &reader);
|
||||
if (code == GBINDER_FIRST_CALL_TRANSACTION) {
|
||||
App* app = user_data;
|
||||
const char* iface = gbinder_remote_request_interface(req);
|
||||
|
||||
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);
|
||||
|
||||
GVERBOSE("\"%s\" %u", iface, code);
|
||||
|
@ -100,6 +106,17 @@ app_reply(
|
|||
} else {
|
||||
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;
|
||||
return NULL;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
all:
|
||||
%:
|
||||
@$(MAKE) -C unit_buffer $*
|
||||
@$(MAKE) -C unit_cleanup $*
|
||||
@$(MAKE) -C unit_client $*
|
||||
@$(MAKE) -C unit_driver $*
|
||||
@$(MAKE) -C unit_ipc $*
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
TESTS="\
|
||||
unit_buffer \
|
||||
unit_cleanup \
|
||||
unit_client \
|
||||
unit_driver \
|
||||
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_io.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static TestOpt test_opt;
|
||||
|
||||
typedef struct binder_buffer_object_64 {
|
||||
|
@ -53,9 +56,12 @@ typedef struct binder_buffer_object_64 {
|
|||
guint64 parent_offset;
|
||||
} BinderObject64;
|
||||
|
||||
#define BINDER_TYPE_HANDLE GBINDER_FOURCC('s','h','*',0x85)
|
||||
#define BINDER_TYPE_PTR GBINDER_FOURCC('p','t','*',0x85)
|
||||
#define BINDER_TYPE_(c1,c2,c3) GBINDER_FOURCC(c1,c2,c3,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_FLAG_ACCEPTS_FDS 0x100
|
||||
#define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE)
|
||||
G_STATIC_ASSERT(sizeof(BinderObject64) == BUFFER_OBJECT_SIZE_64);
|
||||
|
||||
|
@ -933,6 +939,256 @@ test_hidl_string_err(
|
|||
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
|
||||
*==========================================================================*/
|
||||
|
@ -1294,6 +1550,12 @@ int main(int argc, char* argv[])
|
|||
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/invalid"), test_object_invalid);
|
||||
g_test_add_func(TEST_("object/no_reg"), test_object_no_reg);
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
#include <gutil_intarray.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
static TestOpt test_opt;
|
||||
|
||||
#define BUFFER_OBJECT_SIZE_32 (24)
|
||||
|
@ -77,6 +79,7 @@ test_null(
|
|||
gbinder_writer_append_string16_utf16(NULL, NULL, 0);
|
||||
gbinder_writer_append_bool(NULL, FALSE);
|
||||
gbinder_writer_append_bool(&writer, FALSE);
|
||||
gbinder_writer_append_fd(NULL, 0);
|
||||
gbinder_writer_append_bytes(NULL, NULL, 0);
|
||||
gbinder_writer_append_bytes(&writer, NULL, 0);
|
||||
gbinder_writer_append_hidl_vec(NULL, NULL, 0, 0);
|
||||
|
@ -706,6 +709,76 @@ test_parent(
|
|||
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
|
||||
*==========================================================================*/
|
||||
|
@ -874,6 +947,9 @@ int main(int argc, char* argv[])
|
|||
|
||||
g_test_add_func(TEST_("buffer"), test_buffer);
|
||||
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_("remote_object"), test_remote_object);
|
||||
g_test_add_func(TEST_("byte_array"), test_byte_array);
|
||||
|
|
Loading…
Reference in New Issue