[gbinder] Support for passing object references via proxy. JB#52557

GBinderProxyObject automatically creates proxies for the remote objects
found in the transaction payload.
This commit is contained in:
Slava Monich 2021-02-17 13:35:55 +02:00
parent 0c85299efc
commit 82f71a6c91
50 changed files with 2146 additions and 519 deletions

View File

@ -30,9 +30,9 @@ This package contains the development library for %{name}.
%build %build
make LIBDIR=%{_libdir} KEEP_SYMBOLS=1 release pkgconfig make LIBDIR=%{_libdir} KEEP_SYMBOLS=1 release pkgconfig
make -C test/binder-bridge release make -C test/binder-bridge KEEP_SYMBOLS=1 release
make -C test/binder-list release make -C test/binder-list KEEP_SYMBOLS=1 release
make -C test/binder-ping release make -C test/binder-ping KEEP_SYMBOLS=1 release
%install %install
rm -rf %{buildroot} rm -rf %{buildroot}

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -14,8 +14,8 @@
* 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 names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software 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
@ -112,6 +112,47 @@ gbinder_buffer_contents_unref(
} }
} }
/*==========================================================================*
* GBinderBufferContentsList
* It's actually a GSList containing GBinderBufferContents refs.
*==========================================================================*/
GBinderBufferContentsList*
gbinder_buffer_contents_list_add(
GBinderBufferContentsList* list,
GBinderBufferContents* contents)
{
/* Prepend rather than append for better efficiency */
return contents ? (GBinderBufferContentsList*) g_slist_prepend((GSList*)
list, gbinder_buffer_contents_ref(contents)) : list;
}
GBinderBufferContentsList*
gbinder_buffer_contents_list_dup(
GBinderBufferContentsList* list)
{
GSList* out = NULL;
if (list) {
GSList* l = (GSList*) list;
/* The order gets reversed but it doesn't matter */
while (l) {
out = g_slist_prepend(out, gbinder_buffer_contents_ref(l->data));
l = l->next;
}
}
return (GBinderBufferContentsList*) out;
}
void
gbinder_buffer_contents_list_free(
GBinderBufferContentsList* list)
{
g_slist_free_full((GSList*) list, (GDestroyNotify)
gbinder_buffer_contents_unref);
}
/*==========================================================================* /*==========================================================================*
* GBinderBuffer * GBinderBuffer
*==========================================================================*/ *==========================================================================*/

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -88,6 +88,22 @@ gbinder_buffer_contents_unref(
GBinderBufferContents* contents) GBinderBufferContents* contents)
GBINDER_INTERNAL; GBINDER_INTERNAL;
GBinderBufferContentsList*
gbinder_buffer_contents_list_add(
GBinderBufferContentsList* list,
GBinderBufferContents* contents)
GBINDER_INTERNAL;
GBinderBufferContentsList*
gbinder_buffer_contents_list_dup(
GBinderBufferContentsList* list)
GBINDER_INTERNAL;
void
gbinder_buffer_contents_list_free(
GBinderBufferContentsList* list)
GBINDER_INTERNAL;
#endif /* GBINDER_BUFFER_PRIVATE_H */ #endif /* GBINDER_BUFFER_PRIVATE_H */
/* /*

View File

@ -100,6 +100,7 @@ typedef struct gbinder_driver_context {
GBinderObjectRegistry* reg; GBinderObjectRegistry* reg;
GBinderHandler* handler; GBinderHandler* handler;
GBinderCleanup* unrefs; GBinderCleanup* unrefs;
GBinderBufferContentsList* bufs;
} GBinderDriverContext; } GBinderDriverContext;
static static
@ -341,19 +342,19 @@ gbinder_driver_cmd_data(
static static
gboolean gboolean
gbinder_driver_death_notification( gbinder_driver_handle_cookie(
GBinderDriver* self, GBinderDriver* self,
guint32 cmd, guint32 cmd,
GBinderRemoteObject* obj) GBinderRemoteObject* obj)
{ {
GBinderIoBuf write; GBinderIoBuf write;
guint8 buf[4 + GBINDER_MAX_DEATH_NOTIFICATION_SIZE]; guint8 buf[4 + GBINDER_MAX_HANDLE_COOKIE_SIZE];
guint32* data = (guint32*)buf; guint32* data = (guint32*)buf;
data[0] = cmd; data[0] = cmd;
memset(&write, 0, sizeof(write)); memset(&write, 0, sizeof(write));
write.ptr = (uintptr_t)buf; write.ptr = (uintptr_t)buf;
write.size = 4 + self->io->encode_death_notification(data + 1, obj); write.size = 4 + self->io->encode_handle_cookie(data + 1, obj);
return gbinder_driver_write(self, &write) >= 0; return gbinder_driver_write(self, &write) >= 0;
} }
@ -384,6 +385,7 @@ gbinder_driver_context_init(
context->reg = reg; context->reg = reg;
context->handler = handler; context->handler = handler;
context->unrefs = NULL; context->unrefs = NULL;
context->bufs = NULL;
} }
static static
@ -392,6 +394,7 @@ gbinder_driver_context_cleanup(
GBinderDriverContext* context) GBinderDriverContext* context)
{ {
gbinder_cleanup_free(context->unrefs); gbinder_cleanup_free(context->unrefs);
gbinder_buffer_contents_list_free(context->bufs);
} }
static static
@ -513,9 +516,13 @@ gbinder_driver_handle_transaction(
/* Transfer data ownership to the request */ /* Transfer data ownership to the request */
if (tx.data && tx.size) { if (tx.data && tx.size) {
GBinderBuffer* buf = gbinder_buffer_new(self,
tx.data, tx.size, tx.objects);
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size); gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
gbinder_remote_request_set_data(req, tx.code, gbinder_remote_request_set_data(req, tx.code, buf);
gbinder_buffer_new(self, tx.data, tx.size, tx.objects)); context->bufs = gbinder_buffer_contents_list_add(context->bufs,
gbinder_buffer_contents(buf));
} else { } else {
GASSERT(!tx.objects); GASSERT(!tx.objects);
gbinder_driver_free_buffer(self, tx.data); gbinder_driver_free_buffer(self, tx.data);
@ -548,6 +555,8 @@ gbinder_driver_handle_transaction(
/* No reply for one-way transactions */ /* No reply for one-way transactions */
if (!(tx.flags & GBINDER_TX_FLAG_ONEWAY)) { if (!(tx.flags & GBINDER_TX_FLAG_ONEWAY)) {
if (reply) { if (reply) {
context->bufs = gbinder_buffer_contents_list_add(context->bufs,
gbinder_local_reply_contents(reply));
gbinder_driver_reply_data(self, gbinder_local_reply_data(reply)); gbinder_driver_reply_data(self, gbinder_local_reply_data(reply));
} else { } else {
gbinder_driver_reply_status(self, txstatus); gbinder_driver_reply_status(self, txstatus);
@ -614,7 +623,7 @@ gbinder_driver_handle_command(
} else if (cmd == io->br.increfs) { } else if (cmd == io->br.increfs) {
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE]; guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
GBinderLocalObject* obj = gbinder_object_registry_get_local GBinderLocalObject* obj = gbinder_object_registry_get_local
(reg, io->decode_binder_ptr_cookie(data)); (reg, io->decode_ptr_cookie(data));
GVERBOSE("> BR_INCREFS %p", obj); GVERBOSE("> BR_INCREFS %p", obj);
gbinder_local_object_handle_increfs(obj); gbinder_local_object_handle_increfs(obj);
@ -623,7 +632,7 @@ gbinder_driver_handle_command(
gbinder_driver_cmd_data(self, io->bc.increfs_done, data, buf); gbinder_driver_cmd_data(self, io->bc.increfs_done, data, buf);
} else if (cmd == io->br.decrefs) { } else if (cmd == io->br.decrefs) {
GBinderLocalObject* obj = gbinder_object_registry_get_local GBinderLocalObject* obj = gbinder_object_registry_get_local
(reg, io->decode_binder_ptr_cookie(data)); (reg, io->decode_ptr_cookie(data));
GVERBOSE("> BR_DECREFS %p", obj); GVERBOSE("> BR_DECREFS %p", obj);
if (obj) { if (obj) {
@ -637,16 +646,21 @@ gbinder_driver_handle_command(
} else if (cmd == io->br.acquire) { } else if (cmd == io->br.acquire) {
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE]; guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
GBinderLocalObject* obj = gbinder_object_registry_get_local GBinderLocalObject* obj = gbinder_object_registry_get_local
(reg, io->decode_binder_ptr_cookie(data)); (reg, io->decode_ptr_cookie(data));
GVERBOSE("> BR_ACQUIRE %p", obj); GVERBOSE("> BR_ACQUIRE %p", obj);
gbinder_local_object_handle_acquire(obj); if (obj) {
gbinder_local_object_unref(obj); /* BC_ACQUIRE_DONE will be sent after the request is handled */
GVERBOSE("< BC_ACQUIRE_DONE %p", obj); gbinder_local_object_handle_acquire(obj, context->bufs);
gbinder_driver_cmd_data(self, io->bc.acquire_done, data, buf); gbinder_local_object_unref(obj);
} else {
/* This shouldn't normally happen. Just send the same data back. */
GVERBOSE("< BC_ACQUIRE_DONE");
gbinder_driver_cmd_data(self, io->bc.acquire_done, data, buf);
}
} else if (cmd == io->br.release) { } else if (cmd == io->br.release) {
GBinderLocalObject* obj = gbinder_object_registry_get_local GBinderLocalObject* obj = gbinder_object_registry_get_local
(reg, io->decode_binder_ptr_cookie(data)); (reg, io->decode_ptr_cookie(data));
GVERBOSE("> BR_RELEASE %p", obj); GVERBOSE("> BR_RELEASE %p", obj);
if (obj) { if (obj) {
@ -660,19 +674,24 @@ gbinder_driver_handle_command(
} else if (cmd == io->br.transaction) { } else if (cmd == io->br.transaction) {
gbinder_driver_handle_transaction(self, context, data); gbinder_driver_handle_transaction(self, context, data);
} else if (cmd == io->br.dead_binder) { } else if (cmd == io->br.dead_binder) {
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE]; guint8 buf[4 + GBINDER_MAX_COOKIE_SIZE];
guint64 handle = 0; guint64 handle = 0;
GBinderRemoteObject* obj; GBinderRemoteObject* obj;
io->decode_cookie(data, &handle); io->decode_cookie(data, &handle);
GVERBOSE("> BR_DEAD_BINDER %llu", (long long unsigned int)handle); GVERBOSE("> BR_DEAD_BINDER %llu", (long long unsigned int)handle);
obj = gbinder_object_registry_get_remote(reg, (guint32)handle); obj = gbinder_object_registry_get_remote(reg, (guint32)handle,
REMOTE_REGISTRY_DONT_CREATE);
if (obj) { if (obj) {
/* BC_DEAD_BINDER_DONE will be sent after the request is handled */
gbinder_remote_object_handle_death_notification(obj); gbinder_remote_object_handle_death_notification(obj);
gbinder_remote_object_unref(obj); gbinder_remote_object_unref(obj);
} else {
/* This shouldn't normally happen. Just send the same data back. */
GVERBOSE("< BC_DEAD_BINDER_DONE %llu", (long long unsigned int)
handle);
gbinder_driver_cmd_data(self, io->bc.dead_binder_done, data, buf);
} }
GVERBOSE("< BC_DEAD_BINDER_DONE %llu", (long long unsigned int)handle);
gbinder_driver_cmd_data(self, io->bc.dead_binder_done, data, buf);
} else if (cmd == io->br.clear_death_notification_done) { } else if (cmd == io->br.clear_death_notification_done) {
GVERBOSE("> BR_CLEAR_DEATH_NOTIFICATION_DONE"); GVERBOSE("> BR_CLEAR_DEATH_NOTIFICATION_DONE");
} else { } else {
@ -765,19 +784,38 @@ gbinder_driver_txstatus(
io->decode_transaction_data(data, &tx); io->decode_transaction_data(data, &tx);
gbinder_driver_verbose_transaction_data("BR_REPLY", &tx); gbinder_driver_verbose_transaction_data("BR_REPLY", &tx);
/* Transfer data ownership to the request */ /* Transfer data ownership to the reply */
if (tx.data && tx.size) { if (tx.data && tx.size) {
GBinderBuffer* buf = gbinder_buffer_new(self,
tx.data, tx.size, tx.objects);
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size); gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
gbinder_remote_reply_set_data(reply, gbinder_remote_reply_set_data(reply, buf);
gbinder_buffer_new(self, tx.data, tx.size, tx.objects)); context->bufs = gbinder_buffer_contents_list_add(context->bufs,
gbinder_buffer_contents(buf));
} else { } else {
GASSERT(!tx.objects); GASSERT(!tx.objects);
gbinder_driver_free_buffer(self, tx.data); gbinder_driver_free_buffer(self, tx.data);
} }
txstatus = tx.status; /*
GASSERT(txstatus != (-EAGAIN)); * Filter out special cases. It's a bit unfortunate that
if (txstatus == (-EAGAIN)) txstatus = (-EFAULT); * libgbinder API historically mixed TF_STATUS_CODE payload
* with special delivery errors. It's not a bit deal though,
* because in real life TF_STATUS_CODE transactions are not
* being used that often, if at all.
*/
switch (tx.status) {
case (-EAGAIN):
case GBINDER_STATUS_FAILED:
case GBINDER_STATUS_DEAD_OBJECT:
txstatus = (-EFAULT);
GWARN("Replacing tx status %d with %d", tx.status, txstatus);
break;
default:
txstatus = tx.status;
break;
}
} else { } else {
gbinder_driver_handle_command(self, context, cmd, data); gbinder_driver_handle_command(self, context, cmd, data);
} }
@ -952,6 +990,48 @@ gbinder_driver_protocol(
return self->protocol; return self->protocol;
} }
gboolean
gbinder_driver_acquire_done(
GBinderDriver* self,
GBinderLocalObject* obj)
{
GBinderIoBuf write;
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
guint32* data = (guint32*)buf;
const GBinderIo* io = self->io;
data[0] = io->bc.acquire_done;
memset(&write, 0, sizeof(write));
write.ptr = (uintptr_t)buf;
write.size = 4 + io->encode_ptr_cookie(data + 1, obj);
GVERBOSE("< BC_ACQUIRE_DONE %p", obj);
return gbinder_driver_write(self, &write) >= 0;
}
gboolean
gbinder_driver_dead_binder_done(
GBinderDriver* self,
GBinderRemoteObject* obj)
{
if (G_LIKELY(obj)) {
GBinderIoBuf write;
guint8 buf[4 + GBINDER_MAX_COOKIE_SIZE];
guint32* data = (guint32*)buf;
const GBinderIo* io = self->io;
data[0] = io->bc.dead_binder_done;
memset(&write, 0, sizeof(write));
write.ptr = (uintptr_t)buf;
write.size = 4 + io->encode_cookie(data + 1, obj->handle);
GVERBOSE("< BC_DEAD_BINDER_DONE %u", obj->handle);
return gbinder_driver_write(self, &write) >= 0;
} else {
return FALSE;
}
}
gboolean gboolean
gbinder_driver_request_death_notification( gbinder_driver_request_death_notification(
GBinderDriver* self, GBinderDriver* self,
@ -959,7 +1039,7 @@ gbinder_driver_request_death_notification(
{ {
if (G_LIKELY(obj)) { if (G_LIKELY(obj)) {
GVERBOSE("< BC_REQUEST_DEATH_NOTIFICATION 0x%08x", obj->handle); GVERBOSE("< BC_REQUEST_DEATH_NOTIFICATION 0x%08x", obj->handle);
return gbinder_driver_death_notification(self, return gbinder_driver_handle_cookie(self,
self->io->bc.request_death_notification, obj); self->io->bc.request_death_notification, obj);
} else { } else {
return FALSE; return FALSE;
@ -973,7 +1053,7 @@ gbinder_driver_clear_death_notification(
{ {
if (G_LIKELY(obj)) { if (G_LIKELY(obj)) {
GVERBOSE("< BC_CLEAR_DEATH_NOTIFICATION 0x%08x", obj->handle); GVERBOSE("< BC_CLEAR_DEATH_NOTIFICATION 0x%08x", obj->handle);
return gbinder_driver_death_notification(self, return gbinder_driver_handle_cookie(self,
self->io->bc.clear_death_notification, obj); self->io->bc.clear_death_notification, obj);
} else { } else {
return FALSE; return FALSE;
@ -1201,38 +1281,23 @@ gbinder_driver_transact(
return txstatus; return txstatus;
} }
int
gbinder_driver_ping(
GBinderDriver* self,
GBinderObjectRegistry* reg,
guint32 handle)
{
const GBinderRpcProtocol* protocol = self->protocol;
GBinderLocalRequest* req = gbinder_local_request_new(self->io, NULL);
GBinderRemoteReply* reply = gbinder_remote_reply_new(reg);
GBinderWriter writer;
int ret;
gbinder_local_request_init_writer(req, &writer);
protocol->write_ping(&writer);
ret = gbinder_driver_transact(self, reg, NULL, handle, protocol->ping_tx,
req, reply);
gbinder_local_request_unref(req);
gbinder_remote_reply_unref(reply);
return ret;
}
GBinderLocalRequest* GBinderLocalRequest*
gbinder_driver_local_request_new( gbinder_driver_local_request_new(
GBinderDriver* self, GBinderDriver* self,
const char* iface) const char* iface)
{
return gbinder_local_request_new_iface(self->io, self->protocol, iface);
}
GBinderLocalRequest*
gbinder_driver_local_request_new_ping(
GBinderDriver* self)
{ {
GBinderLocalRequest* req = gbinder_local_request_new(self->io, NULL); GBinderLocalRequest* req = gbinder_local_request_new(self->io, NULL);
GBinderWriter writer; GBinderWriter writer;
gbinder_local_request_init_writer(req, &writer); gbinder_local_request_init_writer(req, &writer);
self->protocol->write_rpc_header(&writer, iface); self->protocol->write_ping(&writer);
return req; return req;
} }

View File

@ -84,6 +84,18 @@ gbinder_driver_protocol(
GBinderDriver* driver) GBinderDriver* driver)
GBINDER_INTERNAL; GBINDER_INTERNAL;
gboolean
gbinder_driver_acquire_done(
GBinderDriver* driver,
GBinderLocalObject* obj)
GBINDER_INTERNAL;
gboolean
gbinder_driver_dead_binder_done(
GBinderDriver* driver,
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
gboolean gboolean
gbinder_driver_request_death_notification( gbinder_driver_request_death_notification(
GBinderDriver* driver, GBinderDriver* driver,
@ -161,19 +173,17 @@ gbinder_driver_transact(
GBinderRemoteReply* reply) GBinderRemoteReply* reply)
GBINDER_INTERNAL; GBINDER_INTERNAL;
int
gbinder_driver_ping(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
guint32 handle)
GBINDER_INTERNAL;
GBinderLocalRequest* GBinderLocalRequest*
gbinder_driver_local_request_new( gbinder_driver_local_request_new(
GBinderDriver* driver, GBinderDriver* driver,
const char* iface) const char* iface)
GBINDER_INTERNAL; GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_driver_local_request_new_ping(
GBinderDriver* self)
GBINDER_INTERNAL;
#endif /* GBINDER_DRIVER_H */ #endif /* GBINDER_DRIVER_H */
/* /*

View File

@ -90,19 +90,49 @@ GBINDER_IO_FN(write_read)(
return ret; return ret;
} }
/* Returns size of the object */
static
gsize
GBINDER_IO_FN(object_size)(
const void* obj)
{
if (obj) {
const struct binder_object_header* hdr = obj;
switch (hdr->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER:
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE:
return sizeof(struct flat_binder_object);
case BINDER_TYPE_FD:
return sizeof(struct binder_fd_object);
case BINDER_TYPE_FDA:
return sizeof(struct binder_fd_array_object);
case BINDER_TYPE_PTR:
return sizeof(struct binder_buffer_object);
}
}
return 0;
}
/* Returns size of the object's extra data */ /* Returns size of the object's extra data */
static static
gsize gsize
GBINDER_IO_FN(object_data_size)( GBINDER_IO_FN(object_data_size)(
const void* obj) const void* obj)
{ {
const struct binder_buffer_object* buf = obj; if (obj) {
const struct binder_object_header* hdr = obj;
if (buf && buf->hdr.type == BINDER_TYPE_PTR) { switch (hdr->type) {
return buf->length; case BINDER_TYPE_PTR:
} else { return ((struct binder_buffer_object*)obj)->length;
return 0; case BINDER_TYPE_FDA:
return ((struct binder_fd_array_object*)obj)->num_fds * 4;
}
} }
return 0;
} }
/* Writes pointer to the buffer */ /* Writes pointer to the buffer */
@ -118,6 +148,19 @@ GBINDER_IO_FN(encode_pointer)(
return sizeof(*dest); return sizeof(*dest);
} }
/* Writes cookie to the buffer */
static
guint
GBINDER_IO_FN(encode_cookie)(
void* out,
guint64 cookie)
{
binder_uintptr_t* dest = out;
*dest = (uintptr_t)cookie;
return sizeof(*dest);
}
/* Encodes flat_binder_object */ /* Encodes flat_binder_object */
static static
guint guint
@ -197,7 +240,7 @@ GBINDER_IO_FN(encode_buffer_object)(
static static
guint guint
GBINDER_IO_FN(encode_death_notification)( GBINDER_IO_FN(encode_handle_cookie)(
void* out, void* out,
GBinderRemoteObject* obj) GBinderRemoteObject* obj)
{ {
@ -209,6 +252,20 @@ GBINDER_IO_FN(encode_death_notification)(
return sizeof(*dest); return sizeof(*dest);
} }
static
guint
GBINDER_IO_FN(encode_ptr_cookie)(
void* out,
GBinderLocalObject* obj)
{
struct binder_ptr_cookie* dest = out;
/* We never send these cookies and don't expect them back */
dest->ptr = (uintptr_t)obj;
dest->cookie = 0;
return sizeof(dest);
}
/* Fills binder_transaction_data for BC_TRANSACTION/REPLY */ /* Fills binder_transaction_data for BC_TRANSACTION/REPLY */
static static
void void
@ -412,7 +469,7 @@ GBINDER_IO_FN(decode_cookie)(
/* Decode struct binder_ptr_cookie */ /* Decode struct binder_ptr_cookie */
static static
void* void*
GBINDER_IO_FN(decode_binder_ptr_cookie)( GBINDER_IO_FN(decode_ptr_cookie)(
const void* data) const void* data)
{ {
const struct binder_ptr_cookie* ptr = data; const struct binder_ptr_cookie* ptr = data;
@ -422,6 +479,24 @@ GBINDER_IO_FN(decode_binder_ptr_cookie)(
return (void*)(uintptr_t)ptr->ptr; return (void*)(uintptr_t)ptr->ptr;
} }
static
guint
GBINDER_IO_FN(decode_binder_handle)(
const void* data,
guint32* handle)
{
const struct flat_binder_object* obj = data;
/* Caller guarantees that data points to an object */
if (obj->hdr.type == BINDER_TYPE_HANDLE) {
if (handle) {
*handle = obj->handle;
}
return sizeof(*obj);
}
return 0;
}
static static
guint guint
GBINDER_IO_FN(decode_binder_object)( GBINDER_IO_FN(decode_binder_object)(
@ -436,7 +511,8 @@ GBINDER_IO_FN(decode_binder_object)(
switch (obj->hdr.type) { switch (obj->hdr.type) {
case BINDER_TYPE_HANDLE: case BINDER_TYPE_HANDLE:
if (out) { if (out) {
*out = gbinder_object_registry_get_remote(reg, obj->handle); *out = gbinder_object_registry_get_remote(reg, obj->handle,
REMOTE_REGISTRY_CAN_CREATE_AND_ACQUIRE);
} }
return sizeof(*obj); return sizeof(*obj);
case BINDER_TYPE_BINDER: case BINDER_TYPE_BINDER:
@ -552,15 +628,18 @@ const GBinderIo GBINDER_IO_PREFIX = {
.failed_reply = BR_FAILED_REPLY .failed_reply = BR_FAILED_REPLY
}, },
.object_size = GBINDER_IO_FN(object_size),
.object_data_size = GBINDER_IO_FN(object_data_size), .object_data_size = GBINDER_IO_FN(object_data_size),
/* Encoders */ /* Encoders */
.encode_pointer = GBINDER_IO_FN(encode_pointer), .encode_pointer = GBINDER_IO_FN(encode_pointer),
.encode_cookie = GBINDER_IO_FN(encode_cookie),
.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_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_handle_cookie = GBINDER_IO_FN(encode_handle_cookie),
.encode_ptr_cookie = GBINDER_IO_FN(encode_ptr_cookie),
.encode_transaction = GBINDER_IO_FN(encode_transaction), .encode_transaction = GBINDER_IO_FN(encode_transaction),
.encode_transaction_sg = GBINDER_IO_FN(encode_transaction_sg), .encode_transaction_sg = GBINDER_IO_FN(encode_transaction_sg),
.encode_reply = GBINDER_IO_FN(encode_reply), .encode_reply = GBINDER_IO_FN(encode_reply),
@ -570,7 +649,8 @@ const GBinderIo GBINDER_IO_PREFIX = {
/* Decoders */ /* Decoders */
.decode_transaction_data = GBINDER_IO_FN(decode_transaction_data), .decode_transaction_data = GBINDER_IO_FN(decode_transaction_data),
.decode_cookie = GBINDER_IO_FN(decode_cookie), .decode_cookie = GBINDER_IO_FN(decode_cookie),
.decode_binder_ptr_cookie = GBINDER_IO_FN(decode_binder_ptr_cookie), .decode_ptr_cookie = GBINDER_IO_FN(decode_ptr_cookie),
.decode_binder_handle = GBINDER_IO_FN(decode_binder_handle),
.decode_binder_object = GBINDER_IO_FN(decode_binder_object), .decode_binder_object = GBINDER_IO_FN(decode_binder_object),
.decode_buffer_object = GBINDER_IO_FN(decode_buffer_object), .decode_buffer_object = GBINDER_IO_FN(decode_buffer_object),
.decode_fd_object = GBINDER_IO_FN(decode_fd_object), .decode_fd_object = GBINDER_IO_FN(decode_fd_object),
@ -586,7 +666,7 @@ G_STATIC_ASSERT(sizeof(struct flat_binder_object) <=
G_STATIC_ASSERT(sizeof(struct binder_buffer_object) <= G_STATIC_ASSERT(sizeof(struct binder_buffer_object) <=
GBINDER_MAX_BUFFER_OBJECT_SIZE); GBINDER_MAX_BUFFER_OBJECT_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_handle_cookie) <= G_STATIC_ASSERT(sizeof(struct binder_handle_cookie) <=
GBINDER_MAX_DEATH_NOTIFICATION_SIZE); GBINDER_MAX_HANDLE_COOKIE_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_transaction_data) <= G_STATIC_ASSERT(sizeof(struct binder_transaction_data) <=
GBINDER_MAX_BC_TRANSACTION_SIZE); GBINDER_MAX_BC_TRANSACTION_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_transaction_data_sg) <= G_STATIC_ASSERT(sizeof(struct binder_transaction_data_sg) <=

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2019 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -125,7 +125,8 @@ struct gbinder_io {
guint failed_reply; guint failed_reply;
} br; } br;
/* Size of the object's extra data */ /* Size of the object and its extra data */
gsize (*object_size)(const void* obj);
gsize (*object_data_size)(const void* obj); gsize (*object_data_size)(const void* obj);
/* Writes pointer to the buffer. The destination buffer must have /* Writes pointer to the buffer. The destination buffer must have
@ -134,6 +135,12 @@ struct gbinder_io {
#define GBINDER_MAX_POINTER_SIZE (8) #define GBINDER_MAX_POINTER_SIZE (8)
guint (*encode_pointer)(void* out, const void* pointer); guint (*encode_pointer)(void* out, const void* pointer);
/* Writes cookie to the buffer. The destination buffer must have
* at least GBINDER_IO_MAX_COOKIE_SIZE bytes available. The
* actual size is returned. */
#define GBINDER_MAX_COOKIE_SIZE GBINDER_MAX_POINTER_SIZE
guint (*encode_cookie)(void* out, guint64 cookie);
/* Encode flat_buffer_object */ /* Encode flat_buffer_object */
#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);
@ -145,9 +152,13 @@ struct gbinder_io {
guint (*encode_buffer_object)(void* out, const void* data, gsize size, guint (*encode_buffer_object)(void* out, const void* data, gsize size,
const GBinderParent* parent); const GBinderParent* parent);
/* Encode death notification */ /* Encode binder_handle_cookie */
#define GBINDER_MAX_DEATH_NOTIFICATION_SIZE (12) #define GBINDER_MAX_HANDLE_COOKIE_SIZE (12)
guint (*encode_death_notification)(void* out, GBinderRemoteObject* obj); guint (*encode_handle_cookie)(void* out, GBinderRemoteObject* obj);
/* Encode binder_ptr_cookie */
#define GBINDER_MAX_PTR_COOKIE_SIZE (16)
guint (*encode_ptr_cookie)(void* out, GBinderLocalObject* obj);
/* Encode BC_TRANSACTION/BC_TRANSACTION_SG data */ /* Encode BC_TRANSACTION/BC_TRANSACTION_SG data */
#define GBINDER_MAX_BC_TRANSACTION_SIZE (64) #define GBINDER_MAX_BC_TRANSACTION_SIZE (64)
@ -174,10 +185,9 @@ struct gbinder_io {
/* Decoders */ /* Decoders */
void (*decode_transaction_data)(const void* data, GBinderIoTxData* tx); void (*decode_transaction_data)(const void* data, GBinderIoTxData* tx);
void* (*decode_ptr_cookie)(const void* data);
#define GBINDER_MAX_PTR_COOKIE_SIZE (16)
void* (*decode_binder_ptr_cookie)(const void* data);
guint (*decode_cookie)(const void* data, guint64* cookie); guint (*decode_cookie)(const void* data, guint64* cookie);
guint (*decode_binder_handle)(const void* obj, guint32* handle);
guint (*decode_binder_object)(const void* data, gsize size, guint (*decode_binder_object)(const void* data, gsize size,
GBinderObjectRegistry* reg, GBinderRemoteObject** obj); GBinderObjectRegistry* reg, GBinderRemoteObject** obj);
guint (*decode_buffer_object)(GBinderBuffer* buf, gsize offset, guint (*decode_buffer_object)(GBinderBuffer* buf, gsize offset,

View File

@ -64,6 +64,7 @@ struct gbinder_ipc_priv {
GThreadPool* tx_pool; GThreadPool* tx_pool;
GHashTable* tx_table; GHashTable* tx_table;
char* key; char* key;
const char* name;
GBinderObjectRegistry object_registry; GBinderObjectRegistry object_registry;
GMutex remote_objects_mutex; GMutex remote_objects_mutex;
@ -207,7 +208,7 @@ typedef struct gbinder_ipc_tx_custom {
} GBinderIpcTxCustom; } GBinderIpcTxCustom;
GBINDER_INLINE_FUNC const char* gbinder_ipc_name(GBinderIpc* self) GBINDER_INLINE_FUNC const char* gbinder_ipc_name(GBinderIpc* self)
{ return gbinder_driver_dev(self->driver); } { return self->priv->name; }
static static
GBinderIpcLooper* GBinderIpcLooper*
@ -685,7 +686,7 @@ gbinder_ipc_looper_transact(
/* Lock */ /* Lock */
g_mutex_lock(&priv->looper_mutex); g_mutex_lock(&priv->looper_mutex);
if (gbinder_ipc_looper_remove_primary(looper)) { if (gbinder_ipc_looper_remove_primary(looper)) {
GDEBUG("Primary looper %s is blocked", looper->name); GVERBOSE("Primary looper %s is blocked", looper->name);
looper->next = priv->blocked_loopers; looper->next = priv->blocked_loopers;
priv->blocked_loopers = looper; priv->blocked_loopers = looper;
was_blocked = TRUE; was_blocked = TRUE;
@ -712,7 +713,7 @@ gbinder_ipc_looper_transact(
/* Block until asynchronous transaction gets completed. */ /* Block until asynchronous transaction gets completed. */
done = 0; done = 0;
if (gbinder_ipc_wait(looper->pipefd[0], tx->pipefd[0], &done)) { if (gbinder_ipc_wait(looper->pipefd[0], tx->pipefd[0], &done)) {
GDEBUG("Looper %s is released", looper->name); GVERBOSE("Looper %s is released", looper->name);
GASSERT(done == TX_DONE); GASSERT(done == TX_DONE);
} }
} }
@ -1115,16 +1116,24 @@ gbinder_ipc_tx_handler_transact(
static static
void void
gbinder_ipc_invalidate_remote_handle_locked( gbinder_ipc_invalidate_remote_handle_locked(
GBinderIpcPriv* priv, GBinderIpc* self,
guint32 handle) guint32 handle)
{ {
GBinderIpcPriv* priv = self->priv;
/* Caller holds priv->remote_objects_mutex */ /* Caller holds priv->remote_objects_mutex */
if (priv->remote_objects) { if (priv->remote_objects) {
GVERBOSE_("handle %u", handle); const gpointer key = GINT_TO_POINTER(handle);
g_hash_table_remove(priv->remote_objects, GINT_TO_POINTER(handle)); #if GUTIL_LOG_VERBOSE
if (g_hash_table_size(priv->remote_objects) == 0) { const gpointer obj = g_hash_table_lookup(priv->remote_objects, key);
g_hash_table_unref(priv->remote_objects); #endif
priv->remote_objects = NULL;
if (g_hash_table_remove(priv->remote_objects, key)) {
GVERBOSE_("handle %u %p %s", handle, obj, gbinder_ipc_name(self));
if (g_hash_table_size(priv->remote_objects) == 0) {
g_hash_table_unref(priv->remote_objects);
priv->remote_objects = NULL;
}
} }
} }
} }
@ -1138,7 +1147,7 @@ gbinder_ipc_invalidate_remote_handle(
/* Lock */ /* Lock */
g_mutex_lock(&priv->remote_objects_mutex); g_mutex_lock(&priv->remote_objects_mutex);
gbinder_ipc_invalidate_remote_handle_locked(priv, handle); gbinder_ipc_invalidate_remote_handle_locked(self, handle);
g_mutex_unlock(&priv->remote_objects_mutex); g_mutex_unlock(&priv->remote_objects_mutex);
/* Unlock */ /* Unlock */
} }
@ -1173,10 +1182,12 @@ gbinder_ipc_local_object_disposed(
/* Lock */ /* Lock */
g_mutex_lock(&priv->local_objects_mutex); g_mutex_lock(&priv->local_objects_mutex);
if (obj->object.ref_count == 1 && priv->local_objects) { if (obj->object.ref_count == 1 && priv->local_objects) {
g_hash_table_remove(priv->local_objects, obj); if (g_hash_table_remove(priv->local_objects, obj)) {
if (g_hash_table_size(priv->local_objects) == 0) { GVERBOSE_("%p %s", obj, gbinder_ipc_name(self));
g_hash_table_unref(priv->local_objects); if (g_hash_table_size(priv->local_objects) == 0) {
priv->local_objects = NULL; g_hash_table_unref(priv->local_objects);
priv->local_objects = NULL;
}
} }
} }
g_mutex_unlock(&priv->local_objects_mutex); g_mutex_unlock(&priv->local_objects_mutex);
@ -1193,7 +1204,7 @@ gbinder_ipc_remote_object_disposed(
/* Lock */ /* Lock */
g_mutex_lock(&priv->remote_objects_mutex); g_mutex_lock(&priv->remote_objects_mutex);
if (obj->object.ref_count == 1) { if (obj->object.ref_count == 1) {
gbinder_ipc_invalidate_remote_handle_locked(priv, obj->handle); gbinder_ipc_invalidate_remote_handle_locked(self, obj->handle);
} }
g_mutex_unlock(&priv->remote_objects_mutex); g_mutex_unlock(&priv->remote_objects_mutex);
/* Unlock */ /* Unlock */
@ -1211,11 +1222,13 @@ gbinder_ipc_register_local_object(
if (!priv->local_objects) { if (!priv->local_objects) {
priv->local_objects = g_hash_table_new(g_direct_hash, g_direct_equal); priv->local_objects = g_hash_table_new(g_direct_hash, g_direct_equal);
} }
g_hash_table_insert(priv->local_objects, obj, obj); if (!g_hash_table_contains(priv->local_objects, obj)) {
g_hash_table_insert(priv->local_objects, obj, obj);
GVERBOSE_("%p %s", obj, gbinder_ipc_name(self));
}
g_mutex_unlock(&priv->local_objects_mutex); g_mutex_unlock(&priv->local_objects_mutex);
/* Unlock */ /* Unlock */
GVERBOSE_("%p", obj);
gbinder_ipc_looper_check(self); gbinder_ipc_looper_check(self);
} }
@ -1252,6 +1265,7 @@ GBinderRemoteObject*
gbinder_ipc_priv_get_remote_object( gbinder_ipc_priv_get_remote_object(
GBinderIpcPriv* priv, GBinderIpcPriv* priv,
guint32 handle, guint32 handle,
REMOTE_REGISTRY_CREATE create,
gboolean maybe_dead) gboolean maybe_dead)
{ {
GBinderRemoteObject* obj = NULL; GBinderRemoteObject* obj = NULL;
@ -1264,16 +1278,22 @@ gbinder_ipc_priv_get_remote_object(
} }
if (obj) { if (obj) {
gbinder_remote_object_ref(obj); gbinder_remote_object_ref(obj);
} else { } else if (create != REMOTE_REGISTRY_DONT_CREATE) {
GBinderIpc* self = priv->self;
/* /*
* If maybe_dead is TRUE, the caller is supposed to try reanimating * If maybe_dead is TRUE, the caller is supposed to try reanimating
* the object on the main thread not holding any global locks. * the object on the main thread not holding any global locks.
*/ */
obj = gbinder_remote_object_new(priv->self, handle, maybe_dead); obj = gbinder_remote_object_new(self, handle, maybe_dead ?
REMOTE_OBJECT_CREATE_DEAD : (create == REMOTE_REGISTRY_CAN_CREATE) ?
REMOTE_OBJECT_CREATE_ALIVE :
REMOTE_OBJECT_CREATE_ACQUIRED);
if (!priv->remote_objects) { if (!priv->remote_objects) {
priv->remote_objects = g_hash_table_new priv->remote_objects = g_hash_table_new
(g_direct_hash, g_direct_equal); (g_direct_hash, g_direct_equal);
} }
GVERBOSE_("%p handle %u %s", obj, handle, gbinder_ipc_name(self));
g_hash_table_replace(priv->remote_objects, key, obj); g_hash_table_replace(priv->remote_objects, key, obj);
} }
g_mutex_unlock(&priv->remote_objects_mutex); g_mutex_unlock(&priv->remote_objects_mutex);
@ -1282,14 +1302,47 @@ gbinder_ipc_priv_get_remote_object(
return obj; return obj;
} }
GBinderRemoteObject* GBinderLocalObject*
gbinder_ipc_get_remote_object( gbinder_ipc_find_local_object(
GBinderIpc* self, GBinderIpc* self,
guint32 handle, GBinderIpcLocalObjectCheckFunc func,
gboolean maybe_dead) void* user_data)
{
GBinderLocalObject* found = NULL;
if (self) {
GBinderIpcPriv* priv = self->priv;
/* Lock */
g_mutex_lock(&priv->local_objects_mutex);
if (priv->local_objects) {
GHashTableIter it;
gpointer value;
g_hash_table_iter_init(&it, priv->local_objects);
while (g_hash_table_iter_next(&it, NULL, &value)) {
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(value);
if (func(obj, user_data)) {
found = gbinder_local_object_ref(obj);
break;
}
}
}
g_mutex_unlock(&priv->local_objects_mutex);
/* Unlock */
}
return found;
}
GBinderRemoteObject*
gbinder_ipc_get_service_manager(
GBinderIpc* self)
{ {
/* GBinderServiceManager makes sure that GBinderIpc pointer is not NULL */ /* GBinderServiceManager makes sure that GBinderIpc pointer is not NULL */
return gbinder_ipc_priv_get_remote_object(self->priv, handle, maybe_dead); return gbinder_ipc_priv_get_remote_object(self->priv,
GBINDER_SERVICEMANAGER_HANDLE, REMOTE_REGISTRY_CAN_CREATE, TRUE);
} }
GBINDER_INLINE_FUNC GBINDER_INLINE_FUNC
@ -1338,10 +1391,11 @@ static
GBinderRemoteObject* GBinderRemoteObject*
gbinder_ipc_object_registry_get_remote( gbinder_ipc_object_registry_get_remote(
GBinderObjectRegistry* reg, GBinderObjectRegistry* reg,
guint32 handle) guint32 handle,
REMOTE_REGISTRY_CREATE create)
{ {
return gbinder_ipc_priv_get_remote_object return gbinder_ipc_priv_get_remote_object
(gbinder_ipc_priv_from_object_registry(reg), handle, FALSE); (gbinder_ipc_priv_from_object_registry(reg), handle, create, FALSE);
} }
/*==========================================================================* /*==========================================================================*
@ -1769,6 +1823,9 @@ gbinder_ipc_new(
gbinder_ipc_table = g_hash_table_new(g_str_hash, g_str_equal); gbinder_ipc_table = g_hash_table_new(g_str_hash, g_str_equal);
} }
g_hash_table_replace(gbinder_ipc_table, priv->key, self); g_hash_table_replace(gbinder_ipc_table, priv->key, self);
/* With "/dev/" prefix, it may be too long to be a thread name */
priv->name = priv->key +
(g_str_has_prefix(priv->key, "/dev/") ? 5 : 0);
} }
} }
pthread_mutex_unlock(&gbinder_ipc_mutex); pthread_mutex_unlock(&gbinder_ipc_mutex);
@ -1801,10 +1858,39 @@ GBinderObjectRegistry*
gbinder_ipc_object_registry( gbinder_ipc_object_registry(
GBinderIpc* self) GBinderIpc* self)
{ {
/* Only used by unit tests */
return G_LIKELY(self) ? &self->priv->object_registry : NULL; return G_LIKELY(self) ? &self->priv->object_registry : NULL;
} }
const GBinderIo*
gbinder_ipc_io(
GBinderIpc* self)
{
return G_LIKELY(self) ? gbinder_driver_io(self->driver) : NULL;
}
const GBinderRpcProtocol*
gbinder_ipc_protocol(
GBinderIpc* self)
{
return G_LIKELY(self) ? gbinder_driver_protocol(self->driver) : NULL;
}
int
gbinder_ipc_ping_sync(
GBinderIpc* ipc,
guint32 handle,
const GBinderIpcSyncApi* api)
{
GBinderDriver* driver = ipc->driver;
GBinderLocalRequest* req = gbinder_driver_local_request_new_ping(driver);
guint32 code = gbinder_driver_protocol(driver)->ping_tx;
int ret;
gbinder_remote_reply_unref(api->sync_reply(ipc, handle, code, req, &ret));
gbinder_local_request_unref(req);
return ret;
}
gulong gulong
gbinder_ipc_transact( gbinder_ipc_transact(
GBinderIpc* self, GBinderIpc* self,
@ -1951,7 +2037,11 @@ gbinder_ipc_dispose(
GVERBOSE_("%s", self->dev); GVERBOSE_("%s", self->dev);
/* Lock */ /* Lock */
pthread_mutex_lock(&gbinder_ipc_mutex); pthread_mutex_lock(&gbinder_ipc_mutex);
GASSERT(gbinder_ipc_table); /*
* gbinder_ipc_dispose() can be invoked more than once (typically
* at shutdown) and gbinder_ipc_table here may actually happen to
* be NULL, hence the check.
*/
if (gbinder_ipc_table) { if (gbinder_ipc_table) {
GBinderIpcPriv* priv = self->priv; GBinderIpcPriv* priv = self->priv;

View File

@ -59,6 +59,12 @@ struct gbinder_ipc_tx {
void* user_data; void* user_data;
}; };
typedef
gboolean
(*GBinderIpcLocalObjectCheckFunc)(
GBinderLocalObject* obj,
void* user_data);
typedef typedef
void void
(*GBinderIpcReplyFunc)( (*GBinderIpcReplyFunc)(
@ -109,7 +115,7 @@ gbinder_ipc_unref(
void void
gbinder_ipc_looper_check( gbinder_ipc_looper_check(
GBinderIpc* ipc) GBinderIpc* ipc)
GBINDER_INTERNAL; GBINDER_INTERNAL;
GBinderObjectRegistry* GBinderObjectRegistry*
@ -117,6 +123,24 @@ gbinder_ipc_object_registry(
GBinderIpc* ipc) GBinderIpc* ipc)
GBINDER_INTERNAL; GBINDER_INTERNAL;
const GBinderIo*
gbinder_ipc_io(
GBinderIpc* ipc)
GBINDER_INTERNAL;
const GBinderRpcProtocol*
gbinder_ipc_protocol(
GBinderIpc* ipc)
GBINDER_INTERNAL;
GBinderLocalObject*
gbinder_ipc_find_local_object(
GBinderIpc* ipc,
GBinderIpcLocalObjectCheckFunc func,
void* user_data)
GBINDER_INTERNAL
G_GNUC_WARN_UNUSED_RESULT;
void void
gbinder_ipc_register_local_object( gbinder_ipc_register_local_object(
GBinderIpc* ipc, GBinderIpc* ipc,
@ -124,11 +148,10 @@ gbinder_ipc_register_local_object(
GBINDER_INTERNAL; GBINDER_INTERNAL;
GBinderRemoteObject* GBinderRemoteObject*
gbinder_ipc_get_remote_object( gbinder_ipc_get_service_manager(
GBinderIpc* ipc, GBinderIpc* self)
guint32 handle, GBINDER_INTERNAL
gboolean maybe_dead) G_GNUC_WARN_UNUSED_RESULT;
GBINDER_INTERNAL;
void void
gbinder_ipc_invalidate_remote_handle( gbinder_ipc_invalidate_remote_handle(
@ -136,6 +159,13 @@ gbinder_ipc_invalidate_remote_handle(
guint32 handle) guint32 handle)
GBINDER_INTERNAL; GBINDER_INTERNAL;
int
gbinder_ipc_ping_sync(
GBinderIpc* ipc,
guint32 handle,
const GBinderIpcSyncApi* api)
GBINDER_INTERNAL;
gulong gulong
gbinder_ipc_transact( gbinder_ipc_transact(
GBinderIpc* ipc, GBinderIpc* ipc,

View File

@ -34,6 +34,7 @@
#include "gbinder_driver.h" #include "gbinder_driver.h"
#include "gbinder_ipc.h" #include "gbinder_ipc.h"
#include "gbinder_buffer_p.h"
#include "gbinder_local_object_p.h" #include "gbinder_local_object_p.h"
#include "gbinder_local_reply_p.h" #include "gbinder_local_reply_p.h"
#include "gbinder_remote_request.h" #include "gbinder_remote_request.h"
@ -41,6 +42,7 @@
#include "gbinder_log.h" #include "gbinder_log.h"
#include <gutil_strv.h> #include <gutil_strv.h>
#include <gutil_macros.h>
#include <errno.h> #include <errno.h>
@ -51,6 +53,11 @@ struct gbinder_local_object_priv {
void* user_data; void* user_data;
}; };
typedef struct gbinder_local_object_acquire_data {
GBinderLocalObject* object;
GBinderBufferContentsList* bufs;
} GBinderLocalObjectAcquireData;
G_DEFINE_TYPE(GBinderLocalObject, gbinder_local_object, G_TYPE_OBJECT) G_DEFINE_TYPE(GBinderLocalObject, gbinder_local_object, G_TYPE_OBJECT)
#define PARENT_CLASS gbinder_local_object_parent_class #define PARENT_CLASS gbinder_local_object_parent_class
@ -285,10 +292,10 @@ gbinder_local_object_handle_later(
static static
gboolean gboolean
gbinder_local_object_handle_increfs_proc( gbinder_local_object_increfs_proc(
gpointer local) gpointer user_data)
{ {
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local); GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(user_data);
self->weak_refs++; self->weak_refs++;
g_signal_emit(self, gbinder_local_object_signals g_signal_emit(self, gbinder_local_object_signals
@ -298,10 +305,10 @@ gbinder_local_object_handle_increfs_proc(
static static
gboolean gboolean
gbinder_local_object_handle_decrefs_proc( gbinder_local_object_decrefs_proc(
gpointer local) gpointer user_data)
{ {
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local); GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(user_data);
GASSERT(self->weak_refs > 0); GASSERT(self->weak_refs > 0);
self->weak_refs--; self->weak_refs--;
@ -311,30 +318,66 @@ gbinder_local_object_handle_decrefs_proc(
} }
static static
gboolean void
gbinder_local_object_handle_acquire_proc( gbinder_local_object_default_acquire(
gpointer local) GBinderLocalObject* self)
{ {
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
self->strong_refs++; self->strong_refs++;
gbinder_local_object_ref(self);
GVERBOSE_("%p => %d", self, self->strong_refs);
g_signal_emit(self, gbinder_local_object_signals g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_STRONG_REFS_CHANGED], 0); [SIGNAL_STRONG_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
} }
static static
gboolean gboolean
gbinder_local_object_handle_release_proc( gbinder_local_object_acquire_proc(
gpointer local) gpointer user_data)
{ {
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local); GBinderLocalObjectAcquireData* data = user_data;
GBinderLocalObject* self = data->object;
GASSERT(self->strong_refs > 0); GBINDER_LOCAL_OBJECT_GET_CLASS(self)->acquire(self);
self->strong_refs--; return G_SOURCE_REMOVE;
g_signal_emit(self, gbinder_local_object_signals }
[SIGNAL_STRONG_REFS_CHANGED], 0);
static
void
gbinder_local_object_acquire_done(
gpointer user_data)
{
GBinderLocalObjectAcquireData* data = user_data;
GBinderLocalObject* self = data->object;
gbinder_driver_acquire_done(self->ipc->driver, self);
gbinder_local_object_unref(self); gbinder_local_object_unref(self);
gbinder_buffer_contents_list_free(data->bufs);
return gutil_slice_free(data);
}
static
void
gbinder_local_object_default_release(
GBinderLocalObject* self)
{
GASSERT(self->strong_refs > 0);
if (self->strong_refs > 0) {
self->strong_refs--;
GVERBOSE_("%p => %d", self, self->strong_refs);
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_STRONG_REFS_CHANGED], 0);
gbinder_local_object_unref(self);
}
}
static
gboolean
gbinder_local_object_release_proc(
gpointer obj)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(obj);
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->release(self);
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
@ -527,33 +570,51 @@ void
gbinder_local_object_handle_increfs( gbinder_local_object_handle_increfs(
GBinderLocalObject* self) GBinderLocalObject* self)
{ {
gbinder_local_object_handle_later(self, gbinder_local_object_handle_later(self, gbinder_local_object_increfs_proc);
gbinder_local_object_handle_increfs_proc);
} }
void void
gbinder_local_object_handle_decrefs( gbinder_local_object_handle_decrefs(
GBinderLocalObject* self) GBinderLocalObject* self)
{ {
gbinder_local_object_handle_later(self, gbinder_local_object_handle_later(self, gbinder_local_object_decrefs_proc);
gbinder_local_object_handle_decrefs_proc);
} }
void void
gbinder_local_object_handle_acquire( gbinder_local_object_handle_acquire(
GBinderLocalObject* self) GBinderLocalObject* self,
GBinderBufferContentsList* bufs)
{ {
gbinder_local_object_ref(self); if (G_LIKELY(self)) {
gbinder_local_object_handle_later(self, GBinderLocalObjectPriv* priv = self->priv;
gbinder_local_object_handle_acquire_proc); GBinderLocalObjectAcquireData* data =
g_slice_new(GBinderLocalObjectAcquireData);
/*
* This is a bit complicated :)
* GBinderProxyObject derived from GBinderLocalObject acquires a
* reference to the remote object in addition to performing the
* default GBinderLocalObject action later on the main thread.
* We must ensure that remote object doesn't go away before we
* acquire our reference to it. One of the references to that
* remote object (possibly the last one) may be associated with
* the transaction buffer contained in GBinderBufferContentsList.
* We don't know exactly which one we need, so we keep all those
* buffers alive until we are done with BR_ACQUIRE.
*/
data->object = gbinder_local_object_ref(self);
data->bufs = gbinder_buffer_contents_list_dup(bufs);
g_main_context_invoke_full(priv->context, G_PRIORITY_DEFAULT,
gbinder_local_object_acquire_proc, data,
gbinder_local_object_acquire_done);
}
} }
void void
gbinder_local_object_handle_release( gbinder_local_object_handle_release(
GBinderLocalObject* self) GBinderLocalObject* self)
{ {
gbinder_local_object_handle_later(self, gbinder_local_object_handle_later(self, gbinder_local_object_release_proc);
gbinder_local_object_handle_release_proc);
} }
/*==========================================================================* /*==========================================================================*
@ -614,6 +675,8 @@ gbinder_local_object_class_init(
gbinder_local_object_default_handle_looper_transaction; gbinder_local_object_default_handle_looper_transaction;
klass->can_handle_transaction = klass->can_handle_transaction =
gbinder_local_object_default_can_handle_transaction; gbinder_local_object_default_can_handle_transaction;
klass->acquire = gbinder_local_object_default_acquire;
klass->release = gbinder_local_object_default_release;
klass->drop = gbinder_local_object_default_drop; klass->drop = gbinder_local_object_default_drop;
gbinder_local_object_signals[SIGNAL_WEAK_REFS_CHANGED] = gbinder_local_object_signals[SIGNAL_WEAK_REFS_CHANGED] =

View File

@ -77,6 +77,8 @@ typedef struct gbinder_local_object_class {
GBinderLocalReply* (*handle_looper_transaction) GBinderLocalReply* (*handle_looper_transaction)
(GBinderLocalObject* self, GBinderRemoteRequest* req, guint code, (GBinderLocalObject* self, GBinderRemoteRequest* req, guint code,
guint flags, int* status); guint flags, int* status);
void (*acquire)(GBinderLocalObject* self);
void (*release)(GBinderLocalObject* self);
void (*drop)(GBinderLocalObject* self); void (*drop)(GBinderLocalObject* self);
/* Need to add some placeholders if this class becomes public */ /* Need to add some placeholders if this class becomes public */
} GBinderLocalObjectClass; } GBinderLocalObjectClass;
@ -166,7 +168,8 @@ gbinder_local_object_handle_decrefs(
void void
gbinder_local_object_handle_acquire( gbinder_local_object_handle_acquire(
GBinderLocalObject* obj) GBinderLocalObject* obj,
GBinderBufferContentsList* bufs)
GBINDER_INTERNAL; GBINDER_INTERNAL;
void void

View File

@ -43,6 +43,7 @@ struct gbinder_local_reply {
gint refcount; gint refcount;
GBinderWriterData data; GBinderWriterData data;
GBinderOutputData out; GBinderOutputData out;
GBinderBufferContents* contents;
}; };
GBINDER_INLINE_FUNC GBINDER_INLINE_FUNC
@ -96,10 +97,14 @@ gbinder_local_reply_new(
GBinderLocalReply* GBinderLocalReply*
gbinder_local_reply_set_contents( gbinder_local_reply_set_contents(
GBinderLocalReply* self, GBinderLocalReply* self,
GBinderBuffer* buffer) GBinderBuffer* buffer,
GBinderObjectConverter* convert)
{ {
if (self) { if (self) {
gbinder_writer_data_set_contents(&self->data, buffer); gbinder_writer_data_set_contents(&self->data, buffer, convert);
gbinder_buffer_contents_unref(self->contents);
self->contents = gbinder_buffer_contents_ref
(gbinder_buffer_contents(buffer));
} }
return self; return self;
} }
@ -114,7 +119,8 @@ gbinder_local_reply_free(
gutil_int_array_free(data->offsets, TRUE); gutil_int_array_free(data->offsets, TRUE);
g_byte_array_free(data->bytes, TRUE); g_byte_array_free(data->bytes, TRUE);
gbinder_cleanup_free(data->cleanup); gbinder_cleanup_free(data->cleanup);
g_slice_free(GBinderLocalReply, self); gbinder_buffer_contents_unref(self->contents);
gutil_slice_free(self);
} }
GBinderLocalReply* GBinderLocalReply*
@ -147,6 +153,13 @@ gbinder_local_reply_data(
return G_LIKELY(self) ? &self->out : NULL; return G_LIKELY(self) ? &self->out : NULL;
} }
GBinderBufferContents*
gbinder_local_reply_contents(
GBinderLocalReply* self)
{
return G_LIKELY(self) ? self->contents : NULL;
}
void void
gbinder_local_reply_cleanup( gbinder_local_reply_cleanup(
GBinderLocalReply* self, GBinderLocalReply* self,

View File

@ -47,10 +47,16 @@ gbinder_local_reply_data(
GBinderLocalReply* reply) GBinderLocalReply* reply)
GBINDER_INTERNAL; GBINDER_INTERNAL;
GBinderBufferContents*
gbinder_local_reply_contents(
GBinderLocalReply* reply)
GBINDER_INTERNAL;
GBinderLocalReply* GBinderLocalReply*
gbinder_local_reply_set_contents( gbinder_local_reply_set_contents(
GBinderLocalReply* reply, GBinderLocalReply* reply,
GBinderBuffer* buffer) GBinderBuffer* buffer,
GBinderObjectConverter* convert)
GBINDER_INTERNAL; GBINDER_INTERNAL;
#endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */ #endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */

View File

@ -31,6 +31,7 @@
*/ */
#include "gbinder_local_request_p.h" #include "gbinder_local_request_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_output_data.h" #include "gbinder_output_data.h"
#include "gbinder_writer_p.h" #include "gbinder_writer_p.h"
#include "gbinder_buffer_p.h" #include "gbinder_buffer_p.h"
@ -91,6 +92,7 @@ gbinder_local_request_new(
if (init) { if (init) {
gsize size; gsize size;
gconstpointer data = g_bytes_get_data(init, &size); gconstpointer data = g_bytes_get_data(init, &size);
writer->bytes = g_byte_array_sized_new(size); writer->bytes = g_byte_array_sized_new(size);
g_byte_array_append(writer->bytes, data, size); g_byte_array_append(writer->bytes, data, size);
} else { } else {
@ -103,15 +105,33 @@ gbinder_local_request_new(
return NULL; return NULL;
} }
GBinderLocalRequest*
gbinder_local_request_new_iface(
const GBinderIo* io,
const GBinderRpcProtocol* protocol,
const char* iface)
{
GBinderLocalRequest* self = gbinder_local_request_new(io, NULL);
if (self && G_LIKELY(protocol) && G_LIKELY(iface)) {
GBinderWriter writer;
gbinder_local_request_init_writer(self, &writer);
protocol->write_rpc_header(&writer, iface);
}
return self;
}
GBinderLocalRequest* GBinderLocalRequest*
gbinder_local_request_new_from_data( gbinder_local_request_new_from_data(
GBinderBuffer* buffer) GBinderBuffer* buffer,
GBinderObjectConverter* convert)
{ {
GBinderLocalRequest* self = gbinder_local_request_new GBinderLocalRequest* self = gbinder_local_request_new
(gbinder_buffer_io(buffer), NULL); (gbinder_buffer_io(buffer), NULL);
if (self) { if (self) {
gbinder_writer_data_append_contents(&self->data, buffer, 0); gbinder_writer_data_append_contents(&self->data, buffer, 0, convert);
} }
return self; return self;
} }
@ -120,10 +140,11 @@ void
gbinder_local_request_append_contents( gbinder_local_request_append_contents(
GBinderLocalRequest* self, GBinderLocalRequest* self,
GBinderBuffer* buffer, GBinderBuffer* buffer,
gsize offset) gsize off,
GBinderObjectConverter* convert)
{ {
if (self) { if (self) {
gbinder_writer_data_append_contents(&self->data, buffer, offset); gbinder_writer_data_append_contents(&self->data, buffer, off, convert);
} }
} }

View File

@ -43,21 +43,30 @@ gbinder_local_request_new(
GBytes* init) GBytes* init)
GBINDER_INTERNAL; GBINDER_INTERNAL;
GBinderOutputData* GBinderLocalRequest*
gbinder_local_request_data( gbinder_local_request_new_iface(
GBinderLocalRequest* req) const GBinderIo* io,
const GBinderRpcProtocol* protocol,
const char* iface)
GBINDER_INTERNAL; GBINDER_INTERNAL;
GBinderLocalRequest* GBinderLocalRequest*
gbinder_local_request_new_from_data( gbinder_local_request_new_from_data(
GBinderBuffer* buffer) GBinderBuffer* buffer,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
GBinderOutputData*
gbinder_local_request_data(
GBinderLocalRequest* req)
GBINDER_INTERNAL; GBINDER_INTERNAL;
void void
gbinder_local_request_append_contents( gbinder_local_request_append_contents(
GBinderLocalRequest* req, GBinderLocalRequest* req,
GBinderBuffer* buffer, GBinderBuffer* buffer,
gsize offset) gsize offset,
GBinderObjectConverter* convert)
GBINDER_INTERNAL; GBINDER_INTERNAL;
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */ #endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 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.
*/
#ifndef GBINDER_OBJECT_CONVERTER_H
#define GBINDER_OBJECT_CONVERTER_H
#include "gbinder_types_p.h"
typedef struct gbinder_object_converter_functions {
GBinderLocalObject* (*handle_to_local)(GBinderObjectConverter*, guint32);
} GBinderObjectConverterFunctions;
struct gbinder_object_converter {
const GBinderObjectConverterFunctions* f;
const GBinderIo* io;
const GBinderRpcProtocol* protocol;
};
/* Inline wrappers */
GBINDER_INLINE_FUNC
GBinderLocalObject*
gbinder_object_converter_handle_to_local(
GBinderObjectConverter* convert,
guint32 handle)
{
return convert ? convert->f->handle_to_local(convert, handle) : NULL;
}
#endif /* GBINDER_OBJECT_CONVERTER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -35,13 +35,19 @@
#include "gbinder_types_p.h" #include "gbinder_types_p.h"
typedef enum gbinder_remote_registry_create {
REMOTE_REGISTRY_DONT_CREATE,
REMOTE_REGISTRY_CAN_CREATE,
REMOTE_REGISTRY_CAN_CREATE_AND_ACQUIRE
} REMOTE_REGISTRY_CREATE;
typedef struct gbinder_object_registry_functions { typedef struct gbinder_object_registry_functions {
void (*ref)(GBinderObjectRegistry* reg); void (*ref)(GBinderObjectRegistry* reg);
void (*unref)(GBinderObjectRegistry* reg); void (*unref)(GBinderObjectRegistry* reg);
GBinderLocalObject* (*get_local)(GBinderObjectRegistry* reg, GBinderLocalObject* (*get_local)(GBinderObjectRegistry* reg,
void* pointer); void* pointer);
GBinderRemoteObject* (*get_remote)(GBinderObjectRegistry* reg, GBinderRemoteObject* (*get_remote)(GBinderObjectRegistry* reg,
guint32 handle); guint32 handle, REMOTE_REGISTRY_CREATE create);
} GBinderObjectRegistryFunctions; } GBinderObjectRegistryFunctions;
struct gbinder_object_registry { struct gbinder_object_registry {
@ -81,9 +87,10 @@ GBINDER_INLINE_FUNC
GBinderRemoteObject* GBinderRemoteObject*
gbinder_object_registry_get_remote( gbinder_object_registry_get_remote(
GBinderObjectRegistry* reg, GBinderObjectRegistry* reg,
guint32 handle) guint32 handle,
REMOTE_REGISTRY_CREATE create)
{ {
return reg ? reg->f->get_remote(reg, handle) : NULL; return reg ? reg->f->get_remote(reg, handle, create) : NULL;
} }
#endif /* GBINDER_OBJECT_REGISTRY_H */ #endif /* GBINDER_OBJECT_REGISTRY_H */

View File

@ -38,8 +38,12 @@
#include "gbinder_local_reply.h" #include "gbinder_local_reply.h"
#include "gbinder_remote_object_p.h" #include "gbinder_remote_object_p.h"
#include "gbinder_remote_request_p.h" #include "gbinder_remote_request_p.h"
#include "gbinder_remote_reply.h" #include "gbinder_remote_reply_p.h"
#include "gbinder_object_converter.h"
#include "gbinder_object_registry.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h" #include "gbinder_ipc.h"
#include "gbinder_log.h"
#include <gutil_macros.h> #include <gutil_macros.h>
@ -56,16 +60,195 @@ struct gbinder_proxy_tx {
}; };
struct gbinder_proxy_object_priv { struct gbinder_proxy_object_priv {
gulong remote_death_id;
gboolean dropped; gboolean dropped;
GBinderProxyTx* tx; GBinderProxyTx* tx;
GMutex mutex; /* Protects the hashtable below */
GHashTable* subproxies;
}; };
GType gbinder_proxy_object_get_type(void) GBINDER_INTERNAL;
G_DEFINE_TYPE(GBinderProxyObject, gbinder_proxy_object, \ G_DEFINE_TYPE(GBinderProxyObject, gbinder_proxy_object, \
GBINDER_TYPE_LOCAL_OBJECT) GBINDER_TYPE_LOCAL_OBJECT)
#define GBINDER_IS_PROXY_OBJECT(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, \
GBINDER_TYPE_PROXY_OBJECT)
#define THIS(obj) GBINDER_PROXY_OBJECT(obj)
#define THIS_TYPE GBINDER_TYPE_PROXY_OBJECT
#define PARENT_CLASS gbinder_proxy_object_parent_class #define PARENT_CLASS gbinder_proxy_object_parent_class
static
void
gbinder_proxy_object_subproxy_gone(
gpointer proxy,
GObject* subproxy)
{
GBinderProxyObject* self = THIS(proxy);
GBinderProxyObjectPriv* priv = self->priv;
/* Lock */
g_mutex_lock(&priv->mutex);
g_hash_table_remove(priv->subproxies, subproxy);
if (g_hash_table_size(priv->subproxies) == 0) {
g_hash_table_unref(priv->subproxies);
priv->subproxies = NULL;
}
g_mutex_unlock(&priv->mutex);
/* Unlock */
}
static
void
gbinder_proxy_object_drop_subproxies(
GBinderProxyObject* self)
{
GBinderProxyObjectPriv* priv = self->priv;
GSList* list = NULL;
/* Lock */
g_mutex_lock(&priv->mutex);
if (priv->subproxies) {
GHashTableIter it;
gpointer value;
g_hash_table_iter_init(&it, priv->subproxies);
while (g_hash_table_iter_next(&it, NULL, &value)) {
list = g_slist_append(list, gbinder_local_object_ref(value));
g_object_weak_unref(G_OBJECT(value),
gbinder_proxy_object_subproxy_gone, self);
}
g_hash_table_destroy(priv->subproxies);
priv->subproxies = NULL;
}
g_mutex_unlock(&priv->mutex);
/* Unlock */
/* Drop (and possibly destroy) the objects outside of the lock */
g_slist_free_full(list, (GDestroyNotify) gbinder_local_object_drop);
}
static
void
gbinder_proxy_remote_death_proc(
GBinderRemoteObject* obj,
void* proxy)
{
GBinderProxyObject* self = THIS(proxy);
GBinderProxyObjectPriv* priv = self->priv;
GDEBUG("Remote object %u died on %s", obj->handle, obj->ipc->dev);
gbinder_remote_object_remove_handler(obj, priv->remote_death_id);
priv->remote_death_id = 0;
/* Drop the implicit reference */
gbinder_local_object_unref(&self->parent);
}
/*==========================================================================*
* Converter
*==========================================================================*/
typedef struct gbinder_proxy_object_converter {
GBinderObjectConverter pub;
GBinderProxyObject* proxy;
GBinderIpc* remote;
GBinderIpc* local;
} GBinderProxyObjectConverter;
GBINDER_INLINE_FUNC
GBinderProxyObjectConverter*
gbinder_proxy_object_converter_cast(
GBinderObjectConverter* pub)
{
return G_CAST(pub, GBinderProxyObjectConverter, pub);
}
static
gboolean
gbinder_proxy_object_converter_check(
GBinderLocalObject* obj,
void* remote)
{
if (GBINDER_IS_PROXY_OBJECT(obj) && THIS(obj)->remote == remote) {
/* Found matching proxy object */
return TRUE;
}
/* Keep looking */
return FALSE;
}
static
GBinderLocalObject*
gbinder_proxy_object_converter_handle_to_local(
GBinderObjectConverter* pub,
guint32 handle)
{
GBinderProxyObjectConverter* c = gbinder_proxy_object_converter_cast(pub);
GBinderProxyObject* proxy = c->proxy;
GBinderProxyObjectPriv* priv = proxy->priv;
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(c->remote);
GBinderRemoteObject* remote = gbinder_object_registry_get_remote(reg,
handle, REMOTE_REGISTRY_CAN_CREATE /* but don't acquire */);
GBinderLocalObject* local = gbinder_ipc_find_local_object(c->local,
gbinder_proxy_object_converter_check, remote);
if (!local && !remote->dead) {
/* GBinderProxyObject will reference GBinderRemoteObject */
GBinderProxyObject* subp = gbinder_proxy_object_new(c->local, remote);
/*
* Auto-created proxies may get spontaneously destroyed and
* not necessarily on the UI thread.
*/
subp->priv->remote_death_id = gbinder_remote_object_add_death_handler
(remote, gbinder_proxy_remote_death_proc, subp);
/*
* Remote keeps an implicit reference to this auto-created
* proxy. The reference gets released when the remote object
* dies, i.e. by gbinder_proxy_remote_death_proc().
*/
gbinder_local_object_ref(local = GBINDER_LOCAL_OBJECT(subp));
/* Lock */
g_mutex_lock(&priv->mutex);
if (!priv->subproxies) {
priv->subproxies = g_hash_table_new(g_direct_hash, g_direct_equal);
}
g_hash_table_insert(priv->subproxies, subp, subp);
g_object_weak_ref(G_OBJECT(subp),
gbinder_proxy_object_subproxy_gone, proxy);
g_mutex_unlock(&priv->mutex);
/* Unlock */
}
/* Release the reference returned by gbinder_object_registry_get_remote */
gbinder_remote_object_unref(remote);
return local;
}
static
void
gbinder_proxy_object_converter_init(
GBinderProxyObjectConverter* convert,
GBinderProxyObject* proxy,
GBinderIpc* remote,
GBinderIpc* local)
{
static const GBinderObjectConverterFunctions gbinder_converter_fn = {
.handle_to_local = gbinder_proxy_object_converter_handle_to_local
};
GBinderObjectConverter* pub = &convert->pub;
GBinderIpc* dest = proxy->parent.ipc;
memset(convert, 0, sizeof(*convert));
convert->proxy = proxy;
convert->remote = remote;
convert->local = local;
pub->f = &gbinder_converter_fn;
pub->io = gbinder_ipc_io(dest);
pub->protocol = gbinder_ipc_protocol(dest);
}
/*==========================================================================* /*==========================================================================*
* Implementation * Implementation
*==========================================================================*/ *==========================================================================*/
@ -110,11 +293,31 @@ gbinder_proxy_tx_reply(
void* user_data) void* user_data)
{ {
GBinderProxyTx* tx = user_data; GBinderProxyTx* tx = user_data;
GBinderLocalReply* fwd = gbinder_remote_reply_copy_to_local(reply); GBinderProxyObject* self = tx->proxy;
GBinderProxyObjectConverter convert;
GBinderLocalReply* fwd;
/*
* For proxy objects auto-created by the reply, the remote side (the
* one sent the reply) will be the remote GBinderIpc and this object's
* GBinderIpc will be the local, i.e. those proxies will work in the
* same direction as the top level object. The direction gets inverted
* twice.
*/
gbinder_proxy_object_converter_init(&convert, self, ipc, self->parent.ipc);
fwd = gbinder_remote_reply_convert_to_local(reply, &convert.pub);
tx->id = 0; tx->id = 0;
gbinder_proxy_tx_dequeue(tx); gbinder_proxy_tx_dequeue(tx);
gbinder_remote_request_complete(tx->req, fwd, status); gbinder_remote_request_complete(tx->req, fwd,
(status > 0) ? (-EFAULT) : status);
if (status == GBINDER_STATUS_DEAD_OBJECT) {
/*
* Some kernels sometimes don't bother sending us death notifications.
* Let's also interpret BR_DEAD_REPLY as an obituary to make sure that
* we don't keep dead remote objects around.
*/
gbinder_remote_object_commit_suicide(self->remote);
}
gbinder_local_reply_unref(fwd); gbinder_local_reply_unref(fwd);
} }
@ -139,16 +342,14 @@ gbinder_proxy_object_handle_transaction(
guint flags, guint flags,
int* status) int* status)
{ {
GBinderProxyObject* self = GBINDER_PROXY_OBJECT(object); GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv; GBinderProxyObjectPriv* priv = self->priv;
GBinderRemoteObject* remote = self->remote; GBinderRemoteObject* remote = self->remote;
if (!priv->dropped && !gbinder_remote_object_is_dead(remote)) { if (!priv->dropped && !gbinder_remote_object_is_dead(remote)) {
GBinderIpc* remote_ipc = remote->ipc; GBinderLocalRequest* fwd;
GBinderDriver* remote_driver = remote_ipc->driver;
GBinderLocalRequest* fwd =
gbinder_remote_request_translate_to_local(req, remote_driver);
GBinderProxyTx* tx = g_slice_new0(GBinderProxyTx); GBinderProxyTx* tx = g_slice_new0(GBinderProxyTx);
GBinderProxyObjectConverter convert;
g_object_ref(tx->proxy = self); g_object_ref(tx->proxy = self);
tx->req = gbinder_remote_request_ref(req); tx->req = gbinder_remote_request_ref(req);
@ -158,9 +359,18 @@ gbinder_proxy_object_handle_transaction(
/* Mark the incoming request as pending */ /* Mark the incoming request as pending */
gbinder_remote_request_block(req); gbinder_remote_request_block(req);
/*
* For auto-created proxy objects, this object's GBinderIpc will
* become a remote, and the remote's GBinderIpc will become local
* because they work in the opposite direction.
*/
gbinder_proxy_object_converter_init(&convert, self, object->ipc,
remote->ipc);
/* Forward the transaction */ /* Forward the transaction */
tx->id = gbinder_ipc_transact(remote_ipc, remote->handle, code, flags, fwd = gbinder_remote_request_convert_to_local(req, &convert.pub);
fwd , gbinder_proxy_tx_reply, gbinder_proxy_tx_destroy, tx); tx->id = gbinder_ipc_transact(remote->ipc, remote->handle, code, flags,
fwd, gbinder_proxy_tx_reply, gbinder_proxy_tx_destroy, tx);
gbinder_local_request_unref(fwd); gbinder_local_request_unref(fwd);
*status = GBINDER_STATUS_OK; *status = GBINDER_STATUS_OK;
} else { } else {
@ -180,15 +390,50 @@ gbinder_proxy_object_can_handle_transaction(
return GBINDER_LOCAL_TRANSACTION_SUPPORTED; return GBINDER_LOCAL_TRANSACTION_SUPPORTED;
} }
static
void
gbinder_proxy_object_acquire(
GBinderLocalObject* object)
{
GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
if (priv->remote_death_id && !object->strong_refs) {
GBinderRemoteObject* remote = self->remote;
/* First strong ref, acquire the attached remote object */
gbinder_driver_acquire(remote->ipc->driver, remote->handle);
}
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->acquire(object);
}
static
void
gbinder_proxy_object_release(
GBinderLocalObject* object)
{
GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
if (priv->remote_death_id && object->strong_refs == 1) {
GBinderRemoteObject* remote = self->remote;
/* Last strong ref, release the attached remote object */
gbinder_driver_release(remote->ipc->driver, remote->handle);
}
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->release(object);
}
static static
void void
gbinder_proxy_object_drop( gbinder_proxy_object_drop(
GBinderLocalObject* object) GBinderLocalObject* object)
{ {
GBinderProxyObject* self = GBINDER_PROXY_OBJECT(object); GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv; GBinderProxyObjectPriv* priv = self->priv;
priv->dropped = TRUE; priv->dropped = TRUE;
gbinder_proxy_object_drop_subproxies(self);
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->drop(object); GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->drop(object);
} }
@ -209,10 +454,10 @@ gbinder_proxy_object_new(
* to the remote object. * to the remote object.
*/ */
GBinderLocalObject* object = gbinder_local_object_new_with_type GBinderLocalObject* object = gbinder_local_object_new_with_type
(GBINDER_TYPE_PROXY_OBJECT, src, NULL, NULL, NULL); (THIS_TYPE, src, NULL, NULL, NULL);
if (object) { if (object) {
GBinderProxyObject* self = GBINDER_PROXY_OBJECT(object); GBinderProxyObject* self = THIS(object);
self->remote = gbinder_remote_object_ref(remote); self->remote = gbinder_remote_object_ref(remote);
return self; return self;
@ -230,9 +475,13 @@ void
gbinder_proxy_object_finalize( gbinder_proxy_object_finalize(
GObject* object) GObject* object)
{ {
GBinderProxyObject* self = GBINDER_PROXY_OBJECT(object); GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
gbinder_proxy_object_drop_subproxies(self);
gbinder_remote_object_remove_handler(self->remote, priv->remote_death_id);
gbinder_remote_object_unref(self->remote); gbinder_remote_object_unref(self->remote);
g_mutex_clear(&priv->mutex);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object); G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
} }
@ -241,8 +490,11 @@ void
gbinder_proxy_object_init( gbinder_proxy_object_init(
GBinderProxyObject* self) GBinderProxyObject* self)
{ {
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, GBINDER_TYPE_PROXY_OBJECT, GBinderProxyObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
GBinderProxyObjectPriv); THIS_TYPE, GBinderProxyObjectPriv);
self->priv = priv;
g_mutex_init(&priv->mutex);
} }
static static
@ -256,6 +508,8 @@ gbinder_proxy_object_class_init(
object_class->finalize = gbinder_proxy_object_finalize; object_class->finalize = gbinder_proxy_object_finalize;
klass->can_handle_transaction = gbinder_proxy_object_can_handle_transaction; klass->can_handle_transaction = gbinder_proxy_object_can_handle_transaction;
klass->handle_transaction = gbinder_proxy_object_handle_transaction; klass->handle_transaction = gbinder_proxy_object_handle_transaction;
klass->acquire = gbinder_proxy_object_acquire;
klass->release = gbinder_proxy_object_release;
klass->drop = gbinder_proxy_object_drop; klass->drop = gbinder_proxy_object_drop;
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -40,15 +40,16 @@
struct gbinder_remote_object_priv { struct gbinder_remote_object_priv {
GMainContext* context; GMainContext* context;
gboolean acquired;
}; };
typedef GObjectClass GBinderRemoteObjectClass; typedef GObjectClass GBinderRemoteObjectClass;
GType gbinder_remote_object_get_type(void) GBINDER_INTERNAL;
G_DEFINE_TYPE(GBinderRemoteObject, gbinder_remote_object, G_TYPE_OBJECT) G_DEFINE_TYPE(GBinderRemoteObject, gbinder_remote_object, G_TYPE_OBJECT)
GType gbinder_remote_object_get_type(void); #define PARENT_CLASS gbinder_remote_object_parent_class
#define GBINDER_TYPE_REMOTE_OBJECT (gbinder_remote_object_get_type()) #define THIS_TYPE (gbinder_remote_object_get_type())
#define GBINDER_REMOTE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ #define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,THIS_TYPE,GBinderRemoteObject)
GBINDER_TYPE_REMOTE_OBJECT, GBinderRemoteObject))
enum gbinder_remote_object_signal { enum gbinder_remote_object_signal {
SIGNAL_DEATH, SIGNAL_DEATH,
@ -65,31 +66,31 @@ static guint gbinder_remote_object_signals[SIGNAL_COUNT] = { 0 };
static static
void void
gbinder_remote_object_died_on_main_thread( gbinder_remote_object_handle_death_on_main_thread(
GBinderRemoteObject* self) GBinderRemoteObject* self)
{ {
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
GASSERT(!self->dead);
if (!self->dead) { if (!self->dead) {
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
GBinderRemoteObjectPriv* priv = self->priv;
self->dead = TRUE; self->dead = TRUE;
priv->acquired = FALSE;
/* ServiceManager always has the same handle, and can be reanimated. */ /* ServiceManager always has the same handle, and can be reanimated. */
if (self->handle != GBINDER_SERVICEMANAGER_HANDLE) { if (self->handle != GBINDER_SERVICEMANAGER_HANDLE) {
gbinder_ipc_invalidate_remote_handle(self->ipc, self->handle); gbinder_ipc_invalidate_remote_handle(ipc, self->handle);
} }
gbinder_driver_clear_death_notification(driver, self); gbinder_driver_dead_binder_done(driver, self);
gbinder_driver_release(driver, self->handle);
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0); g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
} }
} }
static static
gboolean gboolean
gbinder_remote_object_died_handle( gbinder_remote_object_death_notification_proc(
gpointer self) gpointer self)
{ {
gbinder_remote_object_died_on_main_thread(GBINDER_REMOTE_OBJECT(self)); gbinder_remote_object_handle_death_on_main_thread(THIS(self));
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
@ -108,16 +109,20 @@ gbinder_remote_object_reanimate(
*/ */
if (self->dead) { if (self->dead) {
GBinderIpc* ipc = self->ipc; GBinderIpc* ipc = self->ipc;
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc); guint32 handle = self->handle;
/* Kick the horse */ /* Kick the horse */
GASSERT(self->handle == GBINDER_SERVICEMANAGER_HANDLE); GASSERT(self->handle == GBINDER_SERVICEMANAGER_HANDLE);
if (gbinder_driver_ping(ipc->driver, reg, self->handle) == 0) { if (gbinder_ipc_ping_sync(ipc, handle, &gbinder_ipc_sync_main) == 0) {
GBinderRemoteObjectPriv* priv = self->priv;
GBinderDriver* driver = ipc->driver;
/* Wow, it's alive! */ /* Wow, it's alive! */
self->dead = FALSE; self->dead = FALSE;
gbinder_ipc_looper_check(self->ipc); /* For death notifications */ priv->acquired = TRUE;
gbinder_driver_acquire(ipc->driver, self->handle); gbinder_ipc_looper_check(ipc); /* For death notifications */
gbinder_driver_request_death_notification(ipc->driver, self); gbinder_driver_acquire(driver, handle);
gbinder_driver_request_death_notification(driver, self);
} }
} }
return !self->dead; return !self->dead;
@ -131,8 +136,26 @@ gbinder_remote_object_handle_death_notification(
* checked the object pointer */ * checked the object pointer */
GVERBOSE_("%p %u", self, self->handle); GVERBOSE_("%p %u", self, self->handle);
g_main_context_invoke_full(self->priv->context, G_PRIORITY_DEFAULT, g_main_context_invoke_full(self->priv->context, G_PRIORITY_DEFAULT,
gbinder_remote_object_died_handle, gbinder_remote_object_ref(self), gbinder_remote_object_death_notification_proc,
g_object_unref); gbinder_remote_object_ref(self), g_object_unref);
}
void
gbinder_remote_object_commit_suicide(
GBinderRemoteObject* self)
{
/* This function is only invoked by GBinderProxyObject in context of
* the main thread, the object pointer is checked by the caller */
if (!self->dead) {
GBinderRemoteObjectPriv* priv = self->priv;
self->dead = TRUE;
priv->acquired = FALSE;
GVERBOSE_("%p %u", self, self->handle);
gbinder_ipc_invalidate_remote_handle(self->ipc, self->handle);
/* Don't submit BC_DEAD_BINDER_DONE because this is a suicide */
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
}
} }
/*==========================================================================* /*==========================================================================*
@ -143,17 +166,29 @@ GBinderRemoteObject*
gbinder_remote_object_new( gbinder_remote_object_new(
GBinderIpc* ipc, GBinderIpc* ipc,
guint32 handle, guint32 handle,
gboolean dead) REMOTE_OBJECT_CREATE create)
{ {
if (G_LIKELY(ipc)) { if (G_LIKELY(ipc)) {
GBinderRemoteObject* self = g_object_new GBinderRemoteObject* self = g_object_new(THIS_TYPE, NULL);
(GBINDER_TYPE_REMOTE_OBJECT, NULL); GBinderRemoteObjectPriv* priv = self->priv;
self->ipc = gbinder_ipc_ref(ipc); self->ipc = gbinder_ipc_ref(ipc);
self->handle = handle; self->handle = handle;
if (!(self->dead = dead)) { switch (create) {
case REMOTE_OBJECT_CREATE_DEAD:
self->dead = TRUE;
break;
case REMOTE_OBJECT_CREATE_ACQUIRED:
priv->acquired = TRUE;
/* fallthrough */
case REMOTE_OBJECT_CREATE_ALIVE:
break;
}
if (!self->dead) {
gbinder_ipc_looper_check(self->ipc); /* For death notifications */ gbinder_ipc_looper_check(self->ipc); /* For death notifications */
gbinder_driver_acquire(ipc->driver, handle); if (priv->acquired) {
gbinder_driver_acquire(ipc->driver, handle);
}
gbinder_driver_request_death_notification(ipc->driver, self); gbinder_driver_request_death_notification(ipc->driver, self);
} }
return self; return self;
@ -166,7 +201,7 @@ gbinder_remote_object_ref(
GBinderRemoteObject* self) GBinderRemoteObject* self)
{ {
if (G_LIKELY(self)) { if (G_LIKELY(self)) {
g_object_ref(GBINDER_REMOTE_OBJECT(self)); g_object_ref(THIS(self));
return self; return self;
} else { } else {
return NULL; return NULL;
@ -178,7 +213,7 @@ gbinder_remote_object_unref(
GBinderRemoteObject* self) GBinderRemoteObject* self)
{ {
if (G_LIKELY(self)) { if (G_LIKELY(self)) {
g_object_unref(GBINDER_REMOTE_OBJECT(self)); g_object_unref(THIS(self));
} }
} }
@ -230,7 +265,7 @@ gbinder_remote_object_init(
GBinderRemoteObject* self) GBinderRemoteObject* self)
{ {
GBinderRemoteObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self, GBinderRemoteObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
GBINDER_TYPE_REMOTE_OBJECT, GBinderRemoteObjectPriv); THIS_TYPE, GBinderRemoteObjectPriv);
priv->context = g_main_context_default(); priv->context = g_main_context_default();
self->priv = priv; self->priv = priv;
@ -239,29 +274,32 @@ gbinder_remote_object_init(
static static
void void
gbinder_remote_object_dispose( gbinder_remote_object_dispose(
GObject* remote) GObject* object)
{ {
GBinderRemoteObject* self = GBINDER_REMOTE_OBJECT(remote); GBinderRemoteObject* self = THIS(object);
gbinder_ipc_remote_object_disposed(self->ipc, self); gbinder_ipc_remote_object_disposed(self->ipc, self);
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->dispose(remote); G_OBJECT_CLASS(PARENT_CLASS)->dispose(object);
} }
static static
void void
gbinder_remote_object_finalize( gbinder_remote_object_finalize(
GObject* remote) GObject* object)
{ {
GBinderRemoteObject* self = GBINDER_REMOTE_OBJECT(remote); GBinderRemoteObject* self = THIS(object);
GBinderRemoteObjectPriv* priv = self->priv;
GBinderIpc* ipc = self->ipc; GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver; GBinderDriver* driver = ipc->driver;
if (!self->dead) { if (!self->dead) {
gbinder_driver_clear_death_notification(driver, self); gbinder_driver_clear_death_notification(driver, self);
gbinder_driver_release(driver, self->handle); if (priv->acquired) {
gbinder_driver_release(driver, self->handle);
}
} }
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->finalize(remote); G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
} }
static static

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -51,11 +51,17 @@ struct gbinder_remote_object {
#define gbinder_remote_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver)) #define gbinder_remote_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
#define gbinder_remote_object_io(obj) (gbinder_driver_io((obj)->ipc->driver)) #define gbinder_remote_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
typedef enum gbinder_remote_object_create {
REMOTE_OBJECT_CREATE_DEAD,
REMOTE_OBJECT_CREATE_ALIVE,
REMOTE_OBJECT_CREATE_ACQUIRED
} REMOTE_OBJECT_CREATE;
GBinderRemoteObject* GBinderRemoteObject*
gbinder_remote_object_new( gbinder_remote_object_new(
GBinderIpc* ipc, GBinderIpc* ipc,
guint32 handle, guint32 handle,
gboolean maybe_dead) REMOTE_OBJECT_CREATE create)
GBINDER_INTERNAL; GBINDER_INTERNAL;
gboolean gboolean
@ -68,6 +74,11 @@ gbinder_remote_object_handle_death_notification(
GBinderRemoteObject* obj) GBinderRemoteObject* obj)
GBINDER_INTERNAL; GBINDER_INTERNAL;
void
gbinder_remote_object_commit_suicide(
GBinderRemoteObject* self)
GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_OBJECT_PRIVATE_H */ #endif /* GBINDER_REMOTE_OBJECT_PRIVATE_H */
/* /*

View File

@ -117,6 +117,14 @@ gbinder_remote_reply_is_empty(
GBinderLocalReply* GBinderLocalReply*
gbinder_remote_reply_copy_to_local( gbinder_remote_reply_copy_to_local(
GBinderRemoteReply* self) GBinderRemoteReply* self)
{
return gbinder_remote_reply_convert_to_local(self, NULL);
}
GBinderLocalReply*
gbinder_remote_reply_convert_to_local(
GBinderRemoteReply* self,
GBinderObjectConverter* convert)
{ {
if (G_LIKELY(self)) { if (G_LIKELY(self)) {
GBinderReaderData* d = &self->data; GBinderReaderData* d = &self->data;
@ -124,7 +132,7 @@ gbinder_remote_reply_copy_to_local(
if (reg) { if (reg) {
return gbinder_local_reply_set_contents return gbinder_local_reply_set_contents
(gbinder_local_reply_new(reg->io), d->buffer); (gbinder_local_reply_new(reg->io), d->buffer, convert);
} }
} }
return NULL; return NULL;

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -42,6 +42,12 @@ gbinder_remote_reply_new(
GBinderObjectRegistry* reg) GBinderObjectRegistry* reg)
GBINDER_INTERNAL; GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_remote_reply_convert_to_local(
GBinderRemoteReply* reply,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
void void
gbinder_remote_reply_set_data( gbinder_remote_reply_set_data(
GBinderRemoteReply* reply, GBinderRemoteReply* reply,

View File

@ -34,6 +34,7 @@
#include "gbinder_reader_p.h" #include "gbinder_reader_p.h"
#include "gbinder_rpc_protocol.h" #include "gbinder_rpc_protocol.h"
#include "gbinder_local_request_p.h" #include "gbinder_local_request_p.h"
#include "gbinder_object_converter.h"
#include "gbinder_object_registry.h" #include "gbinder_object_registry.h"
#include "gbinder_buffer_p.h" #include "gbinder_buffer_p.h"
#include "gbinder_driver.h" #include "gbinder_driver.h"
@ -86,31 +87,31 @@ gbinder_remote_request_copy_to_local(
if (G_LIKELY(self)) { if (G_LIKELY(self)) {
GBinderReaderData* d = &self->data; GBinderReaderData* d = &self->data;
return gbinder_local_request_new_from_data(d->buffer); return gbinder_local_request_new_from_data(d->buffer, NULL);
} }
return NULL; return NULL;
} }
GBinderLocalRequest* GBinderLocalRequest*
gbinder_remote_request_translate_to_local( gbinder_remote_request_convert_to_local(
GBinderRemoteRequest* req, GBinderRemoteRequest* req,
GBinderDriver* driver) GBinderObjectConverter* convert)
{ {
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req); GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) { if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data; GBinderReaderData* data = &self->data;
if (!driver || (gbinder_driver_protocol(driver) == self->protocol)) { if (!convert || convert->protocol == self->protocol) {
/* The same protocol, the same format of RPC header */ /* The same protocol, the same format of RPC header */
return gbinder_local_request_new_from_data(data->buffer); return gbinder_local_request_new_from_data(data->buffer, convert);
} else { } else {
/* Need to translate to another format */ /* Need to translate to another format */
GBinderLocalRequest* local = gbinder_driver_local_request_new GBinderLocalRequest* local = gbinder_local_request_new_iface
(driver, self->iface); (convert->io, convert->protocol, self->iface);
gbinder_local_request_append_contents(local, data->buffer, gbinder_local_request_append_contents(local, data->buffer,
self->header_size); self->header_size, convert);
return local; return local;
} }
} }

View File

@ -57,9 +57,9 @@ gbinder_remote_request_set_data(
GBINDER_INTERNAL; GBINDER_INTERNAL;
GBinderLocalRequest* GBinderLocalRequest*
gbinder_remote_request_translate_to_local( gbinder_remote_request_convert_to_local(
GBinderRemoteRequest* req, GBinderRemoteRequest* req,
GBinderDriver* driver) GBinderObjectConverter* convert)
GBINDER_INTERNAL; GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */ #endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */

View File

@ -529,9 +529,8 @@ gbinder_servicemanager_new_with_type(
if (!dev) dev = klass->default_device; if (!dev) dev = klass->default_device;
ipc = gbinder_ipc_new(dev); ipc = gbinder_ipc_new(dev);
if (ipc) { if (ipc) {
/* Create a possibly dead remote object */ /* Create a (possibly) dead service manager object */
GBinderRemoteObject* object = gbinder_ipc_get_remote_object GBinderRemoteObject* object = gbinder_ipc_get_service_manager(ipc);
(ipc, GBINDER_SERVICEMANAGER_HANDLE, TRUE);
if (object) { if (object) {
gboolean first_ref; gboolean first_ref;

View File

@ -39,9 +39,6 @@
#include <glib-object.h> #include <glib-object.h>
/* As a special case, ServiceManager's handle is zero */
#define GBINDER_SERVICEMANAGER_HANDLE (0)
typedef struct gbinder_servicemanager_priv GBinderServiceManagerPriv; typedef struct gbinder_servicemanager_priv GBinderServiceManagerPriv;
typedef struct gbinder_servicemanager { typedef struct gbinder_servicemanager {

View File

@ -36,10 +36,12 @@
#include <gbinder_types.h> #include <gbinder_types.h>
typedef struct gbinder_buffer_contents GBinderBufferContents; typedef struct gbinder_buffer_contents GBinderBufferContents;
typedef struct gbinder_buffer_contents_list GBinderBufferContentsList;
typedef struct gbinder_cleanup GBinderCleanup; typedef struct gbinder_cleanup GBinderCleanup;
typedef struct gbinder_driver GBinderDriver; typedef struct gbinder_driver GBinderDriver;
typedef struct gbinder_handler GBinderHandler; typedef struct gbinder_handler GBinderHandler;
typedef struct gbinder_io GBinderIo; typedef struct gbinder_io GBinderIo;
typedef struct gbinder_object_converter GBinderObjectConverter;
typedef struct gbinder_object_registry GBinderObjectRegistry; typedef struct gbinder_object_registry GBinderObjectRegistry;
typedef struct gbinder_output_data GBinderOutputData; typedef struct gbinder_output_data GBinderOutputData;
typedef struct gbinder_proxy_object GBinderProxyObject; typedef struct gbinder_proxy_object GBinderProxyObject;
@ -72,6 +74,9 @@ typedef struct gbinder_ipc_sync_api GBinderIpcSyncApi;
#define HIDL_DEBUG_TRANSACTION HIDL_FOURCC('D','B','G') #define HIDL_DEBUG_TRANSACTION HIDL_FOURCC('D','B','G')
#define HIDL_HASH_CHAIN_TRANSACTION HIDL_FOURCC('H','S','H') #define HIDL_HASH_CHAIN_TRANSACTION HIDL_FOURCC('H','S','H')
/* As a special case, ServiceManager's handle is zero */
#define GBINDER_SERVICEMANAGER_HANDLE (0)
#endif /* GBINDER_TYPES_PRIVATE_H */ #endif /* GBINDER_TYPES_PRIVATE_H */
/* /*

View File

@ -32,6 +32,8 @@
#include "gbinder_writer_p.h" #include "gbinder_writer_p.h"
#include "gbinder_buffer_p.h" #include "gbinder_buffer_p.h"
#include "gbinder_local_object.h"
#include "gbinder_object_converter.h"
#include "gbinder_io.h" #include "gbinder_io.h"
#include "gbinder_log.h" #include "gbinder_log.h"
@ -55,62 +57,88 @@ GBINDER_INLINE_FUNC GBinderWriterPriv* gbinder_writer_cast(GBinderWriter* pub)
GBINDER_INLINE_FUNC GBinderWriterData* gbinder_writer_data(GBinderWriter* pub) GBINDER_INLINE_FUNC GBinderWriterData* gbinder_writer_data(GBinderWriter* pub)
{ return G_LIKELY(pub) ? gbinder_writer_cast(pub)->data : NULL; } { return G_LIKELY(pub) ? gbinder_writer_cast(pub)->data : NULL; }
static
void
gbinder_writer_data_buffer_cleanup(
gpointer data)
{
gbinder_buffer_contents_unref((GBinderBufferContents*)data);
}
void void
gbinder_writer_data_set_contents( gbinder_writer_data_set_contents(
GBinderWriterData* data, GBinderWriterData* data,
GBinderBuffer* buffer) GBinderBuffer* buffer,
GBinderObjectConverter* convert)
{ {
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); gbinder_cleanup_reset(data->cleanup);
gbinder_writer_data_append_contents(data, buffer, 0); gbinder_writer_data_append_contents(data, buffer, 0, convert);
} }
void void
gbinder_writer_data_append_contents( gbinder_writer_data_append_contents(
GBinderWriterData* data, GBinderWriterData* data,
GBinderBuffer* buffer, GBinderBuffer* buffer,
gsize off) gsize off,
GBinderObjectConverter* convert)
{ {
GBinderBufferContents* contents = gbinder_buffer_contents(buffer); GBinderBufferContents* contents = gbinder_buffer_contents(buffer);
if (contents) { if (contents) {
gsize bufsize; gsize bufsize;
GByteArray* dest = data->bytes;
const guint8* bufdata = gbinder_buffer_data(buffer, &bufsize); const guint8* bufdata = gbinder_buffer_data(buffer, &bufsize);
void** objects = gbinder_buffer_objects(buffer); void** objects = gbinder_buffer_objects(buffer);
if (off < bufsize) { data->cleanup = gbinder_cleanup_add(data->cleanup, (GDestroyNotify)
g_byte_array_append(data->bytes, bufdata + off, bufsize - off); gbinder_buffer_contents_unref,
}
data->cleanup = gbinder_cleanup_add(data->cleanup,
gbinder_writer_data_buffer_cleanup,
gbinder_buffer_contents_ref(contents)); gbinder_buffer_contents_ref(contents));
if (objects && *objects) { if (objects && *objects) {
const GBinderIo* io = gbinder_buffer_io(buffer); const GBinderIo* io = gbinder_buffer_io(buffer);
/* GBinderIo must be the same because it's defined by the kernel */
GASSERT(io == data->io);
if (!data->offsets) { if (!data->offsets) {
data->offsets = gutil_int_array_new(); data->offsets = gutil_int_array_new();
} }
while (*objects) { while (*objects) {
const guint8* obj = *objects++; const guint8* obj = *objects++;
gsize offset = obj - bufdata; gsize objsize, offset = obj - bufdata;
gsize objsize = io->object_data_size(obj); GBinderLocalObject* local;
guint32 handle;
GASSERT(offset >= off && offset < bufsize);
if (offset > off) {
/* Copy serialized data preceeding this object */
g_byte_array_append(dest, bufdata + off, offset - off);
off = offset;
}
/* Offset in the destination buffer */
gutil_int_array_append(data->offsets, dest->len);
/* Convert remote object into local if necessary */
if (convert && io->decode_binder_handle(obj, &handle) &&
(local = gbinder_object_converter_handle_to_local
(convert, handle))) {
const guint pos = dest->len;
g_byte_array_set_size(dest, pos +
GBINDER_MAX_BINDER_OBJECT_SIZE);
objsize = io->encode_local_object(dest->data + pos, local);
g_byte_array_set_size(dest, pos + objsize);
/* Keep the reference */
data->cleanup = gbinder_cleanup_add(data->cleanup,
(GDestroyNotify) gbinder_local_object_unref, local);
} else {
objsize = io->object_size(obj);
g_byte_array_append(dest, obj, objsize);
}
GASSERT(offset > 0 && offset < bufsize);
gutil_int_array_append(data->offsets, (int)offset);
/* Size of each buffer has to be 8-byte aligned */ /* Size of each buffer has to be 8-byte aligned */
data->buffers_size += G_ALIGN8(objsize); data->buffers_size += G_ALIGN8(io->object_data_size(obj));
off += objsize;
} }
} }
if (off < bufsize) {
/* Copy remaining data */
g_byte_array_append(dest, bufdata + off, bufsize - off);
}
} }
} }

View File

@ -54,14 +54,16 @@ gbinder_writer_init(
void void
gbinder_writer_data_set_contents( gbinder_writer_data_set_contents(
GBinderWriterData* data, GBinderWriterData* data,
GBinderBuffer* buffer) GBinderBuffer* buffer,
GBinderObjectConverter* convert)
GBINDER_INTERNAL; GBINDER_INTERNAL;
void void
gbinder_writer_data_append_contents( gbinder_writer_data_append_contents(
GBinderWriterData* data, GBinderWriterData* data,
GBinderBuffer* buffer, GBinderBuffer* buffer,
gsize data_offset) gsize data_offset,
GBinderObjectConverter* convert)
GBINDER_INTERNAL; GBINDER_INTERNAL;
void void

View File

@ -136,7 +136,6 @@ app_init(
GError* error = NULL; GError* error = NULL;
GOptionContext* options = g_option_context_new("SRC DST NAME IFACES..."); GOptionContext* options = g_option_context_new("SRC DST NAME IFACES...");
gutil_log_timestamp = FALSE;
gutil_log_default.level = GLOG_LEVEL_DEFAULT; gutil_log_default.level = GLOG_LEVEL_DEFAULT;
g_option_context_add_main_entries(options, entries, NULL); g_option_context_add_main_entries(options, entries, NULL);

View File

@ -53,7 +53,7 @@ GLOG_MODULE_DEFINE2("test_binder", gutil_log_default);
static GHashTable* test_fd_map = NULL; static GHashTable* test_fd_map = NULL;
static GHashTable* test_node_map = NULL; static GHashTable* test_node_map = NULL;
static GPrivate test_looper = G_PRIVATE_INIT(NULL); static GPrivate test_looper = G_PRIVATE_INIT(NULL);
static GPrivate test_tx_state = G_PRIVATE_INIT(g_free); static GPrivate test_tx_state = G_PRIVATE_INIT(NULL);
G_LOCK_DEFINE_STATIC(test_binder); G_LOCK_DEFINE_STATIC(test_binder);
static GMainLoop* test_binder_exit_loop = NULL; static GMainLoop* test_binder_exit_loop = NULL;
@ -78,8 +78,16 @@ static GMainLoop* test_binder_exit_loop = NULL;
#define TF_ACCEPT_FDS 0x10 #define TF_ACCEPT_FDS 0x10
#define READ_FLAG_TX_COMPLETION (0x01) #define READ_FLAG_TX_COMPLETION (0x01)
#define READ_FLAG_TX_OTHER (0x02) #define READ_FLAG_TX_INCOMING (0x02)
#define READ_FLAG_ALL (READ_FLAG_TX_COMPLETION|READ_FLAG_TX_OTHER) #define READ_FLAG_TX_REPLY (0x04)
#define READ_FLAG_TX_ERROR (0x08)
#define READ_FLAG_TX_OTHER (0x10)
#define READ_FLAGS_ALL (\
READ_FLAG_TX_COMPLETION | \
READ_FLAG_TX_INCOMING | \
READ_FLAG_TX_REPLY | \
READ_FLAG_TX_ERROR | \
READ_FLAG_TX_OTHER)
typedef struct test_binder_io TestBinderIo; typedef struct test_binder_io TestBinderIo;
@ -98,9 +106,18 @@ typedef struct test_binder_submit_thread {
TestBinder* binder; TestBinder* binder;
} TestBinderSubmitThread; } TestBinderSubmitThread;
typedef enum test_tx_state {
TEST_TX_STATE_NONE,
TEST_TX_STATE_ONEWAY,
TEST_TX_STATE_ACTIVE,
TEST_TX_STATE_REPLY
} TEST_TX_STATE;
/* TestBinderTxState has to be stacked to support nested transactions */
typedef struct test_binder_tx_state { typedef struct test_binder_tx_state {
int tid; int tid;
gboolean one_way; int depth;
TEST_TX_STATE* stack;
} TestBinderTxState; } TestBinderTxState;
typedef struct test_binder_node TestBinderNode; typedef struct test_binder_node TestBinderNode;
@ -218,6 +235,7 @@ typedef struct binder_buffer_64 {
#define BR_DECREFS_64 _IOR('r', 10, BinderPtrCookie64) #define BR_DECREFS_64 _IOR('r', 10, BinderPtrCookie64)
#define BR_NOOP _IO('r', 12) #define BR_NOOP _IO('r', 12)
#define BR_DEAD_BINDER_64 _IOR('r', 15, guint64) #define BR_DEAD_BINDER_64 _IOR('r', 15, guint64)
#define BR_CLEAR_DEATH_NOTIFICATION_DONE_64 _IOR('r', 16, guint64)
#define BR_FAILED_REPLY _IO('r', 17) #define BR_FAILED_REPLY _IO('r', 17)
static static
@ -371,6 +389,22 @@ test_binder_exit_wait(
G_UNLOCK(test_binder); G_UNLOCK(test_binder);
} }
static
void
test_binder_object_dead_locked(
TestBinder* binder,
guint64 handle)
{
/* Caller has to remove the object from handle_map and object_map */
guint32 cmd[3];
/* Send DEAD_BINDER to both ends of the socket */
cmd[0] = BR_DEAD_BINDER_64;
*(guint64*)(cmd + 1) = GPOINTER_TO_SIZE(handle);
write(binder->node[0].fd, cmd, sizeof(cmd));
write(binder->node[1].fd, cmd, sizeof(cmd));
}
static static
void void
test_binder_local_object_gone( test_binder_local_object_gone(
@ -383,16 +417,10 @@ test_binder_local_object_gone(
GDEBUG("Object %p is gone", obj); GDEBUG("Object %p is gone", obj);
if (g_hash_table_contains(binder->object_map, obj)) { if (g_hash_table_contains(binder->object_map, obj)) {
gpointer handle = g_hash_table_lookup(binder->object_map, obj); gpointer handle = g_hash_table_lookup(binder->object_map, obj);
guint32 cmd[3];
test_binder_object_dead_locked(binder, GPOINTER_TO_SIZE(handle));
g_hash_table_remove(binder->handle_map, handle); g_hash_table_remove(binder->handle_map, handle);
g_hash_table_remove(binder->object_map, obj); g_hash_table_remove(binder->object_map, obj);
/* Send DEAD_BINDER to both ends of the socket */
cmd[0] = BR_DEAD_BINDER_64;
*(guint64*)(cmd + 1) = GPOINTER_TO_SIZE(handle);
write(binder->node[0].fd, cmd, sizeof(cmd));
write(binder->node[1].fd, cmd, sizeof(cmd));
} }
G_UNLOCK(test_binder); G_UNLOCK(test_binder);
} }
@ -507,10 +535,14 @@ test_binder_cmd_read_flags(
{ {
switch (cmd) { switch (cmd) {
case BR_TRANSACTION_COMPLETE: case BR_TRANSACTION_COMPLETE:
return READ_FLAG_TX_COMPLETION;
case BR_TRANSACTION_64:
return READ_FLAG_TX_INCOMING;
case BR_REPLY_64:
return READ_FLAG_TX_REPLY;
case BR_FAILED_REPLY: case BR_FAILED_REPLY:
case BR_DEAD_REPLY: case BR_DEAD_REPLY:
case BR_REPLY_64: return READ_FLAG_TX_ERROR;
return READ_FLAG_TX_COMPLETION;
default: default:
return READ_FLAG_TX_OTHER; return READ_FLAG_TX_OTHER;
} }
@ -613,6 +645,84 @@ test_io_short_wait()
usleep(100000); /* 100 ms */ usleep(100000); /* 100 ms */
} }
static
TestBinderTxState*
test_tx_state_acquire(
TestBinderNode* node,
TEST_TX_STATE state)
{
TestBinderTxState* my_tx_state = g_private_get(&test_tx_state);
if (my_tx_state) {
g_assert_cmpint(my_tx_state->tid, == ,gettid());
} else {
my_tx_state = g_new0(TestBinderTxState, 1);
my_tx_state->tid = gettid(); /* For debugging */
g_private_set(&test_tx_state, my_tx_state);
}
my_tx_state->stack = g_renew(TEST_TX_STATE, my_tx_state->stack,
my_tx_state->depth + 1);
my_tx_state->stack[my_tx_state->depth++] = state;
while (g_atomic_pointer_get(&node->tx_state) != my_tx_state &&
!g_atomic_pointer_compare_and_exchange(&node->tx_state, NULL,
my_tx_state)) {
GDEBUG("Thread %d is waiting to become a transacton thread",
my_tx_state->tid);
test_io_short_wait();
}
return my_tx_state;
}
static
void
test_tx_state_release(
TestBinderNode* node)
{
TestBinderTxState* my_tx_state = g_private_get(&test_tx_state);
g_assert(my_tx_state);
g_assert(my_tx_state->depth > 0);
g_assert_cmpint(my_tx_state->tid, == ,gettid());
if (my_tx_state->depth == 1) {
GDEBUG("Thread %d done with the transaction", my_tx_state->tid);
g_assert(g_atomic_pointer_compare_and_exchange(&node->tx_state,
my_tx_state, NULL));
g_private_set(&test_tx_state, NULL);
g_free(my_tx_state->stack);
g_free(my_tx_state);
} else {
my_tx_state->depth--;
my_tx_state->stack = g_renew(TEST_TX_STATE, my_tx_state->stack,
my_tx_state->depth);
GDEBUG("Thread %d is still a transacton thread", my_tx_state->tid);
}
}
static
TEST_TX_STATE
test_tx_state_get(
TestBinderTxState* tx_state)
{
if (tx_state) {
g_assert_cmpint(tx_state->depth, > ,0);
return tx_state->stack[tx_state->depth - 1];
} else {
return TEST_TX_STATE_NONE;
}
}
static
void
test_tx_state_set(
TestBinderTxState* tx_state,
TEST_TX_STATE state)
{
g_assert(tx_state);
g_assert_cmpint(tx_state->depth, > ,0);
tx_state->stack[tx_state->depth - 1] = state;
}
static static
gssize gssize
test_io_passthough_write_64( test_io_passthough_write_64(
@ -620,14 +730,17 @@ test_io_passthough_write_64(
const void* bytes, const void* bytes,
gsize bytes_to_write) gsize bytes_to_write)
{ {
const guint code = *(guint32*)bytes; const guint32 code = *(guint32*)bytes;
TestBinderNode* node = fd->node; TestBinderNode* node = fd->node;
TestBinderNode* other = node->other;
TestBinder* binder = node->binder; TestBinder* binder = node->binder;
BinderTransactionData64* tx = NULL; BinderTransactionData64* tx = NULL;
TestBinderTxState* my_tx_state = g_private_get(&test_tx_state); TestBinderTxState* my_tx_state = g_private_get(&test_tx_state);
const BinderHandleCookie64* hc;
gssize bytes_written; gssize bytes_written;
guint32* buf; guint32* buf;
guint32* cmd; guint32* cmd;
guint64* cookie;
guint32 buflen; guint32 buflen;
void* data; void* data;
@ -636,9 +749,18 @@ test_io_passthough_write_64(
case BC_ACQUIRE: case BC_ACQUIRE:
case BC_RELEASE: case BC_RELEASE:
case BC_REQUEST_DEATH_NOTIFICATION_64: case BC_REQUEST_DEATH_NOTIFICATION_64:
case BC_CLEAR_DEATH_NOTIFICATION_64:
case BC_DEAD_BINDER_DONE: case BC_DEAD_BINDER_DONE:
return bytes_to_write; return bytes_to_write;
case BC_CLEAR_DEATH_NOTIFICATION_64:
hc = (const BinderHandleCookie64*)((guint32*)bytes + 1);
g_assert(bytes_to_write == (sizeof(guint32) + sizeof(*hc)));
buflen = sizeof(guint32) + sizeof(*cookie);
cmd = g_memdup(bytes, buflen);
*cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE_64;
*(guint64*)(cmd + 1) = hc->cookie;
g_assert(write(other->fd, cmd, buflen) == buflen);
g_free(cmd);
return bytes_to_write;
default: default:
break; break;
} }
@ -646,42 +768,21 @@ test_io_passthough_write_64(
buf = cmd = g_memdup(bytes, bytes_to_write); buf = cmd = g_memdup(bytes, bytes_to_write);
data = cmd + 1; data = cmd + 1;
switch (*cmd) { switch (*cmd) {
case BR_TRANSACTION_64:
*cmd = BC_TRANSACTION_64;
tx = data;
break;
case BC_TRANSACTION_64: case BC_TRANSACTION_64:
case BC_TRANSACTION_SG_64: case BC_TRANSACTION_SG_64:
*cmd = BR_TRANSACTION_64; *cmd = BR_TRANSACTION_64;
tx = data; tx = data;
tx->sender_pid = getpid(); tx->sender_pid = getpid();
tx->sender_euid = geteuid(); tx->sender_euid = geteuid();
if (my_tx_state) { my_tx_state = test_tx_state_acquire(node, (tx->flags & TF_ONE_WAY) ?
g_assert_cmpint(my_tx_state->tid, == ,gettid()); TEST_TX_STATE_ONEWAY : TEST_TX_STATE_ACTIVE);
} else {
my_tx_state = g_new0(TestBinderTxState, 1);
my_tx_state->tid = gettid(); /* For debugging */
g_private_set(&test_tx_state, my_tx_state);
}
my_tx_state->one_way = (tx->flags & TF_ONE_WAY) ? TRUE : FALSE;
while (g_atomic_pointer_get(&node->tx_state) != my_tx_state &&
!g_atomic_pointer_compare_and_exchange(&node->tx_state, NULL,
my_tx_state)) {
GDEBUG("Thread %d is waiting to become a transacton thread",
my_tx_state->tid);
test_io_short_wait();
}
GDEBUG("Transaction thread %d", my_tx_state->tid); GDEBUG("Transaction thread %d", my_tx_state->tid);
break; break;
case BR_REPLY_64:
*cmd = BC_REPLY_64;
tx = data;
break;
case BC_REPLY_64: case BC_REPLY_64:
case BC_REPLY_SG_64: case BC_REPLY_SG_64:
/* Prepend BR_TRANSACTION_COMPLETE */ /* Prepend BR_TRANSACTION_COMPLETE */
GDEBUG("Thread %d inserting BR_TRANSACTION_COMPLETE => fd %d", GDEBUG("Thread %d inserting BR_TRANSACTION_COMPLETE before reply => "
gettid(), fd->fd); "fd %d", gettid(), fd->fd);
buf = g_realloc(buf, bytes_to_write + 4); buf = g_realloc(buf, bytes_to_write + 4);
cmd = buf + 1; cmd = buf + 1;
data = cmd + 1; data = cmd + 1;
@ -689,6 +790,8 @@ test_io_passthough_write_64(
*buf = BR_TRANSACTION_COMPLETE; *buf = BR_TRANSACTION_COMPLETE;
*cmd = BR_REPLY_64; *cmd = BR_REPLY_64;
tx = data; tx = data;
my_tx_state = test_tx_state_acquire(node, TEST_TX_STATE_ONEWAY);
GDEBUG("Reply thread %d", my_tx_state->tid);
break; break;
} }
@ -744,21 +847,21 @@ test_io_passthough_write_64(
g_hash_table_replace(fd->destroy_map, data_offsets, NULL); g_hash_table_replace(fd->destroy_map, data_offsets, NULL);
tx->data_buffer = GPOINTER_TO_SIZE(data_buffer); tx->data_buffer = GPOINTER_TO_SIZE(data_buffer);
tx->data_offsets = GPOINTER_TO_SIZE(data_offsets); tx->data_offsets = GPOINTER_TO_SIZE(data_offsets);
if (tx->flags & TF_ONE_WAY) { if ((tx->flags & TF_ONE_WAY) || is_reply) {
const guint32 c = BR_TRANSACTION_COMPLETE; const guint32 c = BR_TRANSACTION_COMPLETE;
GDEBUG("Thread %d inserting BR_TRANSACTION_COMPLETE for " GDEBUG("Thread %d inserting BR_TRANSACTION_COMPLETE for %s "
"one-way transaction => fd %d", gettid(), node->other->fd); "=> fd %d", gettid(), is_reply ? "reply" :
g_assert(!is_reply); "one-way transaction", other->fd);
g_assert(write(node->other->fd, &c, sizeof(c)) == sizeof(c)); g_assert(write(other->fd, &c, sizeof(c)) == sizeof(c));
} }
} else { } else {
const guint32 c = BR_DEAD_REPLY; const guint32 c = BR_DEAD_REPLY;
/* Fail the transaction */ /* Fail the transaction */
GDEBUG("Thread %d inserting BR_DEAD_REPLY => fd %d", gettid(), GDEBUG("Thread %d inserting BR_DEAD_REPLY => fd %d", gettid(),
node->other->fd); other->fd);
g_assert(write(node->other->fd, &c, sizeof(c)) == sizeof(c)); g_assert(write(other->fd, &c, sizeof(c)) == sizeof(c));
data = buf; data = buf;
*cmd = 0; *cmd = 0;
} }
@ -844,11 +947,11 @@ test_io_handle_write_read_64(
/* /*
* If this thread is not performing a transaction (and passthrough * If this thread is not performing a transaction (and passthrough
* mode is enabled), don't steal completion commands from other * mode is enabled), don't steal completion commands from other
* threads. * threads (but allow incoming transactions).
*/ */
const gint max_read_flags = (!binder->passthrough || const gint max_read_flags = (!binder->passthrough ||
(node_tx_state && node_tx_state == my_tx_state)) ? (node_tx_state && node_tx_state == my_tx_state)) ?
READ_FLAG_ALL : READ_FLAG_TX_OTHER; READ_FLAGS_ALL : (READ_FLAG_TX_OTHER | READ_FLAG_TX_INCOMING);
const gint looper = GPOINTER_TO_INT(g_private_get(&test_looper)); const gint looper = GPOINTER_TO_INT(g_private_get(&test_looper));
if (looper <= 0) { if (looper <= 0) {
@ -876,7 +979,6 @@ test_io_handle_write_read_64(
int nbytes = 0; int nbytes = 0;
int avail = wr->read_size - wr->read_consumed; int avail = wr->read_size - wr->read_consumed;
int total = 0; int total = 0;
gboolean transaction_complete = FALSE;
guint8* buf = GSIZE_TO_POINTER(wr->read_buffer + wr->read_consumed); guint8* buf = GSIZE_TO_POINTER(wr->read_buffer + wr->read_consumed);
guint32* cmd; guint32* cmd;
@ -884,17 +986,56 @@ test_io_handle_write_read_64(
g_assert_cmpint(nbytes, <= ,avail); g_assert_cmpint(nbytes, <= ,avail);
switch (cmd[0]) { switch (cmd[0]) {
case BR_TRANSACTION_COMPLETE: case BR_TRANSACTION_COMPLETE:
if (!node_tx_state || node_tx_state != my_tx_state || if (node_tx_state) {
!my_tx_state->one_way) { g_assert(node_tx_state == my_tx_state);
/* Still expecting BR_REPLY */ switch (test_tx_state_get(my_tx_state)) {
break; case TEST_TX_STATE_REPLY:
case TEST_TX_STATE_ONEWAY:
/* Done with the transaction */
can_read &= ~(READ_FLAG_TX_COMPLETION |
READ_FLAG_TX_INCOMING | READ_FLAG_TX_REPLY |
READ_FLAG_TX_ERROR);
test_tx_state_set(my_tx_state, TEST_TX_STATE_NONE);
break;
case TEST_TX_STATE_ACTIVE:
can_read &= ~(READ_FLAG_TX_COMPLETION |
READ_FLAG_TX_INCOMING);
test_tx_state_set(my_tx_state, TEST_TX_STATE_REPLY);
break;
case TEST_TX_STATE_NONE:
g_assert_not_reached();
break;
}
} else {
can_read &= ~(READ_FLAG_TX_COMPLETION |
READ_FLAG_TX_INCOMING | READ_FLAG_TX_REPLY |
READ_FLAG_TX_ERROR);
} }
/* fallthrough */ break;
case BR_REPLY_64:
if (node_tx_state) {
g_assert(node_tx_state == my_tx_state);
test_tx_state_set(my_tx_state, TEST_TX_STATE_NONE);
}
can_read &= ~(READ_FLAG_TX_COMPLETION |
READ_FLAG_TX_INCOMING | READ_FLAG_TX_REPLY |
READ_FLAG_TX_ERROR);
break;
case BR_FAILED_REPLY: case BR_FAILED_REPLY:
case BR_DEAD_REPLY: case BR_DEAD_REPLY:
case BR_REPLY_64: if (node_tx_state) {
can_read &= ~READ_FLAG_TX_COMPLETION; g_assert(node_tx_state == my_tx_state);
transaction_complete = TRUE; test_tx_state_set(my_tx_state, TEST_TX_STATE_NONE);
}
can_read &= ~(READ_FLAG_TX_COMPLETION |
READ_FLAG_TX_INCOMING | READ_FLAG_TX_REPLY |
READ_FLAG_TX_ERROR);
break;
case BR_TRANSACTION_64:
/* Don't swallow transaction related commands too early */
can_read &= ~(READ_FLAG_TX_COMPLETION |
READ_FLAG_TX_INCOMING | READ_FLAG_TX_REPLY |
READ_FLAG_TX_ERROR);
break; break;
} }
memcpy(buf, cmd, nbytes); memcpy(buf, cmd, nbytes);
@ -905,10 +1046,9 @@ test_io_handle_write_read_64(
g_free(cmd); g_free(cmd);
} }
if (transaction_complete && my_tx_state) { if (my_tx_state && my_tx_state == node_tx_state &&
g_assert(g_atomic_pointer_compare_and_exchange(&node->tx_state, test_tx_state_get(my_tx_state) == TEST_TX_STATE_NONE) {
my_tx_state, NULL)); test_tx_state_release(node);
GDEBUG("Thread %d done with the transaction", gettid());
} }
if (nbytes < 0) { if (nbytes < 0) {
@ -1292,7 +1432,8 @@ test_binder_node_clear(
g_hash_table_unref(test_node_map); g_hash_table_unref(test_node_map);
test_node_map = NULL; test_node_map = NULL;
if (test_binder_exit_loop) { if (test_binder_exit_loop) {
g_main_loop_quit(test_binder_exit_loop); GVERBOSE_("All nodes are gone");
test_quit_later(test_binder_exit_loop);
} }
} }
close(node->fd); close(node->fd);
@ -1343,21 +1484,41 @@ test_binder_handle(
GBinderLocalObject* obj) GBinderLocalObject* obj)
{ {
TestBinder* binder = test_binder_from_fd(fd); TestBinder* binder = test_binder_from_fd(fd);
gpointer key = GSIZE_TO_POINTER(obj);
int h = -1; int h = -1;
g_assert(binder); g_assert(binder);
g_assert(obj); g_assert(obj);
G_LOCK(test_binder); G_LOCK(test_binder);
if (g_hash_table_contains(binder->object_map, key)) { if (g_hash_table_contains(binder->object_map, obj)) {
h = GPOINTER_TO_INT(g_hash_table_lookup(binder->object_map, key)); h = GPOINTER_TO_INT(g_hash_table_lookup(binder->object_map, obj));
} }
G_UNLOCK(test_binder); G_UNLOCK(test_binder);
return h; return h;
} }
GBinderLocalObject*
test_binder_object(
int fd,
guint handle)
{
TestBinder* binder = test_binder_from_fd(fd);
gpointer key = GSIZE_TO_POINTER(handle);
GBinderLocalObject* obj = NULL;
g_assert(binder);
G_LOCK(test_binder);
if (g_hash_table_contains(binder->handle_map, key)) {
obj = gbinder_local_object_ref
(g_hash_table_lookup(binder->handle_map, key));
}
G_UNLOCK(test_binder);
return obj;
}
guint guint
test_binder_register_object( test_binder_register_object(
int fd, int fd,
@ -1381,11 +1542,17 @@ test_binder_unregister_objects(
int fd) int fd)
{ {
TestBinder* binder; TestBinder* binder;
GHashTableIter it;
gpointer handle, obj;
G_LOCK(test_binder); G_LOCK(test_binder);
binder = test_binder_from_fd_locked(fd); binder = test_binder_from_fd_locked(fd);
g_hash_table_remove_all(binder->object_map); g_hash_table_iter_init(&it, binder->handle_map);
g_hash_table_remove_all(binder->handle_map); while (g_hash_table_iter_next(&it, &handle, &obj)) {
test_binder_object_dead_locked(binder, GPOINTER_TO_SIZE(handle));
g_hash_table_remove(binder->object_map, obj);
g_hash_table_iter_remove(&it);
}
G_UNLOCK(test_binder); G_UNLOCK(test_binder);
} }

View File

@ -134,6 +134,12 @@ test_binder_handle(
int fd, int fd,
GBinderLocalObject* obj); GBinderLocalObject* obj);
GBinderLocalObject*
test_binder_object(
int fd,
guint handle)
G_GNUC_WARN_UNUSED_RESULT; /* Need to unref */
guint guint
test_binder_register_object( test_binder_register_object(
int fd, int fd,

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -64,6 +64,17 @@ test_quit_later_n(
GMainLoop* loop, GMainLoop* loop,
guint n); guint n);
/*
* Makes sure that we own the context for the entire duration of the test.
* That prevents many race conditions - all callbacks that are supposed to
* be invoked on the main thread, are actually invoked on the main thread
* (rather than a random worker thread which happens to acquire the context).
*/
void
test_run_in_context(
const TestOpt* opt,
GTestFunc func);
#define TEST_TIMEOUT_SEC (20) #define TEST_TIMEOUT_SEC (20)
/* Helper macros */ /* Helper macros */

View File

@ -39,6 +39,11 @@ typedef struct test_quit_later_data{
guint n; guint n;
} TestQuitLaterData; } TestQuitLaterData;
typedef struct test_context_data{
GMainLoop* loop;
GTestFunc func;
} TestContextData;
static static
gboolean gboolean
test_timeout_expired( test_timeout_expired(
@ -104,6 +109,40 @@ test_quit_later(
g_idle_add(test_quit_later_cb, loop); g_idle_add(test_quit_later_cb, loop);
} }
static
gboolean
test_run_in_context_cb(
gpointer data)
{
TestContextData* test = data;
test->func();
g_main_loop_quit(test->loop);
return G_SOURCE_REMOVE;
}
void
test_run_in_context(
const TestOpt* opt,
GTestFunc func)
{
TestContextData test;
test.loop = g_main_loop_new(NULL, FALSE);
test.func = func;
/*
* This makes sure that we own the context for the entire duration
* of the test. That prevents many race conditions - all callbacks
* that are supposed to be invoked on the main thread, are actually
* invoked on the main thread (rather than a random worker thread
* which happens to acquire the context).
*/
g_idle_add(test_run_in_context_cb, &test);
test_run(opt, test.loop);
g_main_loop_unref(test.loop);
}
void void
test_run( test_run(
const TestOpt* opt, const TestOpt* opt,

View File

@ -315,9 +315,21 @@ test_basic_reply(
} }
static static
gboolean void
test_basic_death(
GBinderRemoteObject* obj,
void* loop)
{
GDEBUG("Source object died");
/* Exit the loop */
g_main_loop_quit((GMainLoop*)loop);
}
static
void
test_basic_run( test_basic_run(
gpointer main_loop) void)
{ {
TestBasic test; TestBasic test;
TestConfig config; TestConfig config;
@ -330,12 +342,13 @@ test_basic_run(
GBinderIpc* dest_priv_ipc; GBinderIpc* dest_priv_ipc;
GBinderBridge* bridge; GBinderBridge* bridge;
TestLocalObject* obj; TestLocalObject* obj;
GBinderRemoteObject* br_src_obj;
GBinderRemoteObject* src_obj; GBinderRemoteObject* src_obj;
GBinderLocalRequest* req; GBinderLocalRequest* req;
GBinderClient* src_client; GBinderClient* src_client;
const char* name = "test"; const char* name = "test";
const char* fqname = TEST_IFACE "/test"; const char* fqname = TEST_IFACE "/test";
int src_fd, dest_fd, n = 0; int src_fd, dest_fd, h, n = 0;
gulong id; gulong id;
test_config_init(&config, NULL); test_config_init(&config, NULL);
@ -384,9 +397,9 @@ test_basic_run(
gbinder_servicemanager_remove_handler(src, id); gbinder_servicemanager_remove_handler(src, id);
/* Get a remote reference to the object created by the bridge */ /* Get a remote reference to the object created by the bridge */
src_obj = gbinder_servicemanager_get_service_sync(src, fqname, NULL); br_src_obj = gbinder_servicemanager_get_service_sync(src, fqname, NULL);
g_assert(src_obj); /* autoreleased */ g_assert(gbinder_remote_object_ref(br_src_obj)); /* autoreleased */
g_assert(!src_obj->dead); g_assert(!br_src_obj->dead);
/* /*
* This is a trick specific to test_binder simulation. We need to * This is a trick specific to test_binder simulation. We need to
@ -398,7 +411,8 @@ test_basic_run(
* Note that the original src_obj gets autoreleased and doesn't need * Note that the original src_obj gets autoreleased and doesn't need
* to be explicitly unreferenced. * to be explicitly unreferenced.
*/ */
src_obj = gbinder_remote_object_new(src_priv_ipc, src_obj->handle, FALSE); src_obj = gbinder_remote_object_new(src_priv_ipc,
br_src_obj->handle, REMOTE_OBJECT_CREATE_ALIVE);
/* Make a call */ /* Make a call */
GDEBUG("Submitting a call"); GDEBUG("Submitting a call");
@ -412,11 +426,27 @@ test_basic_run(
/* Wait for completion */ /* Wait for completion */
test_run(&test_opt, test.loop); test_run(&test_opt, test.loop);
/* Kill the destination object and wait for auto-created object to die */
g_assert(!br_src_obj->dead);
id = gbinder_remote_object_add_death_handler(br_src_obj, test_basic_death,
test.loop);
h = test_binder_handle(dest_fd, &obj->parent);
g_assert_cmpint(h, > ,0); /* Zero is servicemanager */
GDEBUG("Killing destination object, handle %d", h);
gbinder_local_object_drop(&obj->parent);
test_binder_br_dead_binder(dest_fd, h);
/* Wait for the auto-created object to die */
test_run(&test_opt, test.loop);
g_assert(br_src_obj->dead);
gbinder_remote_object_remove_handler(br_src_obj, id);
GDEBUG("Done"); GDEBUG("Done");
gbinder_bridge_free(bridge); gbinder_bridge_free(bridge);
gbinder_local_object_unref(&obj->parent);
gbinder_remote_object_unref(src_obj); gbinder_remote_object_unref(src_obj);
gbinder_remote_object_unref(br_src_obj);
test_servicemanager_hidl_free(test.src_impl); test_servicemanager_hidl_free(test.src_impl);
test_servicemanager_hidl_free(dest_impl); test_servicemanager_hidl_free(dest_impl);
gbinder_servicemanager_unref(src); gbinder_servicemanager_unref(src);
@ -433,10 +463,6 @@ test_basic_run(
test_binder_exit_wait(&test_opt, test.loop); test_binder_exit_wait(&test_opt, test.loop);
test_config_deinit(&config); test_config_deinit(&config);
g_main_loop_unref(test.loop); g_main_loop_unref(test.loop);
/* And exit the test loop */
g_main_loop_quit((GMainLoop*)main_loop);
return G_SOURCE_REMOVE;
} }
static static
@ -444,18 +470,7 @@ void
test_basic( test_basic(
void) void)
{ {
GMainLoop* loop = g_main_loop_new(NULL, FALSE); test_run_in_context(&test_opt, test_basic_run);
/*
* This makes sure that we own the context for the entire duration
* of the test. That prevents many race conditions - all callbacks
* that are supposed to be invoked on the main thread, are actually
* invoked on the main thread (rather than a worker thread which
* happens to acquire the context).
*/
g_idle_add(test_basic_run, loop);
test_run(&test_opt, loop);
g_main_loop_unref(loop);
} }
/*==========================================================================* /*==========================================================================*

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -14,8 +14,8 @@
* 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 names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software 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
@ -68,15 +68,47 @@ test_null(
gbinder_buffer_free(buf2); gbinder_buffer_free(buf2);
gbinder_buffer_free(NULL); gbinder_buffer_free(NULL);
gbinder_buffer_contents_list_free(NULL);
g_assert(!gbinder_buffer_driver(NULL)); g_assert(!gbinder_buffer_driver(NULL));
g_assert(!gbinder_buffer_objects(NULL)); g_assert(!gbinder_buffer_objects(NULL));
g_assert(!gbinder_buffer_io(NULL)); g_assert(!gbinder_buffer_io(NULL));
g_assert(!gbinder_buffer_data(NULL, NULL)); g_assert(!gbinder_buffer_data(NULL, NULL));
g_assert(!gbinder_buffer_data(NULL, &size)); g_assert(!gbinder_buffer_data(NULL, &size));
g_assert(!gbinder_buffer_contents(NULL));
g_assert(!gbinder_buffer_contents_list_add(NULL, NULL));
g_assert(!gbinder_buffer_contents_list_dup(NULL));
g_assert(!size); g_assert(!size);
gbinder_driver_unref(driver); gbinder_driver_unref(driver);
} }
/*==========================================================================*
* list
*==========================================================================*/
static
void
test_list(
void)
{
static const guint8 data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
void* ptr = g_memdup(data, sizeof(data));
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(driver, ptr, sizeof(data), NULL);
GBinderBufferContents* contents = gbinder_buffer_contents(buf);
GBinderBufferContentsList* list = gbinder_buffer_contents_list_add
(NULL, contents);
GBinderBufferContentsList* list2 = gbinder_buffer_contents_list_dup(list);
g_assert(contents);
g_assert(list);
g_assert(list2);
gbinder_buffer_free(buf);
gbinder_buffer_contents_list_free(list);
gbinder_buffer_contents_list_free(list2);
gbinder_driver_unref(driver);
}
/*==========================================================================* /*==========================================================================*
* parent * parent
*==========================================================================*/ *==========================================================================*/
@ -112,12 +144,14 @@ test_parent(
*==========================================================================*/ *==========================================================================*/
#define TEST_PREFIX "/buffer/" #define TEST_PREFIX "/buffer/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "null", test_null); g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_PREFIX "parent", test_parent); g_test_add_func(TEST_("list"), test_list);
g_test_add_func(TEST_("parent"), test_parent);
test_init(&test_opt, argc, argv); test_init(&test_opt, argc, argv);
return g_test_run(); return g_test_run();
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -51,12 +51,12 @@ static TestOpt test_opt;
static static
GBinderClient* GBinderClient*
test_client_new( test_client_new(
guint handle, guint h,
const char* iface) const char* iface)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, handle); GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, h, TRUE);
GBinderClient* client = gbinder_client_new(obj, iface); GBinderClient* client = gbinder_client_new(obj, iface);
g_assert(client); g_assert(client);
@ -99,7 +99,7 @@ test_basic(
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0); GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0, TRUE);
const char* iface = "foo"; const char* iface = "foo";
GBinderClient* client = gbinder_client_new(obj, iface); GBinderClient* client = gbinder_client_new(obj, iface);
@ -125,7 +125,7 @@ test_interfaces(
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0); GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0, TRUE);
static const GBinderClientIfaceInfo ifaces[] = { static const GBinderClientIfaceInfo ifaces[] = {
{"33", 33 }, { "11", 11 }, { "22", 22 } {"33", 33 }, { "11", 11 }, { "22", 22 }
}; };
@ -198,7 +198,7 @@ test_dead(
gbinder_remote_object_add_death_handler(obj, test_dead_done, loop); gbinder_remote_object_add_death_handler(obj, test_dead_done, loop);
test_binder_br_dead_binder(fd, handle); test_binder_br_dead_binder(fd, handle);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
g_assert(gbinder_remote_object_is_dead(obj)); g_assert(gbinder_remote_object_is_dead(obj));
@ -207,8 +207,9 @@ test_dead(
g_assert(!gbinder_client_transact(client, 0, 0, NULL, NULL, NULL, NULL)); g_assert(!gbinder_client_transact(client, 0, 0, NULL, NULL, NULL, NULL));
gbinder_client_unref(client); gbinder_client_unref(client);
g_main_loop_unref(loop);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
} }
/*==========================================================================* /*==========================================================================*

View File

@ -76,6 +76,7 @@ test_basic(
g_assert(gbinder_driver_exit_looper(driver)); g_assert(gbinder_driver_exit_looper(driver));
g_assert(!gbinder_driver_request_death_notification(driver, NULL)); g_assert(!gbinder_driver_request_death_notification(driver, NULL));
g_assert(!gbinder_driver_clear_death_notification(driver, NULL)); g_assert(!gbinder_driver_clear_death_notification(driver, NULL));
g_assert(!gbinder_driver_dead_binder_done(NULL, NULL));
gbinder_driver_unref(driver); gbinder_driver_unref(driver);
g_assert(!gbinder_handler_transact(NULL, NULL, NULL, 0, 0, NULL)); g_assert(!gbinder_handler_transact(NULL, NULL, NULL, 0, 0, NULL));

View File

@ -103,13 +103,23 @@ test_null(
g_assert(!gbinder_object_registry_ref(NULL)); g_assert(!gbinder_object_registry_ref(NULL));
gbinder_object_registry_unref(NULL); gbinder_object_registry_unref(NULL);
g_assert(!gbinder_object_registry_get_local(NULL, NULL)); g_assert(!gbinder_object_registry_get_local(NULL, NULL));
g_assert(!gbinder_object_registry_get_remote(NULL, 0)); g_assert(!gbinder_object_registry_get_remote(NULL, 0, FALSE));
g_assert(!gbinder_ipc_find_local_object(NULL, NULL, NULL));
} }
/*==========================================================================* /*==========================================================================*
* basic * basic
*==========================================================================*/ *==========================================================================*/
static
gboolean
test_basic_find_none(
GBinderLocalObject* obj,
void* user_data)
{
return FALSE;
}
static static
void void
test_basic( test_basic(
@ -124,6 +134,9 @@ test_basic(
gbinder_ipc_cancel(ipc2, 0); /* not a valid transaction */ gbinder_ipc_cancel(ipc2, 0); /* not a valid transaction */
gbinder_ipc_unref(ipc2); gbinder_ipc_unref(ipc2);
g_assert(!gbinder_ipc_find_local_object(NULL, test_basic_find_none, NULL));
g_assert(!gbinder_ipc_find_local_object(ipc, test_basic_find_none, NULL));
/* Second gbinder_ipc_new returns the same (default) object */ /* Second gbinder_ipc_new returns the same (default) object */
g_assert(gbinder_ipc_new(NULL) == ipc); g_assert(gbinder_ipc_new(NULL) == ipc);
g_assert(gbinder_ipc_new("") == ipc); g_assert(gbinder_ipc_new("") == ipc);
@ -272,7 +285,8 @@ test_sync_reply_error(
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL); GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
const guint32 handle = 0; const guint32 handle = 0;
const guint32 code = 1; const guint32 code = 1;
const gint expected_status = GBINDER_STATUS_FAILED; const gint expected_status = (-EINVAL);
const gint unexpected_status = GBINDER_STATUS_FAILED;
int status = INT_MAX; int status = INT_MAX;
test_binder_br_noop(fd); test_binder_br_noop(fd);
@ -281,7 +295,16 @@ test_sync_reply_error(
test_binder_br_reply_status(fd, expected_status); test_binder_br_reply_status(fd, expected_status);
g_assert(!gbinder_ipc_sync_main.sync_reply(ipc,handle,code,req,&status)); g_assert(!gbinder_ipc_sync_main.sync_reply(ipc,handle,code,req,&status));
g_assert(status == expected_status); g_assert_cmpint(status, == ,expected_status);
/* GBINDER_STATUS_FAILED gets replaced with -EFAULT */
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply_status(fd, unexpected_status);
g_assert(!gbinder_ipc_sync_main.sync_reply(ipc,handle,code,req,&status));
g_assert_cmpint(status, == ,-EFAULT);
gbinder_local_request_unref(req); gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
@ -790,6 +813,58 @@ test_transact_2way(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
/*==========================================================================*
* transact_unhandled
*==========================================================================*/
static
void
test_transact_unhandled_done(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
g_assert(!reply);
g_assert_cmpint(status, == ,GBINDER_STATUS_DEAD_OBJECT);
test_quit_later((GMainLoop*)user_data);
}
static
void
test_transact_unhandled_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderDriver* driver = ipc->driver;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalRequest* req = gbinder_driver_local_request_new_ping(driver);
int fd = gbinder_driver_fd(driver);
test_binder_set_passthrough(fd, TRUE);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
g_assert(gbinder_ipc_transact(ipc, 1 /* Non-existent object */,
gbinder_driver_protocol(driver)->ping_tx, 0, req,
test_transact_unhandled_done, NULL, loop));
gbinder_local_request_unref(req);
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
static
void
test_transact_unhandled(
void)
{
test_run_in_context(&test_opt, test_transact_unhandled_run);
}
/*==========================================================================* /*==========================================================================*
* transact_incoming * transact_incoming
*==========================================================================*/ *==========================================================================*/
@ -819,7 +894,7 @@ test_transact_incoming_proc(
static static
void void
test_transact_incoming( test_transact_incoming_run(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
@ -844,9 +919,11 @@ test_transact_incoming(
test_binder_br_transaction(fd, obj, prot->ping_tx, test_binder_br_transaction(fd, obj, prot->ping_tx,
gbinder_local_request_data(ping)->bytes); gbinder_local_request_data(ping)->bytes);
test_binder_br_transaction_complete(fd); /* For reply */
test_binder_br_transaction(fd, obj, 1, test_binder_br_transaction(fd, obj, 1,
gbinder_local_request_data(req)->bytes); gbinder_local_request_data(req)->bytes);
test_binder_set_looper_enabled(fd, TRUE); test_binder_br_transaction_complete(fd); /* For reply */
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */ /* Now we need to wait until GBinderIpc is destroyed */
@ -863,6 +940,14 @@ test_transact_incoming(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_transact_incoming(
void)
{
test_run_in_context(&test_opt, test_transact_incoming_run);
}
/*==========================================================================* /*==========================================================================*
* transact_status_reply * transact_status_reply
*==========================================================================*/ *==========================================================================*/
@ -890,7 +975,7 @@ test_transact_status_reply_proc(
static static
void void
test_transact_status_reply( test_transact_status_reply_run(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
@ -912,7 +997,8 @@ test_transact_status_reply(
data = gbinder_local_request_data(req); data = gbinder_local_request_data(req);
test_binder_br_transaction(fd, obj, 1, data->bytes); test_binder_br_transaction(fd, obj, 1, data->bytes);
test_binder_set_looper_enabled(fd, TRUE); test_binder_br_transaction_complete(fd); /* For reply */
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE_ONE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */ /* Now we need to wait until GBinderIpc is destroyed */
@ -928,6 +1014,14 @@ test_transact_status_reply(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_transact_status_reply(
void)
{
test_run_in_context(&test_opt, test_transact_status_reply_run);
}
/*==========================================================================* /*==========================================================================*
* transact_async * transact_async
*==========================================================================*/ *==========================================================================*/
@ -998,7 +1092,7 @@ test_transact_async_proc(
static static
void void
test_transact_async( test_transact_async_run(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
@ -1020,7 +1114,8 @@ test_transact_async(
data = gbinder_local_request_data(req); data = gbinder_local_request_data(req);
test_binder_br_transaction(fd, obj, 1, data->bytes); test_binder_br_transaction(fd, obj, 1, data->bytes);
test_binder_set_looper_enabled(fd, TRUE); test_binder_br_transaction_complete(fd); /* For reply */
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE_ONE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */ /* Now we need to wait until GBinderIpc is destroyed */
@ -1036,6 +1131,14 @@ test_transact_async(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_transact_async(
void)
{
test_run_in_context(&test_opt, test_transact_async_run);
}
/*==========================================================================* /*==========================================================================*
* transact_async_sync * transact_async_sync
*==========================================================================*/ *==========================================================================*/
@ -1072,7 +1175,7 @@ test_transact_async_sync_proc(
static static
void void
test_transact_async_sync( test_transact_async_sync_run(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
@ -1094,7 +1197,8 @@ test_transact_async_sync(
data = gbinder_local_request_data(req); data = gbinder_local_request_data(req);
test_binder_br_transaction(fd, obj, 1, data->bytes); test_binder_br_transaction(fd, obj, 1, data->bytes);
test_binder_set_looper_enabled(fd, TRUE); test_binder_br_transaction_complete(fd); /* For reply */
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE_ONE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */ /* Now we need to wait until GBinderIpc is destroyed */
@ -1110,6 +1214,14 @@ test_transact_async_sync(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_transact_async_sync(
void)
{
test_run_in_context(&test_opt, test_transact_async_sync_run);
}
/*==========================================================================* /*==========================================================================*
* drop_remote_refs * drop_remote_refs
*==========================================================================*/ *==========================================================================*/
@ -1127,7 +1239,7 @@ test_drop_remote_refs_cb(
static static
void void
test_drop_remote_refs( test_drop_remote_refs_run(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
@ -1139,7 +1251,7 @@ test_drop_remote_refs(
test_drop_remote_refs_cb, loop); test_drop_remote_refs_cb, loop);
test_binder_br_acquire(fd, obj); test_binder_br_acquire(fd, obj);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
g_assert(obj->strong_refs == 1); g_assert(obj->strong_refs == 1);
@ -1153,6 +1265,14 @@ test_drop_remote_refs(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_drop_remote_refs(
void)
{
test_run_in_context(&test_opt, test_drop_remote_refs_run);
}
/*==========================================================================* /*==========================================================================*
* cancel_on_exit * cancel_on_exit
*==========================================================================*/ *==========================================================================*/
@ -1218,6 +1338,7 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_("transact_cancel2"), test_transact_cancel2); g_test_add_func(TEST_("transact_cancel2"), test_transact_cancel2);
g_test_add_func(TEST_("transact_2way"), test_transact_2way); g_test_add_func(TEST_("transact_2way"), test_transact_2way);
g_test_add_func(TEST_("transact_incoming"), test_transact_incoming); g_test_add_func(TEST_("transact_incoming"), test_transact_incoming);
g_test_add_func(TEST_("transact_unhandled"), test_transact_unhandled);
g_test_add_func(TEST_("transact_status_reply"), test_transact_status_reply); g_test_add_func(TEST_("transact_status_reply"), test_transact_status_reply);
g_test_add_func(TEST_("transact_async"), test_transact_async); g_test_add_func(TEST_("transact_async"), test_transact_async);
g_test_add_func(TEST_("transact_async_sync"), test_transact_async_sync); g_test_add_func(TEST_("transact_async_sync"), test_transact_async_sync);

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -137,7 +137,7 @@ test_null(
g_assert(!gbinder_ipc_transact_custom(NULL, NULL, NULL, NULL, NULL)); g_assert(!gbinder_ipc_transact_custom(NULL, NULL, NULL, NULL, NULL));
gbinder_local_object_handle_increfs(NULL); gbinder_local_object_handle_increfs(NULL);
gbinder_local_object_handle_decrefs(NULL); gbinder_local_object_handle_decrefs(NULL);
gbinder_local_object_handle_acquire(NULL); gbinder_local_object_handle_acquire(NULL, NULL);
gbinder_local_object_handle_release(NULL); gbinder_local_object_handle_release(NULL);
} }
@ -179,7 +179,7 @@ test_basic(
base_interface, -1) == GBINDER_LOCAL_TRANSACTION_NOT_SUPPORTED); base_interface, -1) == GBINDER_LOCAL_TRANSACTION_NOT_SUPPORTED);
gbinder_local_object_handle_increfs(foo); gbinder_local_object_handle_increfs(foo);
gbinder_local_object_handle_decrefs(foo); gbinder_local_object_handle_decrefs(foo);
gbinder_local_object_handle_acquire(foo); gbinder_local_object_handle_acquire(foo, NULL);
gbinder_local_object_handle_release(foo); gbinder_local_object_handle_release(foo);
gbinder_local_object_unref(foo); gbinder_local_object_unref(foo);
@ -621,7 +621,7 @@ test_increfs_cb(
static static
void void
test_increfs( test_increfs_run(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
@ -635,7 +635,7 @@ test_increfs(
/* ipc is not an object, will be ignored */ /* ipc is not an object, will be ignored */
test_binder_br_increfs(fd, ipc); test_binder_br_increfs(fd, ipc);
test_binder_br_increfs(fd, obj); test_binder_br_increfs(fd, obj);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
g_assert(obj->weak_refs == 1); g_assert(obj->weak_refs == 1);
@ -646,6 +646,14 @@ test_increfs(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_increfs(
void)
{
test_run_in_context(&test_opt, test_increfs_run);
}
/*==========================================================================* /*==========================================================================*
* decrefs * decrefs
*==========================================================================*/ *==========================================================================*/
@ -664,7 +672,7 @@ test_decrefs_cb(
static static
void void
test_decrefs( test_decrefs_run(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
@ -679,7 +687,7 @@ test_decrefs(
test_binder_br_decrefs(fd, ipc); test_binder_br_decrefs(fd, ipc);
test_binder_br_increfs(fd, obj); test_binder_br_increfs(fd, obj);
test_binder_br_decrefs(fd, obj); test_binder_br_decrefs(fd, obj);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
g_assert(obj->weak_refs == 0); g_assert(obj->weak_refs == 0);
@ -690,6 +698,14 @@ test_decrefs(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_decrefs(
void)
{
test_run_in_context(&test_opt, test_decrefs_run);
}
/*==========================================================================* /*==========================================================================*
* acquire * acquire
*==========================================================================*/ *==========================================================================*/
@ -707,7 +723,7 @@ test_acquire_cb(
static static
void void
test_acquire( test_acquire_run(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
@ -721,7 +737,7 @@ test_acquire(
/* ipc is not an object, will be ignored */ /* ipc is not an object, will be ignored */
test_binder_br_acquire(fd, ipc); test_binder_br_acquire(fd, ipc);
test_binder_br_acquire(fd, obj); test_binder_br_acquire(fd, obj);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
g_assert(obj->strong_refs == 1); g_assert(obj->strong_refs == 1);
@ -732,6 +748,14 @@ test_acquire(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_acquire(
void)
{
test_run_in_context(&test_opt, test_acquire_run);
}
/*==========================================================================* /*==========================================================================*
* release * release
*==========================================================================*/ *==========================================================================*/
@ -750,7 +774,7 @@ test_release_cb(
static static
void void
test_release( test_release_run(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
@ -764,7 +788,7 @@ test_release(
test_binder_br_release(fd, ipc); test_binder_br_release(fd, ipc);
test_binder_br_acquire(fd, obj); test_binder_br_acquire(fd, obj);
test_binder_br_release(fd, obj); test_binder_br_release(fd, obj);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
g_assert(obj->strong_refs == 0); g_assert(obj->strong_refs == 0);
@ -775,6 +799,14 @@ test_release(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_release(
void)
{
test_run_in_context(&test_opt, test_release_run);
}
/*==========================================================================* /*==========================================================================*
* Common * Common
*==========================================================================*/ *==========================================================================*/

View File

@ -88,7 +88,8 @@ test_null(
gbinder_local_reply_init_writer(NULL, NULL); gbinder_local_reply_init_writer(NULL, NULL);
gbinder_local_reply_init_writer(NULL, &writer); gbinder_local_reply_init_writer(NULL, &writer);
g_assert(!gbinder_local_reply_data(NULL)); g_assert(!gbinder_local_reply_data(NULL));
g_assert(!gbinder_local_reply_set_contents(NULL, NULL)); g_assert(!gbinder_local_reply_contents(NULL));
g_assert(!gbinder_local_reply_set_contents(NULL, NULL, NULL));
gbinder_local_reply_cleanup(NULL, NULL, &count); gbinder_local_reply_cleanup(NULL, NULL, &count);
gbinder_local_reply_cleanup(NULL, test_int_inc, &count); gbinder_local_reply_cleanup(NULL, test_int_inc, &count);
@ -480,7 +481,7 @@ test_remote_reply(
/* Copy flat structures (no binder objects) */ /* Copy flat structures (no binder objects) */
buffer = test_buffer_from_bytes(driver, bytes); buffer = test_buffer_from_bytes(driver, bytes);
req2 = gbinder_local_reply_new(io); req2 = gbinder_local_reply_new(io);
g_assert(gbinder_local_reply_set_contents(req2, buffer) == req2); g_assert(gbinder_local_reply_set_contents(req2, buffer, NULL) == req2);
gbinder_buffer_free(buffer); gbinder_buffer_free(buffer);
data2 = gbinder_local_reply_data(req2); data2 = gbinder_local_reply_data(req2);

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -94,7 +94,7 @@ test_null(
g_assert(!gbinder_local_request_new(NULL, NULL)); g_assert(!gbinder_local_request_new(NULL, NULL));
g_assert(!gbinder_local_request_ref(NULL)); g_assert(!gbinder_local_request_ref(NULL));
g_assert(!gbinder_local_request_new_from_data(NULL)); g_assert(!gbinder_local_request_new_from_data(NULL, NULL));
gbinder_local_request_unref(NULL); gbinder_local_request_unref(NULL);
gbinder_local_request_init_writer(NULL, NULL); gbinder_local_request_init_writer(NULL, NULL);
gbinder_local_request_init_writer(NULL, &writer); gbinder_local_request_init_writer(NULL, &writer);
@ -490,7 +490,7 @@ test_remote_request(
/* Copy flat structures (no binder objects) */ /* Copy flat structures (no binder objects) */
buffer = test_buffer_from_bytes(driver, bytes); buffer = test_buffer_from_bytes(driver, bytes);
req2 = gbinder_local_request_new_from_data(buffer); req2 = gbinder_local_request_new_from_data(buffer, NULL);
gbinder_buffer_free(buffer); gbinder_buffer_free(buffer);
data2 = gbinder_local_request_data(req2); data2 = gbinder_local_request_data(req2);
@ -503,7 +503,7 @@ test_remote_request(
/* Same thing but with non-NULL (albeit empty) array of objects */ /* Same thing but with non-NULL (albeit empty) array of objects */
buffer = test_buffer_from_bytes_and_objects(driver, bytes, no_obj); buffer = test_buffer_from_bytes_and_objects(driver, bytes, no_obj);
req2 = gbinder_local_request_new_from_data(buffer); req2 = gbinder_local_request_new_from_data(buffer, NULL);
gbinder_buffer_free(buffer); gbinder_buffer_free(buffer);
data2 = gbinder_local_request_data(req2); data2 = gbinder_local_request_data(req2);
@ -572,7 +572,7 @@ test_remote_request_obj(
} }
buffer = test_buffer_from_bytes_and_objects(driver, data->bytes, objects); buffer = test_buffer_from_bytes_and_objects(driver, data->bytes, objects);
req2 = gbinder_local_request_new_from_data(buffer); req2 = gbinder_local_request_new_from_data(buffer, NULL);
gbinder_buffer_free(buffer); gbinder_buffer_free(buffer);
test_remote_request_obj_validate_data(gbinder_local_request_data(req2)); test_remote_request_obj_validate_data(gbinder_local_request_data(req2));

View File

@ -54,14 +54,25 @@ static TestOpt test_opt;
#define DEV2 "/dev/ybinder" #define DEV2 "/dev/ybinder"
#define DEV2_PRIV DEV2 "-private" #define DEV2_PRIV DEV2 "-private"
#define TX_CODE (GBINDER_FIRST_CALL_TRANSACTION + 1) enum test_tx_codes {
#define TX_PARAM_REPLY 0x11111111 TX_CODE = GBINDER_FIRST_CALL_TRANSACTION,
#define TX_PARAM_DONT_REPLY 0x22222222 TX_CODE2,
#define TX_RESULT 0x33333333 TX_CODE3
};
#define TX_PARAM1 0x11111111
#define TX_PARAM2 0x22222222
#define TX_PARAM3 0x33333333
#define TX_RESULT1 0x01010101
#define TX_RESULT2 0x02020202
#define TX_PARAM_REPLY 0x11110000
#define TX_PARAM_DONT_REPLY 0x22220000
#define TX_RESULT 0x03030303
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-proxy-XXXXXX"; static const char TMP_DIR_TEMPLATE[] = "gbinder-test-proxy-XXXXXX";
const char TEST_IFACE[] = "test@1.0::ITest"; const char TEST_IFACE[] = "test@1.0::ITest";
const char TEST_IFACE2[] = "test@1.0::ITest2";
static const char* TEST_IFACES[] = { TEST_IFACE, NULL }; static const char* TEST_IFACES[] = { TEST_IFACE, NULL };
static const char* TEST_IFACES2[] = { TEST_IFACE2, NULL };
static const char DEFAULT_CONFIG_DATA[] = static const char DEFAULT_CONFIG_DATA[] =
"[Protocol]\n" "[Protocol]\n"
"Default = hidl\n" "Default = hidl\n"
@ -172,7 +183,7 @@ test_basic_reply(
static static
void void
test_basic( test_basic_run(
void) void)
{ {
TestConfig config; TestConfig config;
@ -193,14 +204,15 @@ test_basic(
fd_obj = gbinder_driver_fd(ipc_obj->driver); fd_obj = gbinder_driver_fd(ipc_obj->driver);
obj = gbinder_local_object_new(ipc_obj, TEST_IFACES, test_basic_cb, &n); obj = gbinder_local_object_new(ipc_obj, TEST_IFACES, test_basic_cb, &n);
remote_obj = gbinder_remote_object_new(ipc_proxy, remote_obj = gbinder_remote_object_new(ipc_proxy,
test_binder_register_object(fd_obj, obj, AUTO_HANDLE), FALSE); test_binder_register_object(fd_obj, obj, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
/* remote_proxy(DEV_PRIV) => proxy (DEV) => obj (DEV) => DEV_PRIV */ /* remote_proxy(DEV_PRIV) => proxy (DEV) => obj (DEV) => DEV_PRIV */
g_assert(!gbinder_proxy_object_new(NULL, remote_obj)); g_assert(!gbinder_proxy_object_new(NULL, remote_obj));
g_assert((proxy = gbinder_proxy_object_new(ipc_proxy, remote_obj))); g_assert((proxy = gbinder_proxy_object_new(ipc_proxy, remote_obj)));
remote_proxy = gbinder_remote_object_new(ipc_obj, remote_proxy = gbinder_remote_object_new(ipc_obj,
test_binder_register_object(fd_proxy, &proxy->parent, AUTO_HANDLE), test_binder_register_object(fd_proxy, &proxy->parent, AUTO_HANDLE),
FALSE); REMOTE_OBJECT_CREATE_ALIVE);
proxy_client = gbinder_client_new(remote_proxy, TEST_IFACE); proxy_client = gbinder_client_new(remote_proxy, TEST_IFACE);
test_binder_set_passthrough(fd_obj, TRUE); test_binder_set_passthrough(fd_obj, TRUE);
@ -230,6 +242,14 @@ test_basic(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_basic(
void)
{
test_run_in_context(&test_opt, test_basic_run);
}
/*==========================================================================* /*==========================================================================*
* param * param
*==========================================================================*/ *==========================================================================*/
@ -324,7 +344,7 @@ test_param_reply(
static static
void void
test_param( test_param_run(
void) void)
{ {
TestConfig config; TestConfig config;
@ -350,14 +370,15 @@ test_param(
fd_obj = gbinder_driver_fd(ipc_obj->driver); fd_obj = gbinder_driver_fd(ipc_obj->driver);
obj = gbinder_local_object_new(ipc_obj, TEST_IFACES, test_param_cb, &n); obj = gbinder_local_object_new(ipc_obj, TEST_IFACES, test_param_cb, &n);
remote_obj = gbinder_remote_object_new(ipc_remote_obj, remote_obj = gbinder_remote_object_new(ipc_remote_obj,
test_binder_register_object(fd_obj, obj, AUTO_HANDLE), FALSE); test_binder_register_object(fd_obj, obj, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
/* remote_proxy(DEV2_PRIV) => proxy (DEV2) => obj (DEV) => DEV_PRIV */ /* remote_proxy(DEV2_PRIV) => proxy (DEV2) => obj (DEV) => DEV_PRIV */
g_assert(!gbinder_proxy_object_new(NULL, remote_obj)); g_assert(!gbinder_proxy_object_new(NULL, remote_obj));
g_assert((proxy = gbinder_proxy_object_new(ipc_proxy, remote_obj))); g_assert((proxy = gbinder_proxy_object_new(ipc_proxy, remote_obj)));
remote_proxy = gbinder_remote_object_new(ipc_remote_proxy, remote_proxy = gbinder_remote_object_new(ipc_remote_proxy,
test_binder_register_object(fd_proxy, &proxy->parent, AUTO_HANDLE), test_binder_register_object(fd_proxy, &proxy->parent, AUTO_HANDLE),
FALSE); REMOTE_OBJECT_CREATE_ALIVE);
proxy_client = gbinder_client_new(remote_proxy, TEST_IFACE); proxy_client = gbinder_client_new(remote_proxy, TEST_IFACE);
test_binder_set_passthrough(fd_obj, TRUE); test_binder_set_passthrough(fd_obj, TRUE);
@ -367,7 +388,7 @@ test_param(
/* /*
* Perform two transactions via proxy. First one never gets completed * Perform two transactions via proxy. First one never gets completed
* and eventually is cancelled, and the seconf one is replied to. * and eventually is cancelled, and the second one is replied to.
*/ */
req = gbinder_client_new_request(proxy_client); req = gbinder_client_new_request(proxy_client);
gbinder_local_request_append_int32(req, TX_PARAM_DONT_REPLY); gbinder_local_request_append_int32(req, TX_PARAM_DONT_REPLY);
@ -382,7 +403,9 @@ test_param(
gbinder_local_request_unref(req); gbinder_local_request_unref(req);
test_run(&test_opt, loop); test_run(&test_opt, loop);
g_assert_cmpint(n, == ,2);
/* Depending on how callbacks are scheduled, n could be 1 or 2 */
g_assert_cmpint(n, > ,0);
test_binder_unregister_objects(fd_obj); test_binder_unregister_objects(fd_obj);
test_binder_unregister_objects(fd_proxy); test_binder_unregister_objects(fd_proxy);
@ -401,6 +424,255 @@ test_param(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_param(
void)
{
test_run_in_context(&test_opt, test_param_run);
}
/*==========================================================================*
* obj
*==========================================================================*/
typedef struct test_obj_data {
GMainLoop* loop;
GBinderLocalObject* tmp_proxy;
gboolean obj_call_handled;
gboolean obj_call_finished;
gboolean obj2_call_handled;
gboolean obj2_call_finished;
} TestObj;
static
GBinderLocalReply*
test_obj2_cb(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
TestObj* test = user_data;
GBinderReader reader;
gint32 param = 0;
GDEBUG("Request 2 handled");
g_assert(!test->obj2_call_handled);
test->obj2_call_handled = TRUE;
g_assert(!flags);
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_IFACE2));
g_assert(code == TX_CODE2);
/* TX_PARAM3 parameter is expected */
gbinder_remote_request_init_reader(req, &reader);
g_assert(gbinder_reader_read_int32(&reader, &param));
g_assert_cmpuint(param, == ,TX_PARAM3);
g_assert(gbinder_reader_at_end(&reader));
*status = GBINDER_STATUS_OK;
return gbinder_local_reply_append_int32
(gbinder_local_object_new_reply(obj), TX_RESULT2);
}
static
void
test_obj2_reply(
GBinderClient* client,
GBinderRemoteReply* reply,
int status,
void* data)
{
GBinderReader reader;
gint32 result = 0;
TestObj* test = data;
GDEBUG("Reply 2 received");
/* Make sure that result got delivered intact */
gbinder_remote_reply_init_reader(reply, &reader);
g_assert(gbinder_reader_read_int32(&reader, &result));
g_assert(gbinder_reader_at_end(&reader));
g_assert_cmpint(result, == ,TX_RESULT2);
g_assert(!test->obj2_call_finished);
test->obj2_call_finished = TRUE;
if (test->obj_call_finished) {
GDEBUG("Both calls are done");
g_main_loop_quit(test->loop);
}
}
static
GBinderLocalReply*
test_obj_cb(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
TestObj* test = user_data;
GBinderReader reader;
GBinderRemoteObject* obj2;
GBinderClient* client2;
GBinderLocalRequest* req2;
gint32 param = 0;
GDEBUG("Request 1 handled");
g_assert(!test->obj_call_handled);
test->obj_call_handled = TRUE;
g_assert(!flags);
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_IFACE));
g_assert(code == TX_CODE);
/* Read parameters: TX_PARAM1, object, TX_PARAM2 */
gbinder_remote_request_init_reader(req, &reader);
g_assert(gbinder_reader_read_int32(&reader, &param));
g_assert_cmpuint(param, == ,TX_PARAM1);
g_assert((obj2 = gbinder_reader_read_object(&reader)));
g_assert(gbinder_reader_read_int32(&reader, &param));
g_assert_cmpuint(param, == ,TX_PARAM2);
g_assert(gbinder_reader_at_end(&reader));
/* Make sure temporary proxy won't get destroyed too early */
test->tmp_proxy = test_binder_object(gbinder_driver_fd(obj->ipc->driver),
obj2->handle);
g_assert(test->tmp_proxy);
/* Call remote object */
client2 = gbinder_client_new(obj2, TEST_IFACE2);
req2 = gbinder_client_new_request(client2);
gbinder_local_request_append_int32(req2, TX_PARAM3);
gbinder_client_transact(client2, TX_CODE2, 0, req2, test_obj2_reply,
NULL, test);
gbinder_local_request_unref(req2);
gbinder_client_unref(client2);
gbinder_remote_object_unref(obj2);
*status = GBINDER_STATUS_OK;
return gbinder_local_reply_append_int32
(gbinder_local_object_new_reply(obj), TX_RESULT1);
}
static
void
test_obj_reply(
GBinderClient* client,
GBinderRemoteReply* reply,
int status,
void* data)
{
GBinderReader reader;
gint32 result = 0;
TestObj* test = data;
GDEBUG("Reply 1 received");
/* Make sure that result got delivered intact */
gbinder_remote_reply_init_reader(reply, &reader);
g_assert(gbinder_reader_read_int32(&reader, &result));
g_assert(gbinder_reader_at_end(&reader));
g_assert_cmpint(result, == ,TX_RESULT1);
g_assert(!test->obj_call_finished);
test->obj_call_finished = TRUE;
if (test->obj2_call_finished) {
GDEBUG("Both calls are done");
g_main_loop_quit(test->loop);
}
}
static
void
test_obj_run(
void)
{
TestConfig config;
TestObj test;
GBinderLocalObject* obj;
GBinderLocalObject* obj2;
GBinderProxyObject* proxy;
GBinderRemoteObject* remote_obj;
GBinderRemoteObject* remote_proxy;
GBinderClient* proxy_client;
GBinderIpc* ipc_obj;
GBinderIpc* ipc_proxy;
GBinderLocalRequest* req;
int fd_obj, fd_proxy;
test_config_init(&config, NULL);
memset(&test, 0, sizeof(test));
test.loop = g_main_loop_new(NULL, FALSE);
ipc_proxy = gbinder_ipc_new(DEV);
ipc_obj = gbinder_ipc_new(DEV_PRIV);
fd_proxy = gbinder_driver_fd(ipc_proxy->driver);
fd_obj = gbinder_driver_fd(ipc_obj->driver);
obj = gbinder_local_object_new(ipc_obj, TEST_IFACES, test_obj_cb, &test);
obj2 = gbinder_local_object_new(ipc_obj, TEST_IFACES2, test_obj2_cb, &test);
remote_obj = gbinder_remote_object_new(ipc_proxy,
test_binder_register_object(fd_obj, obj, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
/* remote_proxy(DEV_PRIV) => proxy (DEV) => obj (DEV) => DEV_PRIV */
g_assert(!gbinder_proxy_object_new(NULL, remote_obj));
g_assert((proxy = gbinder_proxy_object_new(ipc_proxy, remote_obj)));
remote_proxy = gbinder_remote_object_new(ipc_obj,
test_binder_register_object(fd_proxy, &proxy->parent, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
proxy_client = gbinder_client_new(remote_proxy, TEST_IFACE);
test_binder_set_passthrough(fd_obj, TRUE);
test_binder_set_passthrough(fd_proxy, TRUE);
test_binder_set_looper_enabled(fd_obj, TEST_LOOPER_ENABLE);
test_binder_set_looper_enabled(fd_proxy, TEST_LOOPER_ENABLE);
/* Pass object reference via proxy */
req = gbinder_client_new_request(proxy_client);
gbinder_local_request_append_int32(req, TX_PARAM1);
gbinder_local_request_append_local_object(req, obj2);
gbinder_local_request_append_int32(req, TX_PARAM2);
gbinder_client_transact(proxy_client, TX_CODE, 0, req, test_obj_reply,
NULL, &test);
gbinder_local_request_unref(req);
test_run(&test_opt, test.loop);
g_assert(test.obj_call_handled);
g_assert(test.obj_call_finished);
g_assert(test.obj2_call_handled);
g_assert(test.obj2_call_finished);
g_assert(test.tmp_proxy);
gbinder_local_object_unref(test.tmp_proxy);
test_binder_unregister_objects(fd_obj);
test_binder_unregister_objects(fd_proxy);
gbinder_local_object_drop(obj);
gbinder_local_object_drop(obj2);
gbinder_local_object_drop(&proxy->parent);
gbinder_remote_object_unref(remote_obj);
gbinder_remote_object_unref(remote_proxy);
gbinder_client_unref(proxy_client);
gbinder_ipc_unref(ipc_obj);
gbinder_ipc_unref(ipc_proxy);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, test.loop);
test_config_deinit(&config);
g_main_loop_unref(test.loop);
}
static
void
test_obj(
void)
{
test_run_in_context(&test_opt, test_obj_run);
}
/*==========================================================================* /*==========================================================================*
* Common * Common
*==========================================================================*/ *==========================================================================*/
@ -413,6 +685,7 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_("null"), test_null); g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("basic"), test_basic); g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("param"), test_param); g_test_add_func(TEST_("param"), test_param);
g_test_add_func(TEST_("obj"), test_obj);
test_init(&test_opt, argc, argv); test_init(&test_opt, argc, argv);
return g_test_run(); return g_test_run();
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2020 Jolla Ltd. * Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@ -70,8 +70,8 @@ test_basic(
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj1 = gbinder_object_registry_get_remote(reg, 1); GBinderRemoteObject* obj1 = gbinder_object_registry_get_remote(reg,1,TRUE);
GBinderRemoteObject* obj2 = gbinder_object_registry_get_remote(reg, 2); GBinderRemoteObject* obj2 = gbinder_object_registry_get_remote(reg,2,TRUE);
g_assert(obj1); g_assert(obj1);
g_assert(obj2); g_assert(obj2);
@ -84,7 +84,7 @@ test_basic(
g_assert(gbinder_remote_object_ref(obj1) == obj1); g_assert(gbinder_remote_object_ref(obj1) == obj1);
gbinder_remote_object_unref(obj1); /* Compensate the above reference */ gbinder_remote_object_unref(obj1); /* Compensate the above reference */
g_assert(!gbinder_remote_object_add_death_handler(obj1, NULL, NULL)); g_assert(!gbinder_remote_object_add_death_handler(obj1, NULL, NULL));
g_assert(gbinder_ipc_get_remote_object(ipc, 1, TRUE) == obj1); g_assert(gbinder_object_registry_get_remote(reg, 1, FALSE) == obj1);
gbinder_remote_object_unref(obj1); /* Compensate the above reference */ gbinder_remote_object_unref(obj1); /* Compensate the above reference */
gbinder_remote_object_unref(obj1); gbinder_remote_object_unref(obj1);
gbinder_remote_object_unref(obj2); gbinder_remote_object_unref(obj2);
@ -107,20 +107,20 @@ test_dead_done(
static static
void void
test_dead( test_dead_run(
void) void)
{ {
const guint handle = 1; const guint h = 1;
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
const int fd = gbinder_driver_fd(ipc->driver); const int fd = gbinder_driver_fd(ipc->driver);
GBinderRemoteObject* obj = gbinder_ipc_get_remote_object GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, h, TRUE);
(ipc, handle, FALSE);
gulong id = gbinder_remote_object_add_death_handler gulong id = gbinder_remote_object_add_death_handler
(obj, test_dead_done, loop); (obj, test_dead_done, loop);
test_binder_br_dead_binder(fd, handle); test_binder_br_dead_binder(fd, h);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
g_assert(gbinder_remote_object_is_dead(obj)); g_assert(gbinder_remote_object_is_dead(obj));
@ -132,6 +132,14 @@ test_dead(
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_dead(
void)
{
test_run_in_context(&test_opt, test_dead_run);
}
/*==========================================================================* /*==========================================================================*
* Common * Common
*==========================================================================*/ *==========================================================================*/

View File

@ -71,7 +71,8 @@ static
GBinderRemoteObject* GBinderRemoteObject*
reg_dummy_get_remote( reg_dummy_get_remote(
GBinderObjectRegistry* reg, GBinderObjectRegistry* reg,
guint32 handle) guint32 handle,
REMOTE_REGISTRY_CREATE create)
{ {
return NULL; return NULL;
} }

View File

@ -38,6 +38,7 @@
#include "gbinder_remote_request_p.h" #include "gbinder_remote_request_p.h"
#include "gbinder_rpc_protocol.h" #include "gbinder_rpc_protocol.h"
#include "gbinder_local_request_p.h" #include "gbinder_local_request_p.h"
#include "gbinder_object_converter.h"
#include "gbinder_output_data.h" #include "gbinder_output_data.h"
#include "gbinder_io.h" #include "gbinder_io.h"
@ -80,6 +81,7 @@ test_null(
g_assert(gbinder_reader_at_end(&reader)); g_assert(gbinder_reader_at_end(&reader));
g_assert(!gbinder_remote_request_interface(NULL)); g_assert(!gbinder_remote_request_interface(NULL));
g_assert(!gbinder_remote_request_copy_to_local(NULL)); g_assert(!gbinder_remote_request_copy_to_local(NULL));
g_assert(!gbinder_remote_request_convert_to_local(NULL, NULL));
g_assert(gbinder_remote_request_sender_pid(NULL) == (pid_t)(-1)); g_assert(gbinder_remote_request_sender_pid(NULL) == (pid_t)(-1));
g_assert(gbinder_remote_request_sender_euid(NULL) == (uid_t)(-1)); g_assert(gbinder_remote_request_sender_euid(NULL) == (uid_t)(-1));
g_assert(!gbinder_remote_request_read_int32(NULL, NULL)); g_assert(!gbinder_remote_request_read_int32(NULL, NULL));
@ -89,6 +91,7 @@ test_null(
g_assert(!gbinder_remote_request_read_string8(NULL)); g_assert(!gbinder_remote_request_read_string8(NULL));
g_assert(!gbinder_remote_request_read_string16(NULL)); g_assert(!gbinder_remote_request_read_string16(NULL));
g_assert(!gbinder_remote_request_read_object(NULL)); g_assert(!gbinder_remote_request_read_object(NULL));
g_assert(!gbinder_object_converter_handle_to_local(NULL, 0));
} }
/*==========================================================================* /*==========================================================================*
@ -252,6 +255,15 @@ test_string16(
* to_local * to_local
*==========================================================================*/ *==========================================================================*/
static
GBinderLocalObject*
test_to_local_convert_none(
GBinderObjectConverter* convert,
guint32 handle)
{
return NULL;
}
static static
void void
test_to_local( test_to_local(
@ -277,12 +289,16 @@ test_to_local(
TEST_INT64_BYTES(0), /* handle */ TEST_INT64_BYTES(0), /* handle */
TEST_INT64_BYTES(0) /* cookie */ TEST_INT64_BYTES(0) /* cookie */
}; };
static const GBinderObjectConverterFunctions convert_f = {
.handle_to_local = test_to_local_convert_none
};
const char* dev = GBINDER_DEFAULT_BINDER; const char* dev = GBINDER_DEFAULT_BINDER;
const char* dev2 = GBINDER_DEFAULT_HWBINDER; const char* dev2 = GBINDER_DEFAULT_HWBINDER;
GBinderDriver* driver = gbinder_driver_new(dev, NULL); GBinderDriver* driver = gbinder_driver_new(dev, NULL);
GBinderDriver* driver2 = gbinder_driver_new(dev2, NULL); GBinderDriver* driver2 = gbinder_driver_new(dev2, NULL);
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL, GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
gbinder_rpc_protocol_for_device(dev), 0, 0); gbinder_rpc_protocol_for_device(dev), 0, 0);
GBinderObjectConverter convert;
GBinderLocalRequest* req2; GBinderLocalRequest* req2;
GBinderOutputData* data; GBinderOutputData* data;
const GByteArray* bytes; const GByteArray* bytes;
@ -311,7 +327,7 @@ test_to_local(
gbinder_local_request_unref(req2); gbinder_local_request_unref(req2);
/* The same with gbinder_remote_request_translate_to_local() */ /* The same with gbinder_remote_request_translate_to_local() */
req2 = gbinder_remote_request_translate_to_local(req, NULL); req2 = gbinder_remote_request_convert_to_local(req, NULL);
data = gbinder_local_request_data(req2); data = gbinder_local_request_data(req2);
offsets = gbinder_output_data_offsets(data); offsets = gbinder_output_data_offsets(data);
bytes = data->bytes; bytes = data->bytes;
@ -324,7 +340,11 @@ test_to_local(
gbinder_local_request_unref(req2); gbinder_local_request_unref(req2);
/* Different driver actually requires translation */ /* Different driver actually requires translation */
req2 = gbinder_remote_request_translate_to_local(req, driver2); memset(&convert, 0, sizeof(convert));
convert.f = &convert_f;
convert.io = gbinder_driver_io(driver2);
convert.protocol = gbinder_driver_protocol(driver2);
req2 = gbinder_remote_request_convert_to_local(req, &convert);
data = gbinder_local_request_data(req2); data = gbinder_local_request_data(req2);
offsets = gbinder_output_data_offsets(data); offsets = gbinder_output_data_offsets(data);
bytes = data->bytes; bytes = data->bytes;

View File

@ -39,6 +39,7 @@
#include "gbinder_ipc.h" #include "gbinder_ipc.h"
#include "gbinder_local_object_p.h" #include "gbinder_local_object_p.h"
#include "gbinder_servicemanager_p.h" #include "gbinder_servicemanager_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_rpc_protocol.h" #include "gbinder_rpc_protocol.h"
#include <gutil_strv.h> #include <gutil_strv.h>
@ -177,8 +178,9 @@ test_servicemanager_get_service(
if (gutil_strv_contains(self->services, name)) { if (gutil_strv_contains(self->services, name)) {
if (!self->remote) { if (!self->remote) {
self->remote = gbinder_ipc_get_remote_object self->remote = gbinder_object_registry_get_remote
(gbinder_client_ipc(sm->client), 1, TRUE); (gbinder_ipc_object_registry(gbinder_client_ipc(sm->client)),
1, TRUE);
} }
*status = GBINDER_STATUS_OK; *status = GBINDER_STATUS_OK;
return gbinder_remote_object_ref(self->remote); return gbinder_remote_object_ref(self->remote);
@ -491,6 +493,7 @@ test_basic(
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
} }
/*==========================================================================* /*==========================================================================*
@ -533,6 +536,7 @@ test_legacy(
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_servicemanager_exit(); gbinder_servicemanager_exit();
gbinder_ipc_exit();
} }
/*==========================================================================* /*==========================================================================*
@ -682,6 +686,7 @@ test_wait(
gbinder_servicemanager_remove_handler(sm, id); gbinder_servicemanager_remove_handler(sm, id);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
} }
/*==========================================================================* /*==========================================================================*
@ -727,6 +732,7 @@ test_wait_long(
gbinder_servicemanager_remove_handler(sm, id); gbinder_servicemanager_remove_handler(sm, id);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
} }
/*==========================================================================* /*==========================================================================*
@ -770,6 +776,7 @@ test_wait_async(
gbinder_servicemanager_remove_all_handlers(sm, id); gbinder_servicemanager_remove_all_handlers(sm, id);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
@ -779,8 +786,7 @@ test_wait_async(
static static
void void
test_death( test_death_run()
void)
{ {
const char* dev = GBINDER_DEFAULT_HWBINDER; const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev); GBinderIpc* ipc = gbinder_ipc_new(dev);
@ -806,7 +812,7 @@ test_death(
/* Generate death notification (need looper for that) */ /* Generate death notification (need looper for that) */
test_binder_br_dead_binder(fd, 0); test_binder_br_dead_binder(fd, 0);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
/* No registrations must have occured */ /* No registrations must have occured */
@ -819,9 +825,17 @@ test_death(
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_death()
{
test_run_in_context(&test_opt, test_death_run);
}
/*==========================================================================* /*==========================================================================*
* reanimate * reanimate
*==========================================================================*/ *==========================================================================*/
@ -840,7 +854,7 @@ test_reanimate_quit(
/* Disable looper and reanimate the object */ /* Disable looper and reanimate the object */
GDEBUG("Reanimating..."); GDEBUG("Reanimating...");
test_binder_set_looper_enabled(fd, FALSE); test_binder_set_looper_enabled(fd, TEST_LOOPER_DISABLE);
test_binder_br_transaction_complete(fd); test_binder_br_transaction_complete(fd);
test_binder_br_reply(fd, 0, 0, NULL); test_binder_br_reply(fd, 0, 0, NULL);
} }
@ -877,7 +891,7 @@ test_reanimate(
/* Generate death notification (need looper for that) */ /* Generate death notification (need looper for that) */
test_binder_br_dead_binder(fd, 0); test_binder_br_dead_binder(fd, 0);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_run(&test_opt, loop); test_run(&test_opt, loop);
/* No registrations must have occured */ /* No registrations must have occured */
@ -891,6 +905,7 @@ test_reanimate(
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
@ -948,6 +963,7 @@ test_reuse(
gbinder_ipc_unref(binder_ipc); gbinder_ipc_unref(binder_ipc);
gbinder_ipc_unref(vndbinder_ipc); gbinder_ipc_unref(vndbinder_ipc);
gbinder_ipc_unref(hwbinder_ipc); gbinder_ipc_unref(hwbinder_ipc);
gbinder_ipc_exit();
} }
/*==========================================================================* /*==========================================================================*
@ -992,6 +1008,7 @@ test_notify_type(
gbinder_servicemanager_remove_handler(sm, id2); gbinder_servicemanager_remove_handler(sm, id2);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
} }
static static
@ -1049,6 +1066,7 @@ test_list(
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
@ -1112,6 +1130,7 @@ test_get(
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
@ -1156,8 +1175,10 @@ test_add(
test_run(&test_opt, loop); test_run(&test_opt, loop);
g_assert(gutil_strv_contains(test->services, "foo")); g_assert(gutil_strv_contains(test->services, "foo"));
gbinder_local_object_unref(obj);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }

View File

@ -178,7 +178,7 @@ servicemanager_aidl_new(
self->handle_on_looper_thread = handle_on_looper_thread; self->handle_on_looper_thread = handle_on_looper_thread;
gbinder_local_object_init_base(obj, ipc, servicemanager_aidl_ifaces, gbinder_local_object_init_base(obj, ipc, servicemanager_aidl_ifaces,
servicemanager_aidl_handler, self); servicemanager_aidl_handler, self);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_register_object(fd, obj, SVCMGR_HANDLE); test_binder_register_object(fd, obj, SVCMGR_HANDLE);
gbinder_ipc_register_local_object(ipc, obj); gbinder_ipc_register_local_object(ipc, obj);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
@ -308,7 +308,7 @@ test_get_cb(
static static
void void
test_get() test_get_run()
{ {
const char* dev = GBINDER_DEFAULT_BINDER; const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private"; const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
@ -319,7 +319,6 @@ test_get()
const char* name = "name"; const char* name = "name";
GBinderServiceManager* sm; GBinderServiceManager* sm;
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GMainContext* context = g_main_loop_get_context(loop);
/* Set up binder simulator */ /* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE); test_binder_register_object(fd, obj, AUTO_HANDLE);
@ -346,25 +345,24 @@ test_get()
g_assert(gbinder_servicemanager_get_service(sm, name, test_get_cb, loop)); g_assert(gbinder_servicemanager_get_service(sm, name, test_get_cb, loop));
test_run(&test_opt, loop); test_run(&test_opt, loop);
/*
* Synchronize deletion of objects with the threads that may
* still be running.
*/
while (!g_main_context_acquire(context)) {
GDEBUG("Acquiring the context");
}
test_binder_unregister_objects(fd); test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj); gbinder_local_object_unref(obj);
servicemanager_aidl_free(smsvc); servicemanager_aidl_free(smsvc);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
g_main_context_release(context);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop); test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_get()
{
test_run_in_context(&test_opt, test_get_run);
}
/*==========================================================================* /*==========================================================================*
* list * list
*==========================================================================*/ *==========================================================================*/
@ -392,7 +390,7 @@ test_list_cb(
static static
void void
test_list() test_list_run()
{ {
const char* dev = GBINDER_DEFAULT_BINDER; const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private"; const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
@ -402,7 +400,6 @@ test_list()
const int fd = gbinder_driver_fd(ipc->driver); const int fd = gbinder_driver_fd(ipc->driver);
const char* name = "name"; const char* name = "name";
GBinderServiceManager* sm; GBinderServiceManager* sm;
GMainContext* context;
TestList test; TestList test;
memset(&test, 0, sizeof(test)); memset(&test, 0, sizeof(test));
@ -434,20 +431,11 @@ test_list()
g_assert_cmpuint(gutil_strv_length(test.list), == ,1); g_assert_cmpuint(gutil_strv_length(test.list), == ,1);
g_assert_cmpstr(test.list[0], == ,name); g_assert_cmpstr(test.list[0], == ,name);
/*
* Synchronize deletion of objects with the threads that may
* still be running.
*/
context = g_main_loop_get_context(test.loop);
while (!g_main_context_acquire(context)) {
GDEBUG("Acquiring the context");
}
test_binder_unregister_objects(fd); test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj); gbinder_local_object_unref(obj);
servicemanager_aidl_free(smsvc); servicemanager_aidl_free(smsvc);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
g_main_context_release(context);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, test.loop); test_binder_exit_wait(&test_opt, test.loop);
@ -456,6 +444,13 @@ test_list()
g_main_loop_unref(test.loop); g_main_loop_unref(test.loop);
} }
static
void
test_list()
{
test_run_in_context(&test_opt, test_list_run);
}
/*==========================================================================* /*==========================================================================*
* notify * notify
*==========================================================================*/ *==========================================================================*/
@ -474,7 +469,7 @@ test_notify_cb(
static static
void void
test_notify() test_notify_run()
{ {
const char* dev = GBINDER_DEFAULT_BINDER; const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private"; const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
@ -485,7 +480,6 @@ test_notify()
const char* name = "name"; const char* name = "name";
GBinderServiceManager* sm; GBinderServiceManager* sm;
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GMainContext* context = g_main_loop_get_context(loop);
gulong id; gulong id;
/* Set up binder simulator */ /* Set up binder simulator */
@ -508,32 +502,31 @@ test_notify()
test_run(&test_opt, loop); test_run(&test_opt, loop);
gbinder_servicemanager_remove_handler(sm, id); gbinder_servicemanager_remove_handler(sm, id);
/*
* Synchronize deletion of objects with the threads that may
* still be running.
*/
while (!g_main_context_acquire(context)) {
GDEBUG("Acquiring the context");
}
test_binder_unregister_objects(fd); test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj); gbinder_local_object_unref(obj);
servicemanager_aidl_free(svc); servicemanager_aidl_free(svc);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
g_main_context_release(context);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop); test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_notify()
{
test_run_in_context(&test_opt, test_notify_run);
}
/*==========================================================================* /*==========================================================================*
* notify2 * notify2
*==========================================================================*/ *==========================================================================*/
static static
void void
test_notify2() test_notify2_run()
{ {
const char* dev = GBINDER_DEFAULT_BINDER; const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private"; const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
@ -545,7 +538,6 @@ test_notify2()
const char* name1 = "name1"; const char* name1 = "name1";
const char* name2 = "name2"; const char* name2 = "name2";
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GMainContext* context = g_main_loop_get_context(loop);
gulong id1, id2; gulong id1, id2;
/* Set up binder simulator */ /* Set up binder simulator */
@ -577,25 +569,24 @@ test_notify2()
gbinder_servicemanager_remove_handler(sm, id1); gbinder_servicemanager_remove_handler(sm, id1);
gbinder_servicemanager_remove_handler(sm, id2); gbinder_servicemanager_remove_handler(sm, id2);
/*
* Synchronize deletion of objects with the threads that may
* still be running.
*/
while (!g_main_context_acquire(context)) {
GDEBUG("Acquiring the context");
}
test_binder_unregister_objects(fd); test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj); gbinder_local_object_unref(obj);
servicemanager_aidl_free(smsvc); servicemanager_aidl_free(smsvc);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
g_main_context_release(context);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop); test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_notify2()
{
test_run_in_context(&test_opt, test_notify2_run);
}
/*==========================================================================* /*==========================================================================*
* Common * Common
*==========================================================================*/ *==========================================================================*/

View File

@ -180,7 +180,7 @@ servicemanager_aidl2_new(
self->handle_on_looper_thread = handle_on_looper_thread; self->handle_on_looper_thread = handle_on_looper_thread;
gbinder_local_object_init_base(obj, ipc, servicemanager_aidl_ifaces, gbinder_local_object_init_base(obj, ipc, servicemanager_aidl_ifaces,
servicemanager_aidl2_handler, self); servicemanager_aidl2_handler, self);
test_binder_set_looper_enabled(fd, TRUE); test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_register_object(fd, obj, SVCMGR_HANDLE); test_binder_register_object(fd, obj, SVCMGR_HANDLE);
gbinder_ipc_register_local_object(ipc, obj); gbinder_ipc_register_local_object(ipc, obj);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
@ -344,7 +344,7 @@ test_context_deinit(
static static
void void
test_get() test_get_run()
{ {
TestContext test; TestContext test;
const char* name = "name"; const char* name = "name";
@ -375,13 +375,20 @@ test_get()
test_context_deinit(&test); test_context_deinit(&test);
} }
static
void
test_get()
{
test_run_in_context(&test_opt, test_get_run);
}
/*==========================================================================* /*==========================================================================*
* list * list
*==========================================================================*/ *==========================================================================*/
static static
void void
test_list() test_list_run()
{ {
TestContext test; TestContext test;
const char* name = "name"; const char* name = "name";
@ -413,6 +420,13 @@ test_list()
test_context_deinit(&test); test_context_deinit(&test);
} }
static
void
test_list()
{
test_run_in_context(&test_opt, test_list_run);
}
/*==========================================================================* /*==========================================================================*
* Common * Common
*==========================================================================*/ *==========================================================================*/

View File

@ -169,7 +169,7 @@ test_get_cb(
static static
void void
test_get() test_get_run()
{ {
TestConfig config; TestConfig config;
GBinderIpc* ipc; GBinderIpc* ipc;
@ -178,7 +178,6 @@ test_get()
int fd; int fd;
GBinderServiceManager* sm; GBinderServiceManager* sm;
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GMainContext* context = g_main_loop_get_context(loop);
const char* name = "android.hidl.base@1.0::IBase/test"; const char* name = "android.hidl.base@1.0::IBase/test";
test_config_init(&config, NULL); test_config_init(&config, NULL);
@ -216,19 +215,11 @@ test_get()
g_assert(gbinder_servicemanager_get_service(sm, name, test_get_cb, loop)); g_assert(gbinder_servicemanager_get_service(sm, name, test_get_cb, loop));
test_run(&test_opt, loop); test_run(&test_opt, loop);
/*
* Synchronize deletion of objects with the threads that may
* still be running.
*/
while (!g_main_context_acquire(context)) {
GDEBUG("Acquiring the context");
}
test_binder_unregister_objects(fd); test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj); gbinder_local_object_unref(obj);
test_servicemanager_hidl_free(smsvc); test_servicemanager_hidl_free(smsvc);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
g_main_context_release(context);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop); test_binder_exit_wait(&test_opt, loop);
@ -236,6 +227,13 @@ test_get()
g_main_loop_unref(loop); g_main_loop_unref(loop);
} }
static
void
test_get()
{
test_run_in_context(&test_opt, test_get_run);
}
/*==========================================================================* /*==========================================================================*
* list * list
*==========================================================================*/ *==========================================================================*/
@ -263,7 +261,7 @@ test_list_cb(
static static
void void
test_list() test_list_run()
{ {
TestList test; TestList test;
TestConfig config; TestConfig config;
@ -272,7 +270,6 @@ test_list()
GBinderLocalObject* obj; GBinderLocalObject* obj;
int fd; int fd;
GBinderServiceManager* sm; GBinderServiceManager* sm;
GMainContext* context;
const char* name = "android.hidl.base@1.0::IBase/test"; const char* name = "android.hidl.base@1.0::IBase/test";
memset(&test, 0, sizeof(test)); memset(&test, 0, sizeof(test));
@ -311,20 +308,11 @@ test_list()
g_assert_cmpuint(gutil_strv_length(test.list), == ,1); g_assert_cmpuint(gutil_strv_length(test.list), == ,1);
g_assert_cmpstr(test.list[0], == ,name); g_assert_cmpstr(test.list[0], == ,name);
/*
* Synchronize deletion of objects with the threads that may
* still be running.
*/
context = g_main_loop_get_context(test.loop);
while (!g_main_context_acquire(context)) {
GDEBUG("Acquiring the context");
}
test_binder_unregister_objects(fd); test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj); gbinder_local_object_unref(obj);
test_servicemanager_hidl_free(smsvc); test_servicemanager_hidl_free(smsvc);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
g_main_context_release(context);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, test.loop); test_binder_exit_wait(&test_opt, test.loop);
@ -334,6 +322,13 @@ test_list()
g_main_loop_unref(test.loop); g_main_loop_unref(test.loop);
} }
static
void
test_list()
{
test_run_in_context(&test_opt, test_list_run);
}
/*==========================================================================* /*==========================================================================*
* notify * notify
*==========================================================================*/ *==========================================================================*/
@ -394,7 +389,7 @@ test_notify_cb(
static static
void void
test_notify() test_notify_run()
{ {
TestNotify test; TestNotify test;
TestConfig config; TestConfig config;
@ -402,7 +397,6 @@ test_notify()
GBinderLocalObject* obj; GBinderLocalObject* obj;
int fd; int fd;
GBinderServiceManager* sm; GBinderServiceManager* sm;
GMainContext* context;
const char* name = "android.hidl.base@1.0::IBase/test"; const char* name = "android.hidl.base@1.0::IBase/test";
gulong id; gulong id;
@ -443,20 +437,11 @@ test_notify()
test_run(&test_opt, test.loop); test_run(&test_opt, test.loop);
gbinder_servicemanager_remove_handler(sm, id); gbinder_servicemanager_remove_handler(sm, id);
/*
* Synchronize deletion of objects with the threads that may
* still be running.
*/
context = g_main_loop_get_context(test.loop);
while (!g_main_context_acquire(context)) {
GDEBUG("Acquiring the context");
}
test_binder_unregister_objects(fd); test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj); gbinder_local_object_unref(obj);
test_servicemanager_hidl_free(test.smsvc); test_servicemanager_hidl_free(test.smsvc);
gbinder_servicemanager_unref(sm); gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
g_main_context_release(context);
gbinder_ipc_exit(); gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, test.loop); test_binder_exit_wait(&test_opt, test.loop);
@ -464,6 +449,13 @@ test_notify()
g_main_loop_unref(test.loop); g_main_loop_unref(test.loop);
} }
static
void
test_notify()
{
test_run_in_context(&test_opt, test_notify_run);
}
/*==========================================================================* /*==========================================================================*
* Common * Common
*==========================================================================*/ *==========================================================================*/