Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
148b53e862 | ||
|
|
5c8cb0a013 | ||
|
|
4d644e0584 | ||
|
|
dce9c8b3d1 | ||
|
|
b117ee6404 | ||
|
|
c3f783bf7e | ||
|
|
4c65a6eded | ||
|
|
c382cab922 | ||
|
|
199fd4ed61 | ||
|
|
f86d62fbf8 | ||
|
|
3ea82dc384 | ||
|
|
03ae5834ee | ||
|
|
e39b5c20ee | ||
|
|
d6e131eb6e | ||
|
|
1c36b5f142 | ||
|
|
827bd0b59f | ||
|
|
2dab057652 | ||
|
|
488fbc5b63 | ||
|
|
17f511d7a3 | ||
|
|
63e633c0ec | ||
|
|
f46448c236 | ||
|
|
43023be32d | ||
|
|
4811d51c5d | ||
|
|
821dabca3d | ||
|
|
587f4ebb50 | ||
|
|
0c0b25fcd1 | ||
|
|
bdf07d04d4 | ||
|
|
6936675eb9 | ||
|
|
c39bf4b802 | ||
|
|
5a43b1b091 | ||
|
|
3e039e033c | ||
|
|
6a2af83ea3 | ||
|
|
5a12df240b | ||
|
|
2ea7d91fc7 | ||
|
|
d9903e7398 | ||
|
|
39b69f27ee | ||
|
|
31a1d19b4e | ||
|
|
f4a923c3dc | ||
|
|
171ff7d1e4 | ||
|
|
5cfbf22b81 | ||
|
|
5a35ed5ea1 | ||
|
|
1978359f15 | ||
|
|
fef6543f1a |
1
AUTHORS
1
AUTHORS
@@ -2,3 +2,4 @@ Slava Monich <slava.monich@jolla.com>
|
||||
Matti Lehtimäki <matti.lehtimaki@gmail.com>
|
||||
Franz-Josef Haider <franz.haider@jolla.com>
|
||||
Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
Andrew Branson <andrew.branson@jolla.com>
|
||||
|
||||
10
LICENSE
10
LICENSE
@@ -1,5 +1,5 @@
|
||||
Copyright (C) 2018 Jolla Ltd.
|
||||
Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
Copyright (C) 2018-2019 Jolla Ltd.
|
||||
Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of BSD license as follows:
|
||||
|
||||
@@ -12,9 +12,9 @@ are met:
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of Jolla Ltd nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
3. Neither the names of the copyright holders nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
|
||||
4
Makefile
4
Makefile
@@ -24,7 +24,7 @@ all: debug release pkgconfig
|
||||
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 0
|
||||
VERSION_RELEASE = 15
|
||||
VERSION_RELEASE = 24
|
||||
|
||||
# Version for pkg-config
|
||||
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
|
||||
@@ -248,7 +248,7 @@ $(COVERAGE_LIB): $(COVERAGE_OBJS)
|
||||
$(AR) rc $@ $?
|
||||
ranlib $@
|
||||
|
||||
$(PKGCONFIG): $(LIB_NAME).pc.in
|
||||
$(PKGCONFIG): $(LIB_NAME).pc.in Makefile
|
||||
sed -e 's/\[version\]/'$(PCVERSION)/g $< > $@
|
||||
|
||||
#
|
||||
|
||||
58
debian/changelog
vendored
58
debian/changelog
vendored
@@ -1,3 +1,61 @@
|
||||
libgbinder (1.0.24) unstable; urgency=low
|
||||
|
||||
* Revert "Make sure NULL objects are passed as BINDER_TYPE_WEAK_HANDLE"
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 18 Jan 2019 21:36:32 +0200
|
||||
|
||||
libgbinder (1.0.23) unstable; urgency=low
|
||||
|
||||
* Added gbinder_reader_read_hidl_string_c()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 15 Jan 2019 15:16:41 +0200
|
||||
|
||||
libgbinder (1.0.22) unstable; urgency=low
|
||||
|
||||
* Added gbinder_client_interface()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 10 Jan 2019 14:09:44 +0300
|
||||
|
||||
libgbinder (1.0.21) unstable; urgency=low
|
||||
|
||||
* Added API to overwrite prefix length
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 18 Dec 2018 14:05:14 +0200
|
||||
|
||||
libgbinder (1.0.20) unstable; urgency=low
|
||||
|
||||
* Added API to block incoming requests
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Mon, 17 Dec 2018 16:06:43 +0200
|
||||
|
||||
libgbinder (1.0.19) unstable; urgency=low
|
||||
|
||||
* Added GBinderWriter memory allocation and cleanup API
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 14 Dec 2018 16:27:51 +0200
|
||||
|
||||
libgbinder (1.0.18) unstable; urgency=low
|
||||
|
||||
* Implemented support for file descritors
|
||||
* Allow GBinderClient without RPC header
|
||||
* Added binder-dump test
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Mon, 10 Dec 2018 13:17:22 +0200
|
||||
|
||||
libgbinder (1.0.17) unstable; urgency=low
|
||||
|
||||
* Added gbinder_writer_append_string16_utf16()
|
||||
* Added gbinder_reader_read_nullable_string16_utf16()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 07 Dec 2018 02:54:07 +0200
|
||||
|
||||
libgbinder (1.0.16) unstable; urgency=low
|
||||
|
||||
* Added GBinderHidlVec and GBinderHidlString types
|
||||
* Added gbinder_reader_copy()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 06 Dec 2018 19:03:32 +0200
|
||||
|
||||
libgbinder (1.0.15) unstable; urgency=low
|
||||
|
||||
* Implemented service polling for old servicemanager
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -13,9 +13,9 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -58,6 +58,10 @@ void
|
||||
gbinder_client_unref(
|
||||
GBinderClient* client);
|
||||
|
||||
const char*
|
||||
gbinder_client_interface(
|
||||
GBinderClient* client); /* since 1.0.22 */
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_client_new_request(
|
||||
GBinderClient* client);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -53,7 +53,7 @@ struct gbinder_reader {
|
||||
|
||||
gboolean
|
||||
gbinder_reader_at_end(
|
||||
GBinderReader* reader);
|
||||
const GBinderReader* reader);
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_byte(
|
||||
@@ -95,6 +95,15 @@ gbinder_reader_read_double(
|
||||
GBinderReader* reader,
|
||||
gdouble* value);
|
||||
|
||||
int
|
||||
gbinder_reader_read_fd(
|
||||
GBinderReader* reader); /* Since 1.0.18 */
|
||||
|
||||
int
|
||||
gbinder_reader_read_dup_fd(
|
||||
GBinderReader* reader) /* Since 1.0.18 */
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_nullable_object(
|
||||
GBinderReader* reader,
|
||||
@@ -116,7 +125,7 @@ gbinder_reader_read_buffer(
|
||||
const void*
|
||||
gbinder_reader_read_hidl_struct1(
|
||||
GBinderReader* reader,
|
||||
gsize size); /* since 1.0.9 */
|
||||
gsize size); /* Since 1.0.9 */
|
||||
|
||||
#define gbinder_reader_read_hidl_struct(reader,type) \
|
||||
((const type*)gbinder_reader_read_hidl_struct1(reader, sizeof(type)))
|
||||
@@ -131,7 +140,7 @@ const void*
|
||||
gbinder_reader_read_hidl_vec1(
|
||||
GBinderReader* reader,
|
||||
gsize* count,
|
||||
guint expected_elemsize); /* since 1.0.9 */
|
||||
guint expected_elemsize); /* Since 1.0.9 */
|
||||
|
||||
#define gbinder_reader_read_hidl_type_vec(reader,type,count) \
|
||||
((const type*)gbinder_reader_read_hidl_vec1(reader, count, sizeof(type)))
|
||||
@@ -143,6 +152,13 @@ gbinder_reader_read_hidl_string(
|
||||
GBinderReader* reader)
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
const char*
|
||||
gbinder_reader_read_hidl_string_c(
|
||||
GBinderReader* reader); /* Since 1.0.23 */
|
||||
|
||||
#define gbinder_reader_skip_hidl_string(reader) \
|
||||
(gbinder_reader_read_hidl_string_c(reader) != NULL)
|
||||
|
||||
char**
|
||||
gbinder_reader_read_hidl_string_vec(
|
||||
GBinderReader* reader);
|
||||
@@ -165,6 +181,12 @@ gbinder_reader_read_nullable_string16(
|
||||
GBinderReader* reader,
|
||||
char** out);
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_nullable_string16_utf16(
|
||||
GBinderReader* reader,
|
||||
gunichar2** out,
|
||||
gsize* len); /* Since 1.0.17 */
|
||||
|
||||
gboolean
|
||||
gbinder_reader_skip_string16(
|
||||
GBinderReader* reader);
|
||||
@@ -172,15 +194,20 @@ gbinder_reader_skip_string16(
|
||||
const void*
|
||||
gbinder_reader_read_byte_array(
|
||||
GBinderReader* reader,
|
||||
gsize* len); /* since 1.0.12 */
|
||||
gsize* len); /* Since 1.0.12 */
|
||||
|
||||
gsize
|
||||
gbinder_reader_bytes_read(
|
||||
GBinderReader* reader);
|
||||
const GBinderReader* reader);
|
||||
|
||||
gsize
|
||||
gbinder_reader_bytes_remaining(
|
||||
GBinderReader* reader);
|
||||
const GBinderReader* reader);
|
||||
|
||||
void
|
||||
gbinder_reader_copy(
|
||||
GBinderReader* dest,
|
||||
const GBinderReader* src); /* Since 1.0.16 */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -67,6 +67,16 @@ gbinder_remote_request_copy_to_local(
|
||||
GBinderRemoteRequest* req) /* since 1.0.6 */
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
void
|
||||
gbinder_remote_request_block(
|
||||
GBinderRemoteRequest* req); /* Since 1.0.20 */
|
||||
|
||||
void
|
||||
gbinder_remote_request_complete(
|
||||
GBinderRemoteRequest* req,
|
||||
GBinderLocalReply* reply,
|
||||
int status); /* Since 1.0.20 */
|
||||
|
||||
/* Convenience function to decode requests with just one data item */
|
||||
|
||||
gboolean
|
||||
|
||||
@@ -72,6 +72,30 @@ typedef struct gbinder_servicemanager GBinderServiceManager;
|
||||
typedef struct gbinder_writer GBinderWriter;
|
||||
typedef struct gbinder_parent GBinderParent;
|
||||
|
||||
/* Basic HIDL types */
|
||||
|
||||
typedef struct gbinder_hidl_vec {
|
||||
union {
|
||||
guint64 value;
|
||||
const void* ptr;
|
||||
} data;
|
||||
guint32 count;
|
||||
guint32 owns_buffer;
|
||||
} GBinderHidlVec;
|
||||
|
||||
#define GBINDER_HIDL_VEC_BUFFER_OFFSET (0)
|
||||
|
||||
typedef struct gbinder_hidl_string {
|
||||
union {
|
||||
guint64 value;
|
||||
const char* str;
|
||||
} data;
|
||||
guint32 len;
|
||||
guint32 owns_buffer;
|
||||
} GBinderHidlString;
|
||||
|
||||
#define GBINDER_HIDL_STRING_BUFFER_OFFSET (0)
|
||||
|
||||
/*
|
||||
* Each RPC call is identified by the interface name returned
|
||||
* by gbinder_remote_request_interface() the transaction code.
|
||||
|
||||
@@ -86,6 +86,12 @@ gbinder_writer_append_string16_len(
|
||||
const char* utf8,
|
||||
gssize num_bytes);
|
||||
|
||||
void
|
||||
gbinder_writer_append_string16_utf16(
|
||||
GBinderWriter* writer,
|
||||
const gunichar2* utf16,
|
||||
gssize length); /* Since 1.0.17 */
|
||||
|
||||
void
|
||||
gbinder_writer_append_string8(
|
||||
GBinderWriter* writer,
|
||||
@@ -108,6 +114,21 @@ gbinder_writer_append_bytes(
|
||||
const void* data,
|
||||
gsize size);
|
||||
|
||||
void
|
||||
gbinder_writer_append_fd(
|
||||
GBinderWriter* writer,
|
||||
int fd); /* Since 1.0.18 */
|
||||
|
||||
gsize
|
||||
gbinder_writer_bytes_written(
|
||||
GBinderWriter* writer); /* since 1.0.21 */
|
||||
|
||||
void
|
||||
gbinder_writer_overwrite_int32(
|
||||
GBinderWriter* writer,
|
||||
gsize offset,
|
||||
gint32 value); /* since 1.0.21 */
|
||||
|
||||
guint
|
||||
gbinder_writer_append_buffer_object_with_parent(
|
||||
GBinderWriter* writer,
|
||||
@@ -151,10 +172,38 @@ gbinder_writer_append_remote_object(
|
||||
|
||||
void
|
||||
gbinder_writer_append_byte_array(
|
||||
GBinderWriter* self,
|
||||
GBinderWriter* writer,
|
||||
const void* byte_array,
|
||||
gint32 len); /* since 1.0.12 */
|
||||
|
||||
void*
|
||||
gbinder_writer_malloc(
|
||||
GBinderWriter* writer,
|
||||
gsize size); /* since 1.0.19 */
|
||||
|
||||
void*
|
||||
gbinder_writer_malloc0(
|
||||
GBinderWriter* writer,
|
||||
gsize size); /* since 1.0.19 */
|
||||
|
||||
#define gbinder_writer_new(writer,type) \
|
||||
((type*) gbinder_writer_malloc(writer, sizeof(type)))
|
||||
|
||||
#define gbinder_writer_new0(writer,type) \
|
||||
((type*) gbinder_writer_malloc0(writer, sizeof(type)))
|
||||
|
||||
void*
|
||||
gbinder_writer_memdup(
|
||||
GBinderWriter* writer,
|
||||
const void* buf,
|
||||
gsize size); /* since 1.0.19 */
|
||||
|
||||
void
|
||||
gbinder_writer_add_cleanup(
|
||||
GBinderWriter* writer,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data); /* since 1.0.19 */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GBINDER_WRITER_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: libgbinder
|
||||
Version: 1.0.15
|
||||
Version: 1.0.24
|
||||
Release: 0
|
||||
Summary: Binder client library
|
||||
Group: Development/Libraries
|
||||
|
||||
@@ -36,54 +36,62 @@
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
struct gbinder_buffer_memory {
|
||||
struct gbinder_buffer_contents {
|
||||
gint refcount;
|
||||
void* buffer;
|
||||
gsize size;
|
||||
void** objects;
|
||||
GBinderDriver* driver;
|
||||
};
|
||||
|
||||
typedef struct gbinder_buffer_priv {
|
||||
GBinderBuffer pub;
|
||||
GBinderBufferMemory* memory;
|
||||
GBinderBufferContents* contents;
|
||||
} GBinderBufferPriv;
|
||||
|
||||
static inline GBinderBufferPriv* gbinder_buffer_cast(GBinderBuffer* buf)
|
||||
{ return G_CAST(buf, GBinderBufferPriv, pub); }
|
||||
|
||||
/*==========================================================================*
|
||||
* GBinderBufferMemory
|
||||
* GBinderBufferContents
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory_new(
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents_new(
|
||||
GBinderDriver* driver,
|
||||
void* buffer,
|
||||
gsize size)
|
||||
gsize size,
|
||||
void** objects)
|
||||
{
|
||||
GBinderBufferMemory* self = g_slice_new0(GBinderBufferMemory);
|
||||
GBinderBufferContents* self = g_slice_new0(GBinderBufferContents);
|
||||
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
self->buffer = buffer;
|
||||
self->size = size;
|
||||
self->objects = objects;
|
||||
self->driver = gbinder_driver_ref(driver);
|
||||
return self;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_buffer_memory_free(
|
||||
GBinderBufferMemory* self)
|
||||
gbinder_buffer_contents_free(
|
||||
GBinderBufferContents* self)
|
||||
{
|
||||
if (self->objects) {
|
||||
gbinder_driver_close_fds(self->driver, self->objects,
|
||||
((guint8*)self->buffer) + self->size);
|
||||
g_free(self->objects);
|
||||
}
|
||||
gbinder_driver_free_buffer(self->driver, self->buffer);
|
||||
gbinder_driver_unref(self->driver);
|
||||
g_slice_free(GBinderBufferMemory, self);
|
||||
g_slice_free(GBinderBufferContents, self);
|
||||
}
|
||||
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory_ref(
|
||||
GBinderBufferMemory* self)
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents_ref(
|
||||
GBinderBufferContents* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GASSERT(self->refcount > 0);
|
||||
@@ -93,13 +101,13 @@ gbinder_buffer_memory_ref(
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_buffer_memory_unref(
|
||||
GBinderBufferMemory* self)
|
||||
gbinder_buffer_contents_unref(
|
||||
GBinderBufferContents* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GASSERT(self->refcount > 0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
gbinder_buffer_memory_free(self);
|
||||
gbinder_buffer_contents_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,14 +119,14 @@ gbinder_buffer_memory_unref(
|
||||
static
|
||||
GBinderBuffer*
|
||||
gbinder_buffer_alloc(
|
||||
GBinderBufferMemory* memory,
|
||||
GBinderBufferContents* contents,
|
||||
void* data,
|
||||
gsize size)
|
||||
{
|
||||
GBinderBufferPriv* priv = g_slice_new0(GBinderBufferPriv);
|
||||
GBinderBuffer* self = &priv->pub;
|
||||
|
||||
priv->memory = memory;
|
||||
priv->contents = contents;
|
||||
self->data = data;
|
||||
self->size = size;
|
||||
return self;
|
||||
@@ -131,7 +139,7 @@ gbinder_buffer_free(
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
||||
|
||||
gbinder_buffer_memory_unref(priv->memory);
|
||||
gbinder_buffer_contents_unref(priv->contents);
|
||||
g_slice_free(GBinderBufferPriv, priv);
|
||||
}
|
||||
}
|
||||
@@ -140,10 +148,12 @@ GBinderBuffer*
|
||||
gbinder_buffer_new(
|
||||
GBinderDriver* driver,
|
||||
void* data,
|
||||
gsize size)
|
||||
gsize size,
|
||||
void** objects)
|
||||
{
|
||||
return gbinder_buffer_alloc((driver && data) ?
|
||||
gbinder_buffer_memory_new(driver, data, size) : NULL, data, size);
|
||||
gbinder_buffer_contents_new(driver, data, size, objects) : NULL,
|
||||
data, size);
|
||||
}
|
||||
|
||||
GBinderBuffer*
|
||||
@@ -153,7 +163,7 @@ gbinder_buffer_new_with_parent(
|
||||
gsize size)
|
||||
{
|
||||
return gbinder_buffer_alloc(parent ?
|
||||
gbinder_buffer_memory_ref(gbinder_buffer_memory(parent)) : NULL,
|
||||
gbinder_buffer_contents_ref(gbinder_buffer_contents(parent)) : NULL,
|
||||
data, size);
|
||||
}
|
||||
|
||||
@@ -162,13 +172,13 @@ gbinder_buffer_data(
|
||||
GBinderBuffer* self,
|
||||
gsize* size)
|
||||
{
|
||||
GBinderBufferMemory* memory = gbinder_buffer_memory(self);
|
||||
GBinderBufferContents* contents = gbinder_buffer_contents(self);
|
||||
|
||||
if (G_LIKELY(memory)) {
|
||||
if (G_LIKELY(contents)) {
|
||||
if (size) {
|
||||
*size = memory->size;
|
||||
*size = contents->size;
|
||||
}
|
||||
return memory->buffer;
|
||||
return contents->buffer;
|
||||
} else {
|
||||
if (size) {
|
||||
*size = 0;
|
||||
@@ -184,8 +194,8 @@ gbinder_buffer_driver(
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
||||
|
||||
if (priv->memory) {
|
||||
return priv->memory->driver;
|
||||
if (priv->contents) {
|
||||
return priv->contents->driver;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -200,11 +210,25 @@ gbinder_buffer_io(
|
||||
return driver ? gbinder_driver_io(driver) : NULL;
|
||||
}
|
||||
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory(
|
||||
void**
|
||||
gbinder_buffer_objects(
|
||||
GBinderBuffer* self)
|
||||
{
|
||||
return G_LIKELY(self) ? gbinder_buffer_cast(self)->memory : NULL;
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
||||
|
||||
if (priv->contents) {
|
||||
return priv->contents->objects;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents(
|
||||
GBinderBuffer* self)
|
||||
{
|
||||
return G_LIKELY(self) ? gbinder_buffer_cast(self)->contents : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -41,7 +41,8 @@ GBinderBuffer*
|
||||
gbinder_buffer_new(
|
||||
GBinderDriver* driver,
|
||||
void* data,
|
||||
gsize size);
|
||||
gsize size,
|
||||
void** objects);
|
||||
|
||||
GBinderBuffer*
|
||||
gbinder_buffer_new_with_parent(
|
||||
@@ -53,8 +54,8 @@ GBinderDriver*
|
||||
gbinder_buffer_driver(
|
||||
GBinderBuffer* buf);
|
||||
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory(
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents(
|
||||
GBinderBuffer* buf);
|
||||
|
||||
gconstpointer
|
||||
@@ -66,13 +67,17 @@ const GBinderIo*
|
||||
gbinder_buffer_io(
|
||||
GBinderBuffer* buf);
|
||||
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory_ref(
|
||||
GBinderBufferMemory* mem);
|
||||
void**
|
||||
gbinder_buffer_objects(
|
||||
GBinderBuffer* buffer);
|
||||
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents_ref(
|
||||
GBinderBufferContents* contents);
|
||||
|
||||
void
|
||||
gbinder_buffer_memory_unref(
|
||||
GBinderBufferMemory* mem);
|
||||
gbinder_buffer_contents_unref(
|
||||
GBinderBufferContents* contents);
|
||||
|
||||
#endif /* GBINDER_BUFFER_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -48,11 +48,33 @@ struct gbinder_cleanup {
|
||||
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
|
||||
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_cleanup_destroy_func(
|
||||
gpointer data)
|
||||
{
|
||||
GBinderCleanupItem* item = data;
|
||||
|
||||
item->destroy(item->pointer);
|
||||
}
|
||||
|
||||
static
|
||||
GBinderCleanup*
|
||||
gbinder_cleanup_new()
|
||||
{
|
||||
return (GBinderCleanup*)g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
|
||||
GArray* array = g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
|
||||
|
||||
g_array_set_clear_func(array, gbinder_cleanup_destroy_func);
|
||||
return (GBinderCleanup*)array;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_cleanup_reset(
|
||||
GBinderCleanup* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_array_set_size((GArray*)self, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -60,11 +82,6 @@ gbinder_cleanup_free(
|
||||
GBinderCleanup* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < self->count; i++) {
|
||||
self->items[i].destroy(self->items[i].pointer);
|
||||
}
|
||||
g_array_free((GArray*)self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -39,6 +39,10 @@ void
|
||||
gbinder_cleanup_free(
|
||||
GBinderCleanup* cleanup);
|
||||
|
||||
void
|
||||
gbinder_cleanup_reset(
|
||||
GBinderCleanup* cleanup);
|
||||
|
||||
GBinderCleanup*
|
||||
gbinder_cleanup_add(
|
||||
GBinderCleanup* cleanup,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -13,9 +13,9 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -75,7 +75,9 @@ gbinder_client_free(
|
||||
gbinder_remote_object_unref(self->remote);
|
||||
gbinder_local_request_unref(priv->basic_req);
|
||||
g_free(priv->iface);
|
||||
g_bytes_unref(priv->rpc_header);
|
||||
if (priv->rpc_header) {
|
||||
g_bytes_unref(priv->rpc_header);
|
||||
}
|
||||
g_slice_free(GBinderClientPriv, priv);
|
||||
}
|
||||
|
||||
@@ -117,13 +119,13 @@ gbinder_client_new(
|
||||
GBinderRemoteObject* remote,
|
||||
const char* iface)
|
||||
{
|
||||
if (G_LIKELY(remote) && G_LIKELY(iface)) {
|
||||
if (G_LIKELY(remote)) {
|
||||
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
|
||||
GBinderClient* self = &priv->pub;
|
||||
GBinderIpc* ipc = remote->ipc;
|
||||
GBinderOutputData* hdr;
|
||||
GBinderDriver* driver = remote->ipc->driver;
|
||||
|
||||
g_atomic_int_set(&priv->refcount, 1);
|
||||
self->remote = gbinder_remote_object_ref(remote);
|
||||
|
||||
/*
|
||||
* Generate basic request (without additional parameters) and pull
|
||||
@@ -131,12 +133,17 @@ gbinder_client_new(
|
||||
* transactions which has no additional parameters. The header data
|
||||
* are needed for building non-trivial requests.
|
||||
*/
|
||||
priv->basic_req = gbinder_driver_local_request_new(ipc->driver, iface);
|
||||
hdr = gbinder_local_request_data(priv->basic_req);
|
||||
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
|
||||
if (iface) {
|
||||
GBinderOutputData* hdr;
|
||||
|
||||
self->remote = gbinder_remote_object_ref(remote);
|
||||
self->iface = priv->iface = g_strdup(iface);
|
||||
priv->basic_req = gbinder_driver_local_request_new(driver, iface);
|
||||
hdr = gbinder_local_request_data(priv->basic_req);
|
||||
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
|
||||
self->iface = priv->iface = g_strdup(iface);
|
||||
} else {
|
||||
priv->basic_req = gbinder_local_request_new
|
||||
(gbinder_driver_io(driver), NULL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
@@ -169,6 +176,13 @@ gbinder_client_unref(
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
gbinder_client_interface(
|
||||
GBinderClient* self) /* since 1.0.22 */
|
||||
{
|
||||
return G_LIKELY(self) ? gbinder_client_cast(self)->iface : NULL;
|
||||
}
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_client_new_request(
|
||||
GBinderClient* self)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -439,11 +439,10 @@ gbinder_driver_handle_transaction(
|
||||
/* Transfer data ownership to the request */
|
||||
if (tx.data && tx.size) {
|
||||
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
|
||||
gbinder_remote_request_set_data(req,
|
||||
gbinder_buffer_new(self, tx.data, tx.size),
|
||||
tx.objects);
|
||||
gbinder_remote_request_set_data(req, tx.code,
|
||||
gbinder_buffer_new(self, tx.data, tx.size, tx.objects));
|
||||
} else {
|
||||
g_free(tx.objects);
|
||||
GASSERT(!tx.objects);
|
||||
gbinder_driver_free_buffer(self, tx.data);
|
||||
}
|
||||
|
||||
@@ -459,7 +458,7 @@ gbinder_driver_handle_transaction(
|
||||
&status);
|
||||
break;
|
||||
default:
|
||||
GWARN("Unhandled transaction 0x%08x", tx.code);
|
||||
GWARN("Unhandled transaction %s 0x%08x", iface, tx.code);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -637,10 +636,9 @@ gbinder_driver_txstatus(
|
||||
if (tx.data && tx.size) {
|
||||
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
|
||||
gbinder_remote_reply_set_data(reply,
|
||||
gbinder_buffer_new(self, tx.data, tx.size),
|
||||
tx.objects);
|
||||
gbinder_buffer_new(self, tx.data, tx.size, tx.objects));
|
||||
} else {
|
||||
g_free(tx.objects);
|
||||
GASSERT(!tx.objects);
|
||||
gbinder_driver_free_buffer(self, tx.data);
|
||||
}
|
||||
|
||||
@@ -863,6 +861,32 @@ gbinder_driver_release(
|
||||
return gbinder_driver_cmd_int32(self, self->io->bc.release, handle);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_driver_close_fds(
|
||||
GBinderDriver* self,
|
||||
void** objects,
|
||||
const void* end)
|
||||
{
|
||||
const GBinderIo* io = self->io;
|
||||
void** ptr;
|
||||
|
||||
/* Caller checks objects for NULL */
|
||||
for (ptr = objects; *ptr; ptr++) {
|
||||
void* obj = *ptr;
|
||||
|
||||
GASSERT(obj < end);
|
||||
if (obj < end) {
|
||||
int fd;
|
||||
|
||||
if (io->decode_fd_object(obj, (guint8*)end - (guint8*)obj, &fd)) {
|
||||
if (close(fd) < 0) {
|
||||
GWARN("Error closing fd %d: %s", fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_driver_free_buffer(
|
||||
GBinderDriver* self,
|
||||
|
||||
@@ -97,6 +97,12 @@ gbinder_driver_release(
|
||||
GBinderDriver* driver,
|
||||
guint32 handle);
|
||||
|
||||
void
|
||||
gbinder_driver_close_fds(
|
||||
GBinderDriver* self,
|
||||
void** objects,
|
||||
const void* end);
|
||||
|
||||
void
|
||||
gbinder_driver_free_buffer(
|
||||
GBinderDriver* driver,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -128,7 +128,7 @@ GBINDER_IO_FN(encode_local_object)(
|
||||
struct flat_binder_object* dest = out;
|
||||
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
dest->hdr.type = obj ? BINDER_TYPE_BINDER : BINDER_TYPE_WEAK_HANDLE;
|
||||
dest->hdr.type = BINDER_TYPE_BINDER;
|
||||
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
||||
dest->binder = (uintptr_t)obj;
|
||||
return sizeof(*dest);
|
||||
@@ -153,6 +153,21 @@ GBINDER_IO_FN(encode_remote_object)(
|
||||
return sizeof(*dest);
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_fd_object)(
|
||||
void* out,
|
||||
int fd)
|
||||
{
|
||||
struct flat_binder_object* dest = out;
|
||||
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
dest->hdr.type = BINDER_TYPE_FD;
|
||||
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
||||
dest->handle = fd;
|
||||
return sizeof(*dest);
|
||||
}
|
||||
|
||||
/* Encodes binder_buffer_object */
|
||||
static
|
||||
guint
|
||||
@@ -394,7 +409,7 @@ guint
|
||||
GBINDER_IO_FN(decode_buffer_object)(
|
||||
GBinderBuffer* buf,
|
||||
gsize offset,
|
||||
GBinderBuffer** out)
|
||||
GBinderIoBufferObject* out)
|
||||
{
|
||||
const void* data = (guint8*)buf->data + offset;
|
||||
const gsize size = (offset < buf->size) ? (buf->size - offset) : 0;
|
||||
@@ -402,12 +417,36 @@ GBINDER_IO_FN(decode_buffer_object)(
|
||||
|
||||
if (size >= sizeof(*flat) && flat->hdr.type == BINDER_TYPE_PTR) {
|
||||
if (out) {
|
||||
*out = gbinder_buffer_new_with_parent(buf,
|
||||
(void*)(uintptr_t)flat->buffer, flat->length);
|
||||
out->data = (void*)(uintptr_t)flat->buffer;
|
||||
out->size = (gsize)flat->length;
|
||||
out->parent_offset = (gsize)flat->parent_offset;
|
||||
out->has_parent = (flat->flags & BINDER_BUFFER_FLAG_HAS_PARENT) ?
|
||||
TRUE : FALSE;
|
||||
}
|
||||
return sizeof(*flat);
|
||||
}
|
||||
if (out) *out = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(decode_fd_object)(
|
||||
const void* data,
|
||||
gsize size,
|
||||
int* fd)
|
||||
{
|
||||
const struct flat_binder_object* obj = data;
|
||||
|
||||
if (size >= sizeof(*obj)) {
|
||||
switch (obj->hdr.type) {
|
||||
case BINDER_TYPE_FD:
|
||||
if (fd) *fd = obj->handle;
|
||||
return sizeof(*obj);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fd) *fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -466,6 +505,7 @@ const GBinderIo GBINDER_IO_PREFIX = {
|
||||
.encode_pointer = GBINDER_IO_FN(encode_pointer),
|
||||
.encode_local_object = GBINDER_IO_FN(encode_local_object),
|
||||
.encode_remote_object = GBINDER_IO_FN(encode_remote_object),
|
||||
.encode_fd_object = GBINDER_IO_FN(encode_fd_object),
|
||||
.encode_buffer_object = GBINDER_IO_FN(encode_buffer_object),
|
||||
.encode_death_notification = GBINDER_IO_FN(encode_death_notification),
|
||||
.encode_transaction = GBINDER_IO_FN(encode_transaction),
|
||||
@@ -478,6 +518,7 @@ const GBinderIo GBINDER_IO_PREFIX = {
|
||||
.decode_binder_ptr_cookie = GBINDER_IO_FN(decode_binder_ptr_cookie),
|
||||
.decode_binder_object = GBINDER_IO_FN(decode_binder_object),
|
||||
.decode_buffer_object = GBINDER_IO_FN(decode_buffer_object),
|
||||
.decode_fd_object = GBINDER_IO_FN(decode_fd_object),
|
||||
|
||||
/* ioctl wrappers */
|
||||
.write_read = GBINDER_IO_FN(write_read)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -43,6 +43,13 @@ typedef struct gbinder_io_buf {
|
||||
gsize consumed;
|
||||
} GBinderIoBuf;
|
||||
|
||||
typedef struct gbinder_io_buffer_object {
|
||||
void* data;
|
||||
gsize size;
|
||||
gsize parent_offset;
|
||||
gboolean has_parent;
|
||||
} GBinderIoBufferObject;
|
||||
|
||||
typedef struct gbinder_io_tx_data {
|
||||
int status;
|
||||
guint32 code;
|
||||
@@ -131,6 +138,7 @@ struct gbinder_io {
|
||||
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
|
||||
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
|
||||
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
|
||||
guint (*encode_fd_object)(void* out, int fd);
|
||||
|
||||
/* Encode binder_buffer_object */
|
||||
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
|
||||
@@ -164,9 +172,10 @@ struct gbinder_io {
|
||||
void* (*decode_binder_ptr_cookie)(const void* data);
|
||||
guint (*decode_cookie)(const void* data, guint64* cookie);
|
||||
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,
|
||||
GBinderBuffer** out);
|
||||
GBinderIoBufferObject* out);
|
||||
guint (*decode_fd_object)(const void* data, gsize size, int* fd);
|
||||
|
||||
/* ioctl wrappers */
|
||||
int (*write_read)(int fd, GBinderIoBuf* write, GBinderIoBuf* read);
|
||||
|
||||
@@ -68,9 +68,9 @@ struct gbinder_ipc_priv {
|
||||
GMutex local_objects_mutex;
|
||||
GHashTable* local_objects;
|
||||
|
||||
/* We may need more loopers... But let's start with just one */
|
||||
GMutex looper_mutex;
|
||||
GBinderIpcLooper* looper;
|
||||
GBinderIpcLooper* primary_loopers;
|
||||
GBinderIpcLooper* blocked_loopers;
|
||||
};
|
||||
|
||||
typedef GObjectClass GBinderIpcClass;
|
||||
@@ -100,7 +100,7 @@ static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
* When the main thread receives GBinderIpcLooperTx:
|
||||
*
|
||||
* 1. Lets the object to process it and produce the response (GBinderOutput).
|
||||
* 2. Writes one byte to the sending end of the tx pipe.
|
||||
* 2. Writes one byte (TX_DONE) to the sending end of the tx pipe.
|
||||
* 3. Unreferences GBinderIpcLooperTx
|
||||
*
|
||||
* When tx pipe wakes up the looper:
|
||||
@@ -111,11 +111,26 @@ static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
* Note that GBinderIpcLooperTx can be deallocated on either looper or
|
||||
* main thread, depending on whether looper gives up on the transaction
|
||||
* before it gets processed.
|
||||
*
|
||||
* When transaction is blocked by gbinder_remote_request_block() call, it
|
||||
* gets slightly more complicated. Then the main thread writes TX_BLOCKED
|
||||
* to the pipe (rather than TX_DONE) and then looper thread spawn another
|
||||
* looper and keeps waiting for TX_DONE.
|
||||
*/
|
||||
|
||||
#define TX_DONE (0x2a)
|
||||
#define TX_BLOCKED (0x3b)
|
||||
|
||||
typedef struct gbinder_ipc_looper_tx {
|
||||
typedef enum gbinder_ipc_looper_tx_state {
|
||||
GBINDER_IPC_LOOPER_TX_SCHEDULED,
|
||||
GBINDER_IPC_LOOPER_TX_PROCESSING,
|
||||
GBINDER_IPC_LOOPER_TX_PROCESSED,
|
||||
GBINDER_IPC_LOOPER_TX_BLOCKING,
|
||||
GBINDER_IPC_LOOPER_TX_BLOCKED,
|
||||
GBINDER_IPC_LOOPER_TX_COMPLETE
|
||||
} GBINDER_IPC_LOOPER_TX_STATE;
|
||||
|
||||
struct gbinder_ipc_looper_tx {
|
||||
/* Reference count */
|
||||
gint refcount;
|
||||
/* These are filled by the looper: */
|
||||
@@ -125,19 +140,23 @@ typedef struct gbinder_ipc_looper_tx {
|
||||
GBinderLocalObject* obj;
|
||||
GBinderRemoteRequest* req;
|
||||
/* And these by the main thread processing the transaction: */
|
||||
GBINDER_IPC_LOOPER_TX_STATE state;
|
||||
GBinderLocalReply* reply;
|
||||
int status;
|
||||
} GBinderIpcLooperTx;
|
||||
} /* GBinderIpcLooperTx */;
|
||||
|
||||
struct gbinder_ipc_looper {
|
||||
gint refcount;
|
||||
GBinderIpcLooper* next;
|
||||
char* name;
|
||||
GBinderHandler handler;
|
||||
GBinderDriver* driver;
|
||||
GBinderIpc* ipc; /* Not a reference! */
|
||||
GThread* thread;
|
||||
GMutex mutex;
|
||||
GCond start_cond;
|
||||
gboolean started;
|
||||
gint exit;
|
||||
gint started;
|
||||
int pipefd[2];
|
||||
int txfd[2];
|
||||
};
|
||||
@@ -178,6 +197,11 @@ typedef struct gbinder_ipc_tx_custom {
|
||||
GBINDER_INLINE_FUNC const char* gbinder_ipc_name(GBinderIpc* self)
|
||||
{ return gbinder_driver_dev(self->driver); }
|
||||
|
||||
static
|
||||
GBinderIpcLooper*
|
||||
gbinder_ipc_looper_new(
|
||||
GBinderIpc* ipc);
|
||||
|
||||
/*==========================================================================*
|
||||
* GBinderIpcLooperTx
|
||||
*==========================================================================*/
|
||||
@@ -245,6 +269,91 @@ gbinder_ipc_looper_tx_unref(
|
||||
return dropped;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* State machine of transaction handling. All this is happening on the event
|
||||
* thread and therefore doesn't need to be synchronized.
|
||||
*
|
||||
* SCHEDULED
|
||||
* =========
|
||||
* |
|
||||
* PROCESSING
|
||||
* ==========
|
||||
* |
|
||||
* --------------------- handler is called ---------------------------------
|
||||
* |
|
||||
* +---------------- request doesn't need to be blocked ----------+
|
||||
* | |
|
||||
* gbinder_remote_request_block() |
|
||||
* | |
|
||||
* BLOCKING -- gbinder_remote_request_complete() --> PROCESSED |
|
||||
* ======== ========= |
|
||||
* | | |
|
||||
* --------------------- handler returns -----------------------------------
|
||||
* | | |
|
||||
* BLOCKED COMPLETE <-------+
|
||||
* ======= ========
|
||||
* ^
|
||||
* ... |
|
||||
* gbinder_remote_request_complete() is called later ----+
|
||||
*==========================================================================*/
|
||||
|
||||
void
|
||||
gbinder_remote_request_block(
|
||||
GBinderRemoteRequest* req) /* Since 1.0.20 */
|
||||
{
|
||||
if (G_LIKELY(req)) {
|
||||
GBinderIpcLooperTx* tx = req->tx;
|
||||
|
||||
GASSERT(tx);
|
||||
if (G_LIKELY(tx)) {
|
||||
GASSERT(tx->state == GBINDER_IPC_LOOPER_TX_PROCESSING);
|
||||
if (tx->state == GBINDER_IPC_LOOPER_TX_PROCESSING) {
|
||||
tx->state = GBINDER_IPC_LOOPER_TX_BLOCKING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_request_complete(
|
||||
GBinderRemoteRequest* req,
|
||||
GBinderLocalReply* reply,
|
||||
int status) /* Since 1.0.20 */
|
||||
{
|
||||
if (G_LIKELY(req)) {
|
||||
GBinderIpcLooperTx* tx = req->tx;
|
||||
|
||||
GASSERT(tx);
|
||||
if (G_LIKELY(tx)) {
|
||||
const guint8 done = TX_DONE;
|
||||
|
||||
switch (tx->state) {
|
||||
case GBINDER_IPC_LOOPER_TX_BLOCKING:
|
||||
/* Called by the transaction handler */
|
||||
tx->status = status;
|
||||
tx->reply = gbinder_local_reply_ref(reply);
|
||||
tx->state = GBINDER_IPC_LOOPER_TX_PROCESSED;
|
||||
break;
|
||||
case GBINDER_IPC_LOOPER_TX_BLOCKED:
|
||||
/* Really asynchronous completion */
|
||||
tx->status = status;
|
||||
tx->reply = gbinder_local_reply_ref(reply);
|
||||
tx->state = GBINDER_IPC_LOOPER_TX_COMPLETE;
|
||||
/* Wake up the looper */
|
||||
(void)write(tx->pipefd[1], &done, sizeof(done));
|
||||
break;
|
||||
default:
|
||||
GWARN("Unexpected state %d in request completion", tx->state);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clear the transaction reference */
|
||||
gbinder_ipc_looper_tx_unref(tx, FALSE);
|
||||
req->tx = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* GBinderIpcLooper
|
||||
*==========================================================================*/
|
||||
@@ -255,11 +364,70 @@ gbinder_ipc_looper_tx_handle(
|
||||
gpointer data)
|
||||
{
|
||||
GBinderIpcLooperTx* tx = data;
|
||||
guint8 done = TX_DONE;
|
||||
GBinderRemoteRequest* req = tx->req;
|
||||
GBinderLocalReply* reply;
|
||||
int status = GBINDER_STATUS_OK;
|
||||
guint8 done;
|
||||
|
||||
/*
|
||||
* Transaction reference for gbinder_remote_request_block()
|
||||
* and gbinder_remote_request_complete().
|
||||
*/
|
||||
req->tx = gbinder_ipc_looper_tx_ref(tx);
|
||||
|
||||
/* See state machine */
|
||||
GASSERT(tx->state == GBINDER_IPC_LOOPER_TX_SCHEDULED);
|
||||
tx->state = GBINDER_IPC_LOOPER_TX_PROCESSING;
|
||||
|
||||
/* Actually handle the transaction */
|
||||
tx->reply = gbinder_local_object_handle_transaction(tx->obj, tx->req,
|
||||
tx->code, tx->flags, &tx->status);
|
||||
reply = gbinder_local_object_handle_transaction(tx->obj, req,
|
||||
tx->code, tx->flags, &status);
|
||||
|
||||
/* Handle all possible return states */
|
||||
switch (tx->state) {
|
||||
case GBINDER_IPC_LOOPER_TX_PROCESSING:
|
||||
/* Result was returned by the handler */
|
||||
tx->reply = reply;
|
||||
tx->status = status;
|
||||
tx->state = GBINDER_IPC_LOOPER_TX_COMPLETE;
|
||||
reply = NULL;
|
||||
break;
|
||||
case GBINDER_IPC_LOOPER_TX_PROCESSED:
|
||||
/* Result has been provided to gbinder_remote_request_complete() */
|
||||
tx->state = GBINDER_IPC_LOOPER_TX_COMPLETE;
|
||||
break;
|
||||
case GBINDER_IPC_LOOPER_TX_BLOCKING:
|
||||
/* Result will be provided to gbinder_remote_request_complete() */
|
||||
tx->state = GBINDER_IPC_LOOPER_TX_BLOCKED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* In case handler returns a reply which it wasn't expected to return */
|
||||
GASSERT(!reply);
|
||||
gbinder_local_reply_unref(reply);
|
||||
|
||||
/* Drop the transaction reference unless blocked */
|
||||
if (tx->state == GBINDER_IPC_LOOPER_TX_BLOCKED) {
|
||||
done = TX_BLOCKED;
|
||||
/*
|
||||
* From this point on, it's GBinderRemoteRequest who's holding
|
||||
* reference to GBinderIpcLooperTx, not the other way around and
|
||||
* not both ways. Even if gbinder_remote_request_complete() never
|
||||
* gets called, transaction will still be completed when the last
|
||||
* reference to GBinderRemoteRequest goes away. And if request
|
||||
* never gets deallocated... oh well.
|
||||
*/
|
||||
gbinder_remote_request_unref(tx->req);
|
||||
tx->req = NULL;
|
||||
} else {
|
||||
done = TX_DONE;
|
||||
if (req->tx) {
|
||||
gbinder_ipc_looper_tx_unref(req->tx, FALSE);
|
||||
req->tx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* And wake up the looper */
|
||||
(void)write(tx->pipefd[1], &done, sizeof(done));
|
||||
@@ -274,6 +442,52 @@ gbinder_ipc_looper_tx_done(
|
||||
gbinder_ipc_looper_tx_unref(data, FALSE);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_ipc_looper_remove_from_list(
|
||||
GBinderIpcLooper* looper,
|
||||
GBinderIpcLooper** list)
|
||||
{
|
||||
/* Caller holds looper_mutex */
|
||||
if (*list) {
|
||||
if ((*list) == looper) {
|
||||
(*list) = looper->next;
|
||||
looper->next = NULL;
|
||||
return TRUE;
|
||||
} else {
|
||||
GBinderIpcLooper* prev = (*list);
|
||||
|
||||
while (prev->next) {
|
||||
if (prev->next == looper) {
|
||||
prev->next = looper->next;
|
||||
looper->next = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
prev = prev->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_ipc_looper_remove_primary(
|
||||
GBinderIpcLooper* looper)
|
||||
{
|
||||
return gbinder_ipc_looper_remove_from_list(looper,
|
||||
&looper->ipc->priv->primary_loopers);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_ipc_looper_remove_blocked(
|
||||
GBinderIpcLooper* looper)
|
||||
{
|
||||
return gbinder_ipc_looper_remove_from_list(looper,
|
||||
&looper->ipc->priv->blocked_loopers);
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
gbinder_ipc_looper_transact(
|
||||
@@ -318,11 +532,65 @@ gbinder_ipc_looper_transact(
|
||||
if ((fds[1].revents & POLLIN) &&
|
||||
read(fds[1].fd, &done, sizeof(done)) == 1) {
|
||||
/* Normal completion */
|
||||
if (done == TX_BLOCKED) {
|
||||
/*
|
||||
* We are going to block this looper for potentially
|
||||
* significant period of time. Start new looper to
|
||||
* accept normal incoming requests and terminate this
|
||||
* one when we are done with this transaction.
|
||||
*
|
||||
* For the duration of the transaction, this looper is
|
||||
* moved to the blocked_loopers list.
|
||||
*/
|
||||
GBinderIpcPriv* priv = looper->ipc->priv;
|
||||
|
||||
/* Lock */
|
||||
g_mutex_lock(&priv->looper_mutex);
|
||||
if (gbinder_ipc_looper_remove_primary(looper)) {
|
||||
GBinderIpcLooper* new_looper;
|
||||
|
||||
GDEBUG("Primary looper %s is blocked", looper->name);
|
||||
looper->next = priv->blocked_loopers;
|
||||
priv->blocked_loopers = looper;
|
||||
|
||||
/* Looper will exit once transaction completes */
|
||||
g_atomic_int_set(&looper->exit, 1);
|
||||
|
||||
/* Create new primary looper to replace this one */
|
||||
new_looper = gbinder_ipc_looper_new(ipc);
|
||||
if (new_looper) {
|
||||
new_looper->next = priv->primary_loopers;
|
||||
priv->primary_loopers = new_looper;
|
||||
}
|
||||
}
|
||||
g_mutex_unlock(&priv->looper_mutex);
|
||||
/* Unlock */
|
||||
|
||||
/* Block until asynchronous transaction gets completed. */
|
||||
done = 0;
|
||||
memset(fds, 0, sizeof(fds));
|
||||
fds[0].fd = looper->pipefd[0];
|
||||
fds[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
|
||||
fds[1].fd = tx->pipefd[0];
|
||||
fds[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
|
||||
poll(fds, 2, -1);
|
||||
if ((fds[1].revents & POLLIN) &&
|
||||
read(fds[1].fd, &done, sizeof(done)) == 1) {
|
||||
GASSERT(done == TX_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
GASSERT(done == TX_DONE);
|
||||
reply = gbinder_local_reply_ref(tx->reply);
|
||||
status = tx->status;
|
||||
if (!gbinder_ipc_looper_tx_unref(tx, TRUE)) {
|
||||
/* gbinder_ipc_looper_tx_free() will close those */
|
||||
/*
|
||||
* This wasn't the last references meaning that
|
||||
* gbinder_ipc_looper_tx_free() will close the
|
||||
* descriptors and we will have to create a new
|
||||
* pipe for the next transaction.
|
||||
*/
|
||||
looper->txfd[0] = looper->txfd[1] = -1;
|
||||
}
|
||||
} else {
|
||||
@@ -348,6 +616,7 @@ gbinder_ipc_looper_free(
|
||||
close(looper->txfd[1]);
|
||||
}
|
||||
gbinder_driver_unref(looper->driver);
|
||||
g_free(looper->name);
|
||||
g_cond_clear(&looper->start_cond);
|
||||
g_mutex_clear(&looper->mutex);
|
||||
g_slice_free(GBinderIpcLooper, looper);
|
||||
@@ -384,11 +653,11 @@ gbinder_ipc_looper_thread(
|
||||
|
||||
if (gbinder_driver_enter_looper(driver)) {
|
||||
struct pollfd pipefd;
|
||||
int result;
|
||||
int res;
|
||||
|
||||
GDEBUG("Looper %s running", gbinder_driver_dev(driver));
|
||||
GDEBUG("Looper %s running", looper->name);
|
||||
g_mutex_lock(&looper->mutex);
|
||||
looper->started = TRUE;
|
||||
g_atomic_int_set(&looper->started, TRUE);
|
||||
g_cond_broadcast(&looper->start_cond);
|
||||
g_mutex_unlock(&looper->mutex);
|
||||
|
||||
@@ -396,31 +665,33 @@ gbinder_ipc_looper_thread(
|
||||
pipefd.fd = looper->pipefd[0]; /* read end of the pipe */
|
||||
pipefd.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
|
||||
|
||||
result = gbinder_driver_poll(driver, &pipefd);
|
||||
while (looper->ipc && ((result & POLLIN) || !result)) {
|
||||
if (result & POLLIN) {
|
||||
/* No need to synchronize access to looper->ipc because
|
||||
res = gbinder_driver_poll(driver, &pipefd);
|
||||
while (!g_atomic_int_get(&looper->exit) && ((res & POLLIN) || !res)) {
|
||||
if (res & POLLIN) {
|
||||
/*
|
||||
* No need to synchronize access to looper->ipc because
|
||||
* the other thread would wait until this thread exits
|
||||
* before setting looper->ipc to NULL */
|
||||
* before setting looper->ipc to NULL.
|
||||
*/
|
||||
GBinderIpc* ipc = gbinder_ipc_ref(looper->ipc);
|
||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||
/* But that gbinder_driver_read() may unref GBinderIpc */
|
||||
int ret = gbinder_driver_read(driver, reg, &looper->handler);
|
||||
|
||||
/* And this gbinder_ipc_unref() may release the last ref: */
|
||||
gbinder_ipc_unref(ipc);
|
||||
/* And at this point looper->ipc may be NULL */
|
||||
if (ret < 0) {
|
||||
GDEBUG("Looper %s failed", gbinder_driver_dev(driver));
|
||||
GDEBUG("Looper %s failed", looper->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pipefd.revents) {
|
||||
/* Any event from this pipe terminates the loop */
|
||||
GDEBUG("Looper %s is asked to exit",
|
||||
gbinder_driver_dev(driver));
|
||||
/* Any event from this pipe terminates the loop */
|
||||
if (pipefd.revents || g_atomic_int_get(&looper->exit)) {
|
||||
GDEBUG("Looper %s is requested to exit", looper->name);
|
||||
break;
|
||||
}
|
||||
result = gbinder_driver_poll(driver, &pipefd);
|
||||
res = gbinder_driver_poll(driver, &pipefd);
|
||||
}
|
||||
|
||||
gbinder_driver_exit_looper(driver);
|
||||
@@ -432,24 +703,26 @@ gbinder_ipc_looper_thread(
|
||||
*/
|
||||
if (looper->ipc) {
|
||||
GBinderIpcPriv* priv = looper->ipc->priv;
|
||||
|
||||
/* Lock */
|
||||
g_mutex_lock(&priv->looper_mutex);
|
||||
if (priv->looper == looper) {
|
||||
if (gbinder_ipc_looper_remove_blocked(looper) ||
|
||||
gbinder_ipc_looper_remove_primary(looper)) {
|
||||
/* Spontaneous exit */
|
||||
priv->looper = NULL;
|
||||
GDEBUG("Looper %s exits", gbinder_driver_dev(driver));
|
||||
GDEBUG("Looper %s exits", looper->name);
|
||||
gbinder_ipc_looper_unref(looper);
|
||||
} else {
|
||||
/* Main thread is shutting it down */
|
||||
GDEBUG("Looper %s done", gbinder_driver_dev(driver));
|
||||
GDEBUG("Looper %s done", looper->name);
|
||||
}
|
||||
g_mutex_unlock(&priv->looper_mutex);
|
||||
/* Unlock */
|
||||
} else {
|
||||
GDEBUG("Looper %s is abandoned", gbinder_driver_dev(driver));
|
||||
GDEBUG("Looper %s is abandoned", looper->name);
|
||||
}
|
||||
} else {
|
||||
g_mutex_lock(&looper->mutex);
|
||||
looper->started = TRUE;
|
||||
g_atomic_int_set(&looper->started, TRUE);
|
||||
g_cond_broadcast(&looper->start_cond);
|
||||
g_mutex_unlock(&looper->mutex);
|
||||
}
|
||||
@@ -472,20 +745,24 @@ gbinder_ipc_looper_new(
|
||||
};
|
||||
GError* error = NULL;
|
||||
GBinderIpcLooper* looper = g_slice_new0(GBinderIpcLooper);
|
||||
static gint gbinder_ipc_next_looper_id = 1;
|
||||
guint id = (guint)g_atomic_int_add(&gbinder_ipc_next_looper_id, 1);
|
||||
|
||||
memcpy(looper->pipefd, fd, sizeof(fd));
|
||||
looper->txfd[0] = looper->txfd[1] = -1;
|
||||
g_atomic_int_set(&looper->refcount, 1);
|
||||
g_cond_init(&looper->start_cond);
|
||||
g_mutex_init(&looper->mutex);
|
||||
looper->name = g_strdup_printf("%s#%u", gbinder_ipc_name(ipc), id);
|
||||
looper->handler.f = &handler_functions;
|
||||
looper->ipc = ipc;
|
||||
looper->driver = gbinder_driver_ref(ipc->driver);
|
||||
looper->thread = g_thread_try_new(gbinder_ipc_name(ipc),
|
||||
looper->thread = g_thread_try_new(looper->name,
|
||||
gbinder_ipc_looper_thread, looper, &error);
|
||||
if (looper->thread) {
|
||||
/* gbinder_ipc_looper_thread() will release this reference: */
|
||||
gbinder_ipc_looper_ref(looper);
|
||||
GDEBUG("Starting looper %s", looper->name);
|
||||
return looper;
|
||||
} else {
|
||||
GERR("Failed to create looper thread: %s", GERRMSG(error));
|
||||
@@ -505,29 +782,29 @@ gbinder_ipc_looper_check(
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderIpcPriv* priv = self->priv;
|
||||
|
||||
if (!priv->looper) {
|
||||
if (!priv->primary_loopers) {
|
||||
GBinderIpcLooper* looper;
|
||||
|
||||
/* Lock */
|
||||
g_mutex_lock(&priv->looper_mutex);
|
||||
if (!priv->looper) {
|
||||
GDEBUG("Starting looper %s", gbinder_ipc_name(self));
|
||||
priv->looper = gbinder_ipc_looper_new(self);
|
||||
looper = priv->primary_loopers;
|
||||
if (!looper) {
|
||||
looper = priv->primary_loopers = gbinder_ipc_looper_new(self);
|
||||
}
|
||||
g_mutex_unlock(&priv->looper_mutex);
|
||||
/* Unlock */
|
||||
|
||||
/* We are not ready to accept incoming transactions until
|
||||
* looper has started. We may need to wait a bit. */
|
||||
looper = priv->looper;
|
||||
if (!looper->started) {
|
||||
if (looper && !g_atomic_int_get(&looper->started)) {
|
||||
/* Lock */
|
||||
g_mutex_lock(&looper->mutex);
|
||||
if (!looper->started) {
|
||||
if (!g_atomic_int_get(&looper->started)) {
|
||||
g_cond_wait_until(&looper->start_cond, &looper->mutex,
|
||||
g_get_monotonic_time() +
|
||||
GBINDER_IPC_LOOPER_START_TIMEOUT_SEC *
|
||||
G_TIME_SPAN_SECOND);
|
||||
GASSERT(looper->started);
|
||||
GASSERT(g_atomic_int_get(&looper->started));
|
||||
}
|
||||
g_mutex_unlock(&looper->mutex);
|
||||
/* Unlock */
|
||||
@@ -536,6 +813,54 @@ gbinder_ipc_looper_check(
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_ipc_looper_stop(
|
||||
GBinderIpcLooper* looper)
|
||||
{
|
||||
/* Caller checks looper for NULL */
|
||||
if (looper->thread && looper->thread != g_thread_self()) {
|
||||
guint8 done = TX_DONE;
|
||||
|
||||
GDEBUG("Stopping looper %s", looper->name);
|
||||
g_atomic_int_set(&looper->exit, TRUE);
|
||||
if (write(looper->pipefd[1], &done, sizeof(done)) <= 0) {
|
||||
looper->thread = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
GBinderIpcLooper*
|
||||
gbinder_ipc_looper_stop_all(
|
||||
GBinderIpcLooper* loopers,
|
||||
GBinderIpcLooper* list)
|
||||
{
|
||||
while (list) {
|
||||
GBinderIpcLooper* looper = list;
|
||||
GBinderIpcLooper* next = looper->next;
|
||||
|
||||
gbinder_ipc_looper_stop(looper);
|
||||
looper->next = loopers;
|
||||
loopers = looper;
|
||||
list = next;
|
||||
}
|
||||
return loopers;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_ipc_looper_join(
|
||||
GBinderIpcLooper* looper)
|
||||
{
|
||||
/* Caller checks looper for NULL */
|
||||
if (looper->thread && looper->thread != g_thread_self()) {
|
||||
g_thread_join(looper->thread);
|
||||
looper->thread = NULL;
|
||||
}
|
||||
looper->ipc = NULL;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* GBinderObjectRegistry
|
||||
*==========================================================================*/
|
||||
@@ -1232,7 +1557,7 @@ gbinder_ipc_dispose(
|
||||
{
|
||||
GBinderIpc* self = GBINDER_IPC(object);
|
||||
GBinderIpcPriv* priv = self->priv;
|
||||
GBinderIpcLooper* looper;
|
||||
GBinderIpcLooper* loopers = NULL;
|
||||
|
||||
GVERBOSE_("%s", self->dev);
|
||||
/* Lock */
|
||||
@@ -1253,22 +1578,19 @@ gbinder_ipc_dispose(
|
||||
|
||||
/* Lock */
|
||||
g_mutex_lock(&priv->looper_mutex);
|
||||
looper = priv->looper;
|
||||
priv->looper = NULL;
|
||||
loopers = gbinder_ipc_looper_stop_all(loopers, priv->primary_loopers);
|
||||
loopers = gbinder_ipc_looper_stop_all(loopers, priv->blocked_loopers);
|
||||
priv->blocked_loopers = NULL;
|
||||
priv->primary_loopers = NULL;
|
||||
g_mutex_unlock(&priv->looper_mutex);
|
||||
/* Unlock */
|
||||
|
||||
if (looper) {
|
||||
if (looper->thread && looper->thread != g_thread_self()) {
|
||||
guint8 done = TX_DONE;
|
||||
while (loopers) {
|
||||
GBinderIpcLooper* looper = loopers;
|
||||
|
||||
GDEBUG("Stopping looper %s", gbinder_ipc_name(looper->ipc));
|
||||
if (write(looper->pipefd[1], &done, sizeof(done)) > 0) {
|
||||
g_thread_join(looper->thread);
|
||||
looper->thread = NULL;
|
||||
}
|
||||
}
|
||||
looper->ipc = NULL;
|
||||
loopers = looper->next;
|
||||
looper->next = NULL;
|
||||
gbinder_ipc_looper_join(looper);
|
||||
gbinder_ipc_looper_unref(looper);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -13,9 +13,9 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -286,7 +286,7 @@ gbinder_local_object_new(
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* user_data)
|
||||
{
|
||||
/* Should only be called from gbinder_ipc_new_local_local_object() */
|
||||
/* Should only be called from gbinder_ipc_new_local_object() */
|
||||
if (G_LIKELY(ipc)) {
|
||||
GBinderLocalObject* self = g_object_new
|
||||
(GBINDER_TYPE_LOCAL_OBJECT, NULL);
|
||||
|
||||
@@ -95,14 +95,13 @@ gbinder_local_reply_new(
|
||||
|
||||
GBinderLocalReply*
|
||||
gbinder_local_reply_new_from_data(
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderBuffer* buffer)
|
||||
{
|
||||
const GBinderIo* io = gbinder_buffer_io(buffer);
|
||||
GBinderLocalReply* self = gbinder_local_reply_new(io);
|
||||
|
||||
if (self) {
|
||||
gbinder_writer_data_set_contents(&self->data, buffer, objects);
|
||||
gbinder_writer_data_set_contents(&self->data, buffer);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -47,8 +47,7 @@ gbinder_local_reply_data(
|
||||
|
||||
GBinderLocalReply*
|
||||
gbinder_local_reply_new_from_data(
|
||||
GBinderBuffer* buffer,
|
||||
void** objects);
|
||||
GBinderBuffer* buffer);
|
||||
|
||||
#endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ struct gbinder_local_request {
|
||||
gint refcount;
|
||||
GBinderWriterData data;
|
||||
GBinderOutputData out;
|
||||
GBinderBufferMemory* memory;
|
||||
};
|
||||
|
||||
GBINDER_INLINE_FUNC
|
||||
@@ -106,14 +105,13 @@ gbinder_local_request_new(
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_local_request_new_from_data(
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderBuffer* buffer)
|
||||
{
|
||||
GBinderLocalRequest* self = gbinder_local_request_new
|
||||
(gbinder_buffer_io(buffer), NULL);
|
||||
|
||||
if (self) {
|
||||
gbinder_writer_data_set_contents(&self->data, buffer, objects);
|
||||
gbinder_writer_data_set_contents(&self->data, buffer);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -128,7 +126,6 @@ gbinder_local_request_free(
|
||||
g_byte_array_free(data->bytes, TRUE);
|
||||
gutil_int_array_free(data->offsets, TRUE);
|
||||
gbinder_cleanup_free(data->cleanup);
|
||||
gbinder_buffer_memory_unref(self->memory);
|
||||
g_slice_free(GBinderLocalRequest, self);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,7 @@ gbinder_local_request_data(
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_local_request_new_from_data(
|
||||
GBinderBuffer* buffer,
|
||||
void** objects);
|
||||
GBinderBuffer* buffer);
|
||||
|
||||
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -38,6 +38,9 @@
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
typedef struct gbinder_reader_priv {
|
||||
const guint8* start;
|
||||
const guint8* end;
|
||||
@@ -50,6 +53,8 @@ G_STATIC_ASSERT(sizeof(GBinderReader) >= sizeof(GBinderReaderPriv));
|
||||
|
||||
static inline GBinderReaderPriv* gbinder_reader_cast(GBinderReader* reader)
|
||||
{ return (GBinderReaderPriv*)reader; }
|
||||
static inline const GBinderReaderPriv* gbinder_reader_cast_c
|
||||
(const GBinderReader* reader) { return (GBinderReaderPriv*)reader; }
|
||||
|
||||
void
|
||||
gbinder_reader_init(
|
||||
@@ -81,9 +86,9 @@ gbinder_reader_init(
|
||||
|
||||
gboolean
|
||||
gbinder_reader_at_end(
|
||||
GBinderReader* reader)
|
||||
const GBinderReader* reader)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
|
||||
|
||||
return p->ptr >= p->end;
|
||||
}
|
||||
@@ -229,16 +234,67 @@ gbinder_reader_read_double(
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
gboolean
|
||||
gbinder_reader_can_read_object(
|
||||
GBinderReaderPriv* p)
|
||||
{
|
||||
const GBinderReaderData* data = p->data;
|
||||
|
||||
return data && data->reg &&
|
||||
p->objects && p->objects[0] &&
|
||||
p->ptr == p->objects[0];
|
||||
}
|
||||
|
||||
int
|
||||
gbinder_reader_read_fd(
|
||||
GBinderReader* reader) /* Since 1.0.18 */
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
|
||||
if (gbinder_reader_can_read_object(p)) {
|
||||
int fd;
|
||||
const guint eaten = p->data->reg->io->decode_fd_object(p->ptr,
|
||||
gbinder_reader_bytes_remaining(reader), &fd);
|
||||
|
||||
if (eaten) {
|
||||
GASSERT(fd >= 0);
|
||||
p->ptr += eaten;
|
||||
p->objects++;
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
gbinder_reader_read_dup_fd(
|
||||
GBinderReader* reader) /* Since 1.0.18 */
|
||||
{
|
||||
const int fd = gbinder_reader_read_fd(reader);
|
||||
|
||||
if (fd >= 0) {
|
||||
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||
|
||||
if (dupfd >= 0) {
|
||||
return dupfd;
|
||||
} else {
|
||||
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_nullable_object(
|
||||
GBinderReader* reader,
|
||||
GBinderRemoteObject** out)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderData* data = p->data;
|
||||
|
||||
if (data && data->reg && p->objects && p->objects[0] &&
|
||||
p->ptr == p->objects[0]) {
|
||||
if (gbinder_reader_can_read_object(p)) {
|
||||
const GBinderReaderData* data = p->data;
|
||||
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
|
||||
gbinder_reader_bytes_remaining(reader), data->reg, out);
|
||||
|
||||
@@ -264,15 +320,14 @@ gbinder_reader_read_object(
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_reader_read_buffer_impl(
|
||||
gbinder_reader_read_buffer_object(
|
||||
GBinderReader* reader,
|
||||
GBinderBuffer** out)
|
||||
GBinderIoBufferObject* out)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderData* data = p->data;
|
||||
|
||||
if (data && data->reg && p->objects && p->objects[0] &&
|
||||
p->ptr == p->objects[0]) {
|
||||
if (gbinder_reader_can_read_object(p)) {
|
||||
const GBinderReaderData* data = p->data;
|
||||
GBinderBuffer* buf = data->buffer;
|
||||
const GBinderIo* io = data->reg->io;
|
||||
const gsize offset = p->ptr - (guint8*)buf->data;
|
||||
@@ -284,7 +339,6 @@ gbinder_reader_read_buffer_impl(
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if (out) *out = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -292,34 +346,36 @@ GBinderBuffer*
|
||||
gbinder_reader_read_buffer(
|
||||
GBinderReader* reader)
|
||||
{
|
||||
GBinderBuffer* buf = NULL;
|
||||
GBinderIoBufferObject obj;
|
||||
|
||||
gbinder_reader_read_buffer_impl(reader, &buf);
|
||||
return buf;
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj)) {
|
||||
const GBinderReaderData* data = gbinder_reader_cast(reader)->data;
|
||||
GBinderBuffer* buf = data->buffer;
|
||||
|
||||
return gbinder_buffer_new_with_parent(buf, obj.data, obj.size);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_reader_skip_buffer(
|
||||
GBinderReader* reader)
|
||||
{
|
||||
return gbinder_reader_read_buffer_impl(reader, NULL);
|
||||
return gbinder_reader_read_buffer_object(reader, NULL);
|
||||
}
|
||||
|
||||
/* Helper for gbinder_reader_read_hidl_struct() macro */
|
||||
const void*
|
||||
gbinder_reader_read_hidl_struct1(
|
||||
GBinderReader* reader,
|
||||
gsize size) /* since 1.0.9 */
|
||||
gsize size) /* Since 1.0.9 */
|
||||
{
|
||||
const void* result = NULL;
|
||||
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
|
||||
GBinderIoBufferObject obj;
|
||||
|
||||
/* Check the size */
|
||||
if (buf && buf->size == size) {
|
||||
result = buf->data;
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) && obj.size == size) {
|
||||
return obj.data;
|
||||
}
|
||||
gbinder_buffer_free(buf);
|
||||
return result;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Doesn't copy the data */
|
||||
@@ -329,30 +385,28 @@ gbinder_reader_read_hidl_vec(
|
||||
gsize* count,
|
||||
gsize* elemsize)
|
||||
{
|
||||
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
|
||||
gsize out_count = 0, out_elemsize = 0;
|
||||
GBinderIoBufferObject obj;
|
||||
const void* out = NULL;
|
||||
gsize out_count = 0, out_elemsize = 0;
|
||||
|
||||
if (buf && buf->size == sizeof(HidlVec)) {
|
||||
const HidlVec* vec = buf->data;
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.data && obj.size == sizeof(GBinderHidlVec)) {
|
||||
const GBinderHidlVec* vec = obj.data;
|
||||
const void* next = vec->data.ptr;
|
||||
|
||||
if (next) {
|
||||
GBinderBuffer* vbuf = gbinder_reader_read_buffer(reader);
|
||||
|
||||
if (vbuf && vbuf->data == next && ((!vec->count && !vbuf->size) ||
|
||||
(vec->count && vbuf->size && !(vbuf->size % vec->count)))) {
|
||||
out_elemsize = vec->count ? (vbuf->size / vec->count) : 0;
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.data == next && ((!vec->count && !obj.size) ||
|
||||
(vec->count && obj.size && !(obj.size % vec->count)))) {
|
||||
out_elemsize = vec->count ? (obj.size / vec->count) : 0;
|
||||
out_count = vec->count;
|
||||
out = vbuf->data;
|
||||
out = obj.data;
|
||||
}
|
||||
gbinder_buffer_free(vbuf);
|
||||
} else if (!vec->count) {
|
||||
/* Any non-NULL pointer just to indicate success */
|
||||
/* Any non-NULL pointer just to indicate success? */
|
||||
out = vec;
|
||||
}
|
||||
}
|
||||
gbinder_buffer_free(buf);
|
||||
if (elemsize) {
|
||||
*elemsize = out_elemsize;
|
||||
}
|
||||
@@ -367,7 +421,7 @@ const void*
|
||||
gbinder_reader_read_hidl_vec1(
|
||||
GBinderReader* reader,
|
||||
gsize* count,
|
||||
guint expected_elem_size) /* since 1.0.9 */
|
||||
guint expected_elem_size) /* Since 1.0.9 */
|
||||
{
|
||||
gsize actual;
|
||||
const void* data = gbinder_reader_read_hidl_vec(reader, count, &actual);
|
||||
@@ -376,88 +430,94 @@ gbinder_reader_read_hidl_vec1(
|
||||
return (data && (actual == expected_elem_size || !actual)) ? data : NULL;
|
||||
}
|
||||
|
||||
const char*
|
||||
gbinder_reader_read_hidl_string_c(
|
||||
GBinderReader* reader) /* Since 1.0.23 */
|
||||
{
|
||||
GBinderIoBufferObject obj;
|
||||
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.data && obj.size == sizeof(GBinderHidlString)) {
|
||||
const GBinderHidlString* str = obj.data;
|
||||
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.has_parent &&
|
||||
obj.parent_offset == GBINDER_HIDL_STRING_BUFFER_OFFSET &&
|
||||
obj.data == str->data.str &&
|
||||
obj.size == str->len + 1 &&
|
||||
str->data.str[str->len] == 0) {
|
||||
return str->data.str;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char*
|
||||
gbinder_reader_read_hidl_string(
|
||||
GBinderReader* reader)
|
||||
{
|
||||
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
|
||||
char* str = NULL;
|
||||
|
||||
if (buf && buf->size == sizeof(HidlString)) {
|
||||
const HidlString* s = buf->data;
|
||||
GBinderBuffer* sbuf = gbinder_reader_read_buffer(reader);
|
||||
|
||||
if (sbuf && sbuf->size == s->len + 1 &&
|
||||
sbuf->data == s->data.str &&
|
||||
s->data.str[s->len] == 0) {
|
||||
str = g_strdup(s->data.str);
|
||||
}
|
||||
gbinder_buffer_free(sbuf);
|
||||
}
|
||||
gbinder_buffer_free(buf);
|
||||
return str;
|
||||
/* This function should've been called gbinder_reader_dup_hidl_string */
|
||||
return g_strdup(gbinder_reader_read_hidl_string_c(reader));
|
||||
}
|
||||
|
||||
char**
|
||||
gbinder_reader_read_hidl_string_vec(
|
||||
GBinderReader* reader)
|
||||
{
|
||||
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
|
||||
GBinderIoBufferObject obj;
|
||||
|
||||
/* First buffer contains hidl_vector */
|
||||
if (buf && buf->size == sizeof(HidlVec)) {
|
||||
HidlVec* vec = buf->data;
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.data && obj.size == sizeof(GBinderHidlVec)) {
|
||||
GBinderHidlVec* vec = obj.data;
|
||||
const guint n = vec->count;
|
||||
const void* next = vec->data.ptr;
|
||||
|
||||
gbinder_buffer_free(buf);
|
||||
if (!next && !n) {
|
||||
char** out = g_new(char*, 1);
|
||||
/* Should this be considered an error? */
|
||||
return g_new0(char*, 1);
|
||||
} else if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
/* The second buffer (if any) contains n hidl_string's */
|
||||
obj.parent_offset == GBINDER_HIDL_VEC_BUFFER_OFFSET &&
|
||||
obj.has_parent &&
|
||||
obj.data == next &&
|
||||
obj.size == (sizeof(GBinderHidlString) * n)) {
|
||||
const GBinderHidlString* strings = obj.data;
|
||||
GPtrArray* list = g_ptr_array_sized_new(n + 1);
|
||||
guint i;
|
||||
|
||||
out[0] = NULL;
|
||||
return out;
|
||||
} else {
|
||||
/* The second buffer (if any) contains n hidl_string's */
|
||||
buf = gbinder_reader_read_buffer(reader);
|
||||
if (buf && buf->data == next && buf->size == sizeof(HidlString)*n) {
|
||||
const HidlString* strings = buf->data;
|
||||
GBinderBuffer* sbuf;
|
||||
GPtrArray* list = g_ptr_array_new();
|
||||
guint i;
|
||||
/* Now we expect n buffers containing the actual data */
|
||||
for (i = 0; i < n &&
|
||||
gbinder_reader_read_buffer_object(reader, &obj); i++) {
|
||||
const GBinderHidlString* s = strings + i;
|
||||
const gsize expected_offset = (i * sizeof(*s)) +
|
||||
GBINDER_HIDL_STRING_BUFFER_OFFSET;
|
||||
if (obj.has_parent &&
|
||||
obj.parent_offset == expected_offset &&
|
||||
obj.data == s->data.str &&
|
||||
obj.size == s->len + 1 &&
|
||||
s->data.str[s->len] == 0) {
|
||||
char* name = g_strdup(s->data.str);
|
||||
|
||||
/* Now we expect n buffers containing the actual data */
|
||||
for (i=0; i<n &&
|
||||
(sbuf = gbinder_reader_read_buffer(reader)); i++) {
|
||||
const HidlString* s = strings + i;
|
||||
if (sbuf->size == s->len + 1 &&
|
||||
sbuf->data == s->data.str &&
|
||||
s->data.str[s->len] == 0) {
|
||||
char* name = g_strdup(s->data.str);
|
||||
|
||||
g_ptr_array_add(list, name);
|
||||
GVERBOSE_("%u. %s", i + 1, name);
|
||||
gbinder_buffer_free(sbuf);
|
||||
} else {
|
||||
GWARN("Unexpected hidl_string buffer %p/%u vs %p/%u",
|
||||
sbuf->data, (guint)sbuf->size, s->data.str, s->len);
|
||||
gbinder_buffer_free(sbuf);
|
||||
break;
|
||||
}
|
||||
g_ptr_array_add(list, name);
|
||||
GVERBOSE_("%u. %s", i + 1, name);
|
||||
} else {
|
||||
GWARN("Unexpected hidl_string buffer %p/%u vs %p/%u",
|
||||
obj.data, (guint)obj.size, s->data.str, s->len);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == n) {
|
||||
gbinder_buffer_free(buf);
|
||||
g_ptr_array_add(list, NULL);
|
||||
return (char**)g_ptr_array_free(list, FALSE);
|
||||
}
|
||||
|
||||
g_ptr_array_set_free_func(list, g_free);
|
||||
g_ptr_array_free(list, TRUE);
|
||||
}
|
||||
|
||||
if (i == n) {
|
||||
g_ptr_array_add(list, NULL);
|
||||
return (char**)g_ptr_array_free(list, FALSE);
|
||||
}
|
||||
|
||||
g_ptr_array_set_free_func(list, g_free);
|
||||
g_ptr_array_free(list, TRUE);
|
||||
}
|
||||
}
|
||||
GWARN("Invalid hidl_vec<string>");
|
||||
gbinder_buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -489,6 +549,24 @@ gboolean
|
||||
gbinder_reader_read_nullable_string16(
|
||||
GBinderReader* reader,
|
||||
char** out)
|
||||
{
|
||||
gunichar2* str;
|
||||
gsize len;
|
||||
|
||||
if (gbinder_reader_read_nullable_string16_utf16(reader, &str, &len)) {
|
||||
if (out) {
|
||||
*out = str ? g_utf16_to_utf8(str, len, NULL, NULL, NULL) : NULL;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_nullable_string16_utf16(
|
||||
GBinderReader* reader,
|
||||
gunichar2** out,
|
||||
gsize* out_len) /* Since 1.0.17 */
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
|
||||
@@ -502,15 +580,21 @@ gbinder_reader_read_nullable_string16(
|
||||
if (out) {
|
||||
*out = NULL;
|
||||
}
|
||||
if (out_len) {
|
||||
*out_len = 0;
|
||||
}
|
||||
return TRUE;
|
||||
} else if (len >= 0) {
|
||||
const guint32 padded_len = G_ALIGN4((len+1)*2);
|
||||
const gunichar2* utf16 = (const gunichar2*)(p->ptr + 4);
|
||||
const guint32 padded_len = G_ALIGN4((len + 1)*2);
|
||||
gunichar2* utf16 = (gunichar2*)(p->ptr + 4);
|
||||
|
||||
if ((p->ptr + padded_len + 4) <= p->end) {
|
||||
p->ptr += padded_len + 4;
|
||||
if (out) {
|
||||
*out = g_utf16_to_utf8(utf16, len, NULL, NULL, NULL);
|
||||
*out = utf16;
|
||||
}
|
||||
if (out_len) {
|
||||
*out_len = len;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -558,7 +642,7 @@ gbinder_reader_skip_string16(
|
||||
const void*
|
||||
gbinder_reader_read_byte_array(
|
||||
GBinderReader* reader,
|
||||
gsize* len) /* since 1.0.12 */
|
||||
gsize* len) /* Since 1.0.12 */
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const void* data = NULL;
|
||||
@@ -583,22 +667,31 @@ gbinder_reader_read_byte_array(
|
||||
|
||||
gsize
|
||||
gbinder_reader_bytes_read(
|
||||
GBinderReader* reader)
|
||||
const GBinderReader* reader)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
|
||||
|
||||
return p->ptr - p->start;
|
||||
}
|
||||
|
||||
gsize
|
||||
gbinder_reader_bytes_remaining(
|
||||
GBinderReader* reader)
|
||||
const GBinderReader* reader)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
|
||||
|
||||
return p->end - p->ptr;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_reader_copy(
|
||||
GBinderReader* dest,
|
||||
const GBinderReader* src)
|
||||
{
|
||||
/* It's actually quite simple :) */
|
||||
memcpy(dest, src, sizeof(*dest));
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "gbinder_local_reply_p.h"
|
||||
#include "gbinder_reader_p.h"
|
||||
#include "gbinder_object_registry.h"
|
||||
#include "gbinder_buffer.h"
|
||||
#include "gbinder_buffer_p.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_macros.h>
|
||||
@@ -65,26 +65,22 @@ gbinder_remote_reply_free(
|
||||
|
||||
gbinder_object_registry_unref(data->reg);
|
||||
gbinder_buffer_free(data->buffer);
|
||||
g_free(data->objects);
|
||||
g_slice_free(GBinderRemoteReply, self);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_reply_set_data(
|
||||
GBinderRemoteReply* self,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderBuffer* buffer)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReaderData* data = &self->data;
|
||||
|
||||
g_free(data->objects);
|
||||
gbinder_buffer_free(data->buffer);
|
||||
data->buffer = buffer;
|
||||
data->objects = objects;
|
||||
data->objects = gbinder_buffer_objects(buffer);
|
||||
} else {
|
||||
gbinder_buffer_free(buffer);
|
||||
g_free(objects);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +121,7 @@ gbinder_remote_reply_copy_to_local(
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReaderData* d = &self->data;
|
||||
|
||||
return gbinder_local_reply_new_from_data(d->buffer, d->objects);
|
||||
return gbinder_local_reply_new_from_data(d->buffer);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -44,8 +44,7 @@ gbinder_remote_reply_new(
|
||||
void
|
||||
gbinder_remote_reply_set_data(
|
||||
GBinderRemoteReply* reply,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects);
|
||||
GBinderBuffer* buffer);
|
||||
|
||||
gboolean
|
||||
gbinder_remote_reply_is_empty(
|
||||
|
||||
@@ -35,12 +35,15 @@
|
||||
#include "gbinder_rpc_protocol.h"
|
||||
#include "gbinder_local_request_p.h"
|
||||
#include "gbinder_object_registry.h"
|
||||
#include "gbinder_buffer.h"
|
||||
#include "gbinder_buffer_p.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
struct gbinder_remote_request {
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct gbinder_remote_request_priv {
|
||||
GBinderRemoteRequest pub;
|
||||
gint refcount;
|
||||
pid_t pid;
|
||||
uid_t euid;
|
||||
@@ -49,7 +52,11 @@ struct gbinder_remote_request {
|
||||
char* iface2;
|
||||
gsize header_size;
|
||||
GBinderReaderData data;
|
||||
};
|
||||
} GBinderRemoteRequestPriv;
|
||||
|
||||
GBINDER_INLINE_FUNC GBinderRemoteRequestPriv*
|
||||
gbinder_remote_request_cast(GBinderRemoteRequest* pub)
|
||||
{ return G_LIKELY(pub) ? G_CAST(pub,GBinderRemoteRequestPriv,pub) : NULL; }
|
||||
|
||||
GBinderRemoteRequest*
|
||||
gbinder_remote_request_new(
|
||||
@@ -58,7 +65,7 @@ gbinder_remote_request_new(
|
||||
pid_t pid,
|
||||
uid_t euid)
|
||||
{
|
||||
GBinderRemoteRequest* self = g_slice_new0(GBinderRemoteRequest);
|
||||
GBinderRemoteRequestPriv* self = g_slice_new0(GBinderRemoteRequestPriv);
|
||||
GBinderReaderData* data = &self->data;
|
||||
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
@@ -66,17 +73,19 @@ gbinder_remote_request_new(
|
||||
self->euid = euid;
|
||||
self->protocol = protocol;
|
||||
data->reg = gbinder_object_registry_ref(reg);
|
||||
return self;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_remote_request_copy_to_local(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReaderData* d = &self->data;
|
||||
|
||||
return gbinder_local_request_new_from_data(d->buffer, d->objects);
|
||||
return gbinder_local_request_new_from_data(d->buffer);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -84,22 +93,27 @@ gbinder_remote_request_copy_to_local(
|
||||
static
|
||||
void
|
||||
gbinder_remote_request_free(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequestPriv* self)
|
||||
{
|
||||
GBinderReaderData* data = &self->data;
|
||||
GBinderRemoteRequest* req = &self->pub;
|
||||
|
||||
GASSERT(!req->tx);
|
||||
if (req->tx) {
|
||||
GWARN("Request is dropped without completing the transaction");
|
||||
gbinder_remote_request_complete(req, NULL, -ECANCELED);
|
||||
}
|
||||
gbinder_object_registry_unref(data->reg);
|
||||
gbinder_buffer_free(data->buffer);
|
||||
g_free(data->objects);
|
||||
g_free(self->iface2);
|
||||
g_slice_free(GBinderRemoteRequest, self);
|
||||
g_slice_free(GBinderRemoteRequestPriv, self);
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
gbinder_remote_request_init_reader2(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderRemoteRequestPriv* self,
|
||||
GBinderReader* p)
|
||||
{
|
||||
/* The caller has already checked the request for NULL */
|
||||
@@ -116,53 +130,64 @@ gbinder_remote_request_init_reader2(
|
||||
|
||||
void
|
||||
gbinder_remote_request_set_data(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderRemoteRequest* req,
|
||||
guint32 txcode,
|
||||
GBinderBuffer* buffer)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReaderData* data = &self->data;
|
||||
GBinderReader reader;
|
||||
|
||||
g_free(self->iface2);
|
||||
g_free(data->objects);
|
||||
gbinder_buffer_free(data->buffer);
|
||||
data->buffer = buffer;
|
||||
data->objects = objects;
|
||||
data->objects = gbinder_buffer_objects(buffer);
|
||||
|
||||
/* Parse RPC header */
|
||||
self->header_size = 0;
|
||||
gbinder_remote_request_init_reader2(self, &reader);
|
||||
self->iface = self->protocol->read_rpc_header(&reader, &self->iface2);
|
||||
self->header_size = gbinder_reader_bytes_read(&reader);
|
||||
self->iface = self->protocol->read_rpc_header(&reader, txcode,
|
||||
&self->iface2);
|
||||
if (self->iface) {
|
||||
self->header_size = gbinder_reader_bytes_read(&reader);
|
||||
} else {
|
||||
/* No RPC header */
|
||||
self->header_size = 0;
|
||||
}
|
||||
} else {
|
||||
gbinder_buffer_free(buffer);
|
||||
g_free(objects);
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
gbinder_remote_request_interface(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
return G_LIKELY(self) ? self->iface : NULL;
|
||||
}
|
||||
|
||||
GBinderRemoteRequest*
|
||||
gbinder_remote_request_ref(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GASSERT(self->refcount > 0);
|
||||
g_atomic_int_inc(&self->refcount);
|
||||
}
|
||||
return self;
|
||||
return req;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_request_unref(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GASSERT(self->refcount > 0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
@@ -173,9 +198,11 @@ gbinder_remote_request_unref(
|
||||
|
||||
void
|
||||
gbinder_remote_request_init_reader(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderRemoteRequest* req,
|
||||
GBinderReader* reader)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
gbinder_remote_request_init_reader2(self, reader);
|
||||
} else {
|
||||
@@ -185,15 +212,19 @@ gbinder_remote_request_init_reader(
|
||||
|
||||
pid_t
|
||||
gbinder_remote_request_sender_pid(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
return G_LIKELY(self) ? self->pid : (uid_t)(-1);
|
||||
}
|
||||
|
||||
uid_t
|
||||
gbinder_remote_request_sender_euid(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
return G_LIKELY(self) ? self->euid : (uid_t)(-1);
|
||||
}
|
||||
|
||||
@@ -207,9 +238,11 @@ gbinder_remote_request_read_int32(
|
||||
|
||||
gboolean
|
||||
gbinder_remote_request_read_uint32(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderRemoteRequest* req,
|
||||
guint32* value)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
@@ -229,9 +262,11 @@ gbinder_remote_request_read_int64(
|
||||
|
||||
gboolean
|
||||
gbinder_remote_request_read_uint64(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderRemoteRequest* req,
|
||||
guint64* value)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
@@ -243,8 +278,10 @@ gbinder_remote_request_read_uint64(
|
||||
|
||||
const char*
|
||||
gbinder_remote_request_read_string8(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
@@ -256,8 +293,10 @@ gbinder_remote_request_read_string8(
|
||||
|
||||
char*
|
||||
gbinder_remote_request_read_string16(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
@@ -269,8 +308,10 @@ gbinder_remote_request_read_string16(
|
||||
|
||||
GBinderRemoteObject*
|
||||
gbinder_remote_request_read_object(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -37,6 +37,10 @@
|
||||
|
||||
#include "gbinder_types_p.h"
|
||||
|
||||
struct gbinder_remote_request {
|
||||
GBinderIpcLooperTx* tx;
|
||||
};
|
||||
|
||||
GBinderRemoteRequest*
|
||||
gbinder_remote_request_new(
|
||||
GBinderObjectRegistry* reg,
|
||||
@@ -47,8 +51,8 @@ gbinder_remote_request_new(
|
||||
void
|
||||
gbinder_remote_request_set_data(
|
||||
GBinderRemoteRequest* request,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects);
|
||||
guint txcode,
|
||||
GBinderBuffer* buffer);
|
||||
|
||||
#endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -69,9 +69,13 @@ static
|
||||
const char*
|
||||
gbinder_rpc_protocol_binder_read_rpc_header(
|
||||
GBinderReader* reader,
|
||||
guint32 txcode,
|
||||
char** iface)
|
||||
{
|
||||
if (gbinder_reader_read_int32(reader, NULL)) {
|
||||
if (txcode > GBINDER_TRANSACTION(0,0,0)) {
|
||||
/* Internal transaction e.g. GBINDER_DUMP_TRANSACTION etc. */
|
||||
*iface = NULL;
|
||||
} else if (gbinder_reader_read_int32(reader, NULL)) {
|
||||
*iface = gbinder_reader_read_string16(reader);
|
||||
} else {
|
||||
*iface = NULL;
|
||||
@@ -99,6 +103,7 @@ static
|
||||
const char*
|
||||
gbinder_rpc_protocol_hwbinder_read_rpc_header(
|
||||
GBinderReader* reader,
|
||||
guint32 txcode,
|
||||
char** iface)
|
||||
{
|
||||
*iface = NULL;
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
*/
|
||||
|
||||
struct gbinder_rpc_protocol {
|
||||
const char* (*read_rpc_header)(GBinderReader* reader, char** iface);
|
||||
const char* (*read_rpc_header)(GBinderReader* reader, guint32 txcode,
|
||||
char** iface);
|
||||
void (*write_rpc_header)(GBinderWriter* writer, const char* iface);
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
#include <gbinder_types.h>
|
||||
|
||||
typedef struct gbinder_buffer_memory GBinderBufferMemory;
|
||||
typedef struct gbinder_buffer_contents GBinderBufferContents;
|
||||
typedef struct gbinder_cleanup GBinderCleanup;
|
||||
typedef struct gbinder_driver GBinderDriver;
|
||||
typedef struct gbinder_handler GBinderHandler;
|
||||
@@ -45,28 +45,7 @@ typedef struct gbinder_object_registry GBinderObjectRegistry;
|
||||
typedef struct gbinder_output_data GBinderOutputData;
|
||||
typedef struct gbinder_rpc_protocol GBinderRpcProtocol;
|
||||
typedef struct gbinder_servicepoll GBinderServicePoll;
|
||||
|
||||
typedef struct hidl_vec {
|
||||
union {
|
||||
guint64 value;
|
||||
const void* ptr;
|
||||
} data;
|
||||
guint32 count;
|
||||
guint32 owns_buffer;
|
||||
} HidlVec;
|
||||
|
||||
#define HIDL_VEC_BUFFER_OFFSET (0)
|
||||
|
||||
typedef struct hidl_string {
|
||||
union {
|
||||
guint64 value;
|
||||
const char* str;
|
||||
} data;
|
||||
guint32 len;
|
||||
guint32 owns_buffer;
|
||||
} HidlString;
|
||||
|
||||
#define HIDL_STRING_BUFFER_OFFSET (0)
|
||||
typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
|
||||
|
||||
#define GBINDER_INLINE_FUNC static inline
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -39,7 +39,10 @@
|
||||
#include <gutil_macros.h>
|
||||
#include <gutil_strv.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
typedef struct gbinder_writer_priv {
|
||||
GBinderWriterData* data;
|
||||
@@ -54,47 +57,49 @@ GBINDER_INLINE_FUNC GBinderWriterData* gbinder_writer_data(GBinderWriter* pub)
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_memory_cleanup(
|
||||
gpointer memory)
|
||||
gbinder_writer_data_buffer_cleanup(
|
||||
gpointer data)
|
||||
{
|
||||
gbinder_buffer_memory_unref(memory);
|
||||
gbinder_buffer_contents_unref((GBinderBufferContents*)data);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_data_set_contents(
|
||||
GBinderWriterData* data,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderBuffer* buffer)
|
||||
{
|
||||
gsize bufsize;
|
||||
const guint8* bufdata = gbinder_buffer_data(buffer, &bufsize);
|
||||
const GBinderIo* io = gbinder_buffer_io(buffer);
|
||||
GBinderBufferMemory* mem = gbinder_buffer_memory(buffer);
|
||||
GBinderBufferContents* contents = gbinder_buffer_contents(buffer);
|
||||
|
||||
GASSERT(data->io == io);
|
||||
g_byte_array_set_size(data->bytes, 0);
|
||||
gutil_int_array_set_count(data->offsets, 0);
|
||||
data->buffers_size = 0;
|
||||
gbinder_cleanup_reset(data->cleanup);
|
||||
|
||||
g_byte_array_append(data->bytes, bufdata, bufsize);
|
||||
if (mem) {
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup,
|
||||
gbinder_writer_data_memory_cleanup,
|
||||
gbinder_buffer_memory_ref(mem));
|
||||
}
|
||||
if (objects && *objects) {
|
||||
if (!data->offsets) {
|
||||
data->offsets = gutil_int_array_new();
|
||||
}
|
||||
while (*objects) {
|
||||
const guint8* obj = *objects++;
|
||||
gsize offset = obj - bufdata;
|
||||
gsize objsize = io->object_data_size(obj);
|
||||
if (contents) {
|
||||
void** objects = gbinder_buffer_objects(buffer);
|
||||
|
||||
GASSERT(offset > 0 && offset < bufsize);
|
||||
gutil_int_array_append(data->offsets, (int)offset);
|
||||
/* Size of each buffer has to be 8-byte aligned */
|
||||
data->buffers_size += G_ALIGN8(objsize);
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup,
|
||||
gbinder_writer_data_buffer_cleanup,
|
||||
gbinder_buffer_contents_ref(contents));
|
||||
if (objects && *objects) {
|
||||
if (!data->offsets) {
|
||||
data->offsets = gutil_int_array_new();
|
||||
}
|
||||
while (*objects) {
|
||||
const guint8* obj = *objects++;
|
||||
gsize offset = obj - bufdata;
|
||||
gsize objsize = io->object_data_size(obj);
|
||||
|
||||
GASSERT(offset > 0 && offset < bufsize);
|
||||
gutil_int_array_append(data->offsets, (int)offset);
|
||||
/* Size of each buffer has to be 8-byte aligned */
|
||||
data->buffers_size += G_ALIGN8(objsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,6 +149,14 @@ gbinder_writer_init(
|
||||
gbinder_writer_cast(self)->data = data;
|
||||
}
|
||||
|
||||
gsize
|
||||
gbinder_writer_bytes_written(
|
||||
GBinderWriter* self) /* since 1.0.21 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
return data->bytes->len;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_bool(
|
||||
GBinderWriter* self,
|
||||
@@ -194,6 +207,26 @@ gbinder_writer_data_append_int32(
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_overwrite_int32(
|
||||
GBinderWriter* self,
|
||||
gsize offset,
|
||||
gint32 value) /* since 1.0.21 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
GByteArray* buf = data->bytes;
|
||||
|
||||
if (buf->len >= offset + sizeof(gint32)) {
|
||||
*((gint32*)(buf->data + offset)) = value;
|
||||
} else {
|
||||
GWARN("Can't overwrite at %lu as buffer is only %u bytes long",
|
||||
(gulong)offset, buf->len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_int64(
|
||||
GBinderWriter* self,
|
||||
@@ -351,15 +384,36 @@ gbinder_writer_data_append_string16(
|
||||
gbinder_writer_data_append_string16_len(data, utf8, utf8? strlen(utf8) : 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_append_string16_null(
|
||||
GBinderWriterData* data)
|
||||
{
|
||||
/* NULL string */
|
||||
gbinder_writer_data_append_int32(data, -1);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_append_string16_empty(
|
||||
GBinderWriterData* data)
|
||||
{
|
||||
GByteArray* buf = data->bytes;
|
||||
const gsize old_size = buf->len;
|
||||
guint16* ptr16;
|
||||
|
||||
/* Empty string */
|
||||
g_byte_array_set_size(buf, old_size + 8);
|
||||
ptr16 = (guint16*)(buf->data + old_size);
|
||||
ptr16[0] = ptr16[1] = ptr16[2] = 0; ptr16[3] = 0xffff;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_data_append_string16_len(
|
||||
GBinderWriterData* data,
|
||||
const char* utf8,
|
||||
gssize num_bytes)
|
||||
{
|
||||
GByteArray* buf = data->bytes;
|
||||
const gsize old_size = buf->len;
|
||||
|
||||
if (utf8) {
|
||||
const char* end = utf8;
|
||||
|
||||
@@ -370,6 +424,8 @@ gbinder_writer_data_append_string16_len(
|
||||
}
|
||||
|
||||
if (num_bytes > 0) {
|
||||
GByteArray* buf = data->bytes;
|
||||
const gsize old_size = buf->len;
|
||||
glong len = g_utf8_strlen(utf8, num_bytes);
|
||||
gsize padded_len = G_ALIGN4((len+1)*2);
|
||||
guint32* len_ptr;
|
||||
@@ -407,14 +463,69 @@ gbinder_writer_data_append_string16_len(
|
||||
g_byte_array_set_size(buf, old_size + padded_len + 4);
|
||||
} else if (utf8) {
|
||||
/* Empty string */
|
||||
guint16* ptr16;
|
||||
|
||||
g_byte_array_set_size(buf, old_size + 8);
|
||||
ptr16 = (guint16*)(buf->data + old_size);
|
||||
ptr16[0] = ptr16[1] = ptr16[2] = 0; ptr16[3] = 0xffff;
|
||||
gbinder_writer_data_append_string16_empty(data);
|
||||
} else {
|
||||
/* NULL string */
|
||||
gbinder_writer_data_append_int32(data, -1);
|
||||
gbinder_writer_data_append_string16_null(data);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_append_string16_utf16(
|
||||
GBinderWriterData* data,
|
||||
const gunichar2* utf16,
|
||||
gssize length)
|
||||
{
|
||||
if (length < 0) {
|
||||
length = 0;
|
||||
if (utf16) {
|
||||
const guint16* ptr;
|
||||
|
||||
/* Assume NULL terminated string */
|
||||
for (ptr = utf16; *ptr; ptr++);
|
||||
length = ptr - utf16;
|
||||
}
|
||||
}
|
||||
if (length > 0) {
|
||||
GByteArray* buf = data->bytes;
|
||||
const gsize old_size = buf->len;
|
||||
const gsize padded_size = G_ALIGN4((length + 1) * 2);
|
||||
guint32* len_ptr;
|
||||
gunichar2* utf16_ptr;
|
||||
|
||||
/* Preallocate space */
|
||||
g_byte_array_set_size(buf, old_size + padded_size + 4);
|
||||
len_ptr = (guint32*)(buf->data + old_size);
|
||||
utf16_ptr = (gunichar2*)(len_ptr + 1);
|
||||
|
||||
/* Actual length */
|
||||
*len_ptr = length;
|
||||
|
||||
/* Characters */
|
||||
memcpy(utf16_ptr, utf16, 2 * length);
|
||||
|
||||
/* Zero padding */
|
||||
memset(utf16_ptr + length, 0, padded_size - 2 * length);
|
||||
} else if (utf16) {
|
||||
/* Empty string */
|
||||
gbinder_writer_data_append_string16_empty(data);
|
||||
} else {
|
||||
/* NULL string */
|
||||
gbinder_writer_data_append_string16_null(data);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_string16_utf16(
|
||||
GBinderWriter* self,
|
||||
const gunichar2* utf16,
|
||||
gssize length) /* Since 1.0.17 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
gbinder_writer_data_append_string16_utf16(data, utf16, length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,6 +553,60 @@ gbinder_writer_data_prepare(
|
||||
return data->offsets->count;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_close_fd(
|
||||
gpointer data)
|
||||
{
|
||||
const int fd = GPOINTER_TO_INT(data);
|
||||
|
||||
if (close(fd) < 0) {
|
||||
GWARN("Error closing fd %d: %s", fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_append_fd(
|
||||
GBinderWriterData* data,
|
||||
int fd)
|
||||
{
|
||||
GByteArray* buf = data->bytes;
|
||||
const guint offset = buf->len;
|
||||
/* Duplicate the descriptor so that caller can do whatever with
|
||||
* the one it passed in. */
|
||||
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||
guint written;
|
||||
|
||||
/* Preallocate enough space */
|
||||
g_byte_array_set_size(buf, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
|
||||
/* Write the original fd if we failed to dup it */
|
||||
if (dupfd < 0) {
|
||||
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
|
||||
written = data->io->encode_fd_object(buf->data + offset, fd);
|
||||
} else {
|
||||
written = data->io->encode_fd_object(buf->data + offset, dupfd);
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup,
|
||||
gbinder_writer_data_close_fd, GINT_TO_POINTER(dupfd));
|
||||
}
|
||||
/* Fix the data size */
|
||||
g_byte_array_set_size(buf, offset + written);
|
||||
/* Record the offset */
|
||||
gbinder_writer_data_record_offset(data, offset);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_fd(
|
||||
GBinderWriter* self,
|
||||
int fd) /* Since 1.0.18 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
gbinder_writer_data_append_fd(data, fd);
|
||||
}
|
||||
}
|
||||
|
||||
guint
|
||||
gbinder_writer_append_buffer_object_with_parent(
|
||||
GBinderWriter* self,
|
||||
@@ -504,13 +669,13 @@ gbinder_writer_data_append_hidl_vec(
|
||||
guint elemsize)
|
||||
{
|
||||
GBinderParent vec_parent;
|
||||
HidlVec* vec = g_new0(HidlVec, 1);
|
||||
GBinderHidlVec* vec = g_new0(GBinderHidlVec, 1);
|
||||
const gsize total = count * elemsize;
|
||||
void* buf = g_memdup(base, total);
|
||||
|
||||
/* Prepare parent descriptor for the string data */
|
||||
vec_parent.index = gbinder_writer_data_prepare(data);
|
||||
vec_parent.offset = HIDL_VEC_BUFFER_OFFSET;
|
||||
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
|
||||
|
||||
/* Fill in the vector descriptor */
|
||||
if (buf) {
|
||||
@@ -550,12 +715,12 @@ gbinder_writer_data_append_hidl_string(
|
||||
const char* str)
|
||||
{
|
||||
GBinderParent str_parent;
|
||||
HidlString* hidl_string = g_new0(HidlString, 1);
|
||||
GBinderHidlString* hidl_string = g_new0(GBinderHidlString, 1);
|
||||
const gsize len = str ? strlen(str) : 0;
|
||||
|
||||
/* Prepare parent descriptor for the string data */
|
||||
str_parent.index = gbinder_writer_data_prepare(data);
|
||||
str_parent.offset = HIDL_STRING_BUFFER_OFFSET;
|
||||
str_parent.offset = GBINDER_HIDL_STRING_BUFFER_OFFSET;
|
||||
|
||||
/* Fill in the string descriptor and store it */
|
||||
hidl_string->data.str = str;
|
||||
@@ -597,8 +762,8 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
gssize count)
|
||||
{
|
||||
GBinderParent vec_parent;
|
||||
HidlVec* vec = g_new0(HidlVec, 1);
|
||||
HidlString* strings = NULL;
|
||||
GBinderHidlVec* vec = g_new0(GBinderHidlVec, 1);
|
||||
GBinderHidlString* strings = NULL;
|
||||
int i;
|
||||
|
||||
if (count < 0) {
|
||||
@@ -608,11 +773,11 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
|
||||
/* Prepare parent descriptor for the vector data */
|
||||
vec_parent.index = gbinder_writer_data_prepare(data);
|
||||
vec_parent.offset = HIDL_VEC_BUFFER_OFFSET;
|
||||
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
|
||||
|
||||
/* Fill in the vector descriptor */
|
||||
if (count > 0) {
|
||||
strings = g_new0(HidlString, count);
|
||||
strings = g_new0(GBinderHidlString, count);
|
||||
vec->data.ptr = strings;
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, strings);
|
||||
}
|
||||
@@ -623,7 +788,7 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
/* Fill in string descriptors */
|
||||
for (i = 0; i < count; i++) {
|
||||
const char* str = strv[i];
|
||||
HidlString* hidl_str = strings + i;
|
||||
GBinderHidlString* hidl_str = strings + i;
|
||||
|
||||
if ((hidl_str->data.str = str) != NULL) {
|
||||
hidl_str->len = strlen(str);
|
||||
@@ -638,7 +803,7 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
|
||||
/* Prepare parent descriptor for the string data */
|
||||
str_parent.index = data->offsets->count;
|
||||
str_parent.offset = HIDL_STRING_BUFFER_OFFSET;
|
||||
str_parent.offset = GBINDER_HIDL_STRING_BUFFER_OFFSET;
|
||||
|
||||
/* Write the vector data (it's parent for the string data) */
|
||||
gbinder_writer_data_write_buffer_object(data, strings,
|
||||
@@ -646,7 +811,7 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
|
||||
/* Write the string data */
|
||||
for (i = 0; i < count; i++) {
|
||||
HidlString* hidl_str = strings + i;
|
||||
GBinderHidlString* hidl_str = strings + i;
|
||||
|
||||
if (hidl_str->data.str) {
|
||||
gbinder_writer_data_write_buffer_object(data,
|
||||
@@ -655,7 +820,7 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
(guint)hidl_str->len, (guint)str_parent.index,
|
||||
(guint)data->buffers_size);
|
||||
}
|
||||
str_parent.offset += sizeof(HidlString);
|
||||
str_parent.offset += sizeof(GBinderHidlString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -752,6 +917,73 @@ gbinder_writer_data_append_remote_object(
|
||||
gbinder_writer_data_record_offset(data, offset);
|
||||
}
|
||||
|
||||
static
|
||||
void*
|
||||
gbinder_writer_alloc(
|
||||
GBinderWriter* self,
|
||||
gsize size,
|
||||
gpointer (*alloc)(gsize),
|
||||
void (*dealloc)())
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
void* ptr = alloc(size);
|
||||
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, dealloc, ptr);
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void*
|
||||
gbinder_writer_malloc(
|
||||
GBinderWriter* self,
|
||||
gsize size) /* since 1.0.19 */
|
||||
{
|
||||
return gbinder_writer_alloc(self, size, g_malloc, g_free);
|
||||
}
|
||||
|
||||
void*
|
||||
gbinder_writer_malloc0(
|
||||
GBinderWriter* self,
|
||||
gsize size) /* since 1.0.19 */
|
||||
{
|
||||
return gbinder_writer_alloc(self, size, g_malloc0, g_free);
|
||||
}
|
||||
|
||||
void*
|
||||
gbinder_writer_memdup(
|
||||
GBinderWriter* self,
|
||||
const void* buf,
|
||||
gsize size) /* since 1.0.19 */
|
||||
{
|
||||
if (buf) {
|
||||
void* ptr = gbinder_writer_malloc(self, size);
|
||||
|
||||
if (ptr) {
|
||||
memcpy(ptr, buf, size);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_add_cleanup(
|
||||
GBinderWriter* self,
|
||||
GDestroyNotify destroy,
|
||||
gpointer ptr) /* since 1.0.19 */
|
||||
{
|
||||
if (G_LIKELY(destroy)) {
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, destroy, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -53,8 +53,7 @@ gbinder_writer_init(
|
||||
void
|
||||
gbinder_writer_data_set_contents(
|
||||
GBinderWriterData* data,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects);
|
||||
GBinderBuffer* buffer);
|
||||
|
||||
void
|
||||
gbinder_writer_data_append_bool(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
all:
|
||||
%:
|
||||
@$(MAKE) -C binder-client $*
|
||||
@$(MAKE) -C binder-dump $*
|
||||
@$(MAKE) -C binder-list $*
|
||||
@$(MAKE) -C binder-service $*
|
||||
@$(MAKE) -C rild-card-status $*
|
||||
|
||||
140
test/binder-dump/Makefile
Normal file
140
test/binder-dump/Makefile
Normal file
@@ -0,0 +1,140 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
.PHONY: all debug release clean cleaner
|
||||
.PHONY: libgbinder-release libgbinder-debug
|
||||
|
||||
#
|
||||
# Required packages
|
||||
#
|
||||
|
||||
PKGS = glib-2.0 gio-2.0 gio-unix-2.0 libglibutil
|
||||
|
||||
#
|
||||
# Default target
|
||||
#
|
||||
|
||||
all: debug release
|
||||
|
||||
#
|
||||
# Executable
|
||||
#
|
||||
|
||||
EXE = binder-dump
|
||||
|
||||
#
|
||||
# Sources
|
||||
#
|
||||
|
||||
SRC = $(EXE).c
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
SRC_DIR = .
|
||||
BUILD_DIR = build
|
||||
LIB_DIR = ../..
|
||||
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
|
||||
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
|
||||
|
||||
#
|
||||
# Tools and flags
|
||||
#
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
LD = $(CC)
|
||||
WARNINGS = -Wall
|
||||
INCLUDES = -I$(LIB_DIR)/include
|
||||
BASE_FLAGS = -fPIC
|
||||
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
|
||||
$(shell pkg-config --cflags $(PKGS))
|
||||
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
|
||||
QUIET_MAKE = make --no-print-directory
|
||||
DEBUG_FLAGS = -g
|
||||
RELEASE_FLAGS =
|
||||
|
||||
ifndef KEEP_SYMBOLS
|
||||
KEEP_SYMBOLS = 0
|
||||
endif
|
||||
|
||||
ifneq ($(KEEP_SYMBOLS),0)
|
||||
RELEASE_FLAGS += -g
|
||||
SUBMAKE_OPTS += KEEP_SYMBOLS=1
|
||||
endif
|
||||
|
||||
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
|
||||
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
|
||||
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
|
||||
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
|
||||
|
||||
#
|
||||
# Files
|
||||
#
|
||||
|
||||
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
|
||||
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
|
||||
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
|
||||
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
|
||||
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
|
||||
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
|
||||
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
|
||||
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
|
||||
|
||||
#
|
||||
# Dependencies
|
||||
#
|
||||
|
||||
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(strip $(DEPS)),)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
|
||||
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
|
||||
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
|
||||
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
|
||||
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
|
||||
|
||||
debug: libgbinder-debug $(DEBUG_EXE)
|
||||
|
||||
release: libgbinder-release $(RELEASE_EXE)
|
||||
|
||||
clean:
|
||||
rm -f *~
|
||||
rm -fr $(BUILD_DIR)
|
||||
|
||||
cleaner: clean
|
||||
@make -C $(LIB_DIR) clean
|
||||
|
||||
$(DEBUG_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(RELEASE_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
|
||||
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
|
||||
|
||||
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
|
||||
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
|
||||
ifeq ($(KEEP_SYMBOLS),0)
|
||||
strip $@
|
||||
endif
|
||||
|
||||
libgbinder-debug:
|
||||
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
|
||||
|
||||
libgbinder-release:
|
||||
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
|
||||
237
test/binder-dump/binder-dump.c
Normal file
237
test/binder-dump/binder-dump.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <gbinder.h>
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define RET_OK (0)
|
||||
#define RET_NOTFOUND (1)
|
||||
#define RET_INVARG (2)
|
||||
#define RET_ERR (3)
|
||||
|
||||
#define DEV_DEFAULT GBINDER_DEFAULT_BINDER
|
||||
|
||||
#define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
|
||||
#define GBINDER_DUMP_TRANSACTION GBINDER_TRANSACTION('D','M','P')
|
||||
|
||||
typedef struct app_options {
|
||||
char* dev;
|
||||
const char* service;
|
||||
} AppOptions;
|
||||
|
||||
typedef struct app {
|
||||
const AppOptions* opt;
|
||||
GMainLoop* loop;
|
||||
GBinderServiceManager* sm;
|
||||
int ret;
|
||||
} App;
|
||||
|
||||
static const char pname[] = "binder-dump";
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_dump_service(
|
||||
App* app,
|
||||
const char* service)
|
||||
{
|
||||
int status = 0;
|
||||
GBinderRemoteObject* obj = gbinder_servicemanager_get_service_sync(app->sm,
|
||||
service, &status);
|
||||
|
||||
if (obj) {
|
||||
GBinderClient* client = gbinder_client_new(obj, NULL);
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(client);
|
||||
GBinderRemoteReply* reply;
|
||||
GBinderWriter writer;
|
||||
|
||||
gbinder_remote_object_ref(obj);
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
gbinder_writer_append_fd(&writer, STDOUT_FILENO);
|
||||
gbinder_writer_append_int32(&writer, 0);
|
||||
reply = gbinder_client_transact_sync_reply(client,
|
||||
GBINDER_DUMP_TRANSACTION, req, &status);
|
||||
if (status < 0) {
|
||||
GERR("Error %d", status);
|
||||
}
|
||||
gbinder_remote_object_unref(obj);
|
||||
gbinder_remote_reply_unref(reply);
|
||||
gbinder_local_request_unref(req);
|
||||
gbinder_client_unref(client);
|
||||
return TRUE;
|
||||
} else {
|
||||
GERR("No such service: %s (%d)", service, status);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
app_dump_services(
|
||||
App* app,
|
||||
char** strv)
|
||||
{
|
||||
if (strv) {
|
||||
while (*strv) {
|
||||
const char* name = *strv++;
|
||||
|
||||
printf("========= %s\n", name);
|
||||
app_dump_service(app, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
app_run(
|
||||
App* app)
|
||||
{
|
||||
const AppOptions* opt = app->opt;
|
||||
|
||||
if (opt->service) {
|
||||
app->ret = app_dump_service(app, opt->service) ? RET_OK : RET_NOTFOUND;
|
||||
} else {
|
||||
char** services = gbinder_servicemanager_list_sync(app->sm);
|
||||
|
||||
if (services) {
|
||||
app_dump_services(app, services);
|
||||
g_strfreev(services);
|
||||
app->ret = RET_OK;
|
||||
} else {
|
||||
app->ret = RET_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_verbose(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = GLOG_LEVEL_VERBOSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_quiet(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = GLOG_LEVEL_ERR;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_init(
|
||||
AppOptions* opt,
|
||||
int argc,
|
||||
char* argv[])
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
GOptionEntry entries[] = {
|
||||
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_verbose, "Enable verbose output", NULL },
|
||||
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_quiet, "Be quiet", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
GError* error = NULL;
|
||||
GOptionContext* options = g_option_context_new("[SERVICE]");
|
||||
|
||||
memset(opt, 0, sizeof(*opt));
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_set_type(GLOG_TYPE_STDERR, pname);
|
||||
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
|
||||
|
||||
g_option_context_add_main_entries(options, entries, NULL);
|
||||
if (g_option_context_parse(options, &argc, &argv, &error)) {
|
||||
char* help;
|
||||
|
||||
opt->dev = g_strdup(DEV_DEFAULT);
|
||||
switch (argc) {
|
||||
case 2:
|
||||
opt->service = argv[1];
|
||||
/* no break */
|
||||
case 1:
|
||||
ok = TRUE;
|
||||
break;
|
||||
default:
|
||||
help = g_option_context_get_help(options, TRUE, NULL);
|
||||
fprintf(stderr, "%s", help);
|
||||
g_free(help);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
GERR("%s", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
g_option_context_free(options);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
App app;
|
||||
AppOptions opt;
|
||||
|
||||
memset(&app, 0, sizeof(app));
|
||||
app.ret = RET_INVARG;
|
||||
app.opt = &opt;
|
||||
if (app_init(&opt, argc, argv)) {
|
||||
app.sm = gbinder_servicemanager_new(opt.dev);
|
||||
if (app.sm) {
|
||||
app_run(&app);
|
||||
gbinder_servicemanager_unref(app.sm);
|
||||
}
|
||||
}
|
||||
g_free(opt.dev);
|
||||
return app.ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -194,7 +194,7 @@ app_init(
|
||||
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_quiet, "Be quiet", NULL },
|
||||
{ "async", 'a', 0, G_OPTION_ARG_NONE, &opt->async,
|
||||
"Parform operations asynchronously", NULL },
|
||||
"Perform operations asynchronously", NULL },
|
||||
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
|
||||
"Binder device [" DEV_DEFAULT "]", "DEVICE" },
|
||||
{ NULL }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -13,9 +13,9 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -36,6 +36,9 @@
|
||||
|
||||
#include <glib-unix.h>
|
||||
|
||||
#define BINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
|
||||
#define BINDER_DUMP_TRANSACTION BINDER_TRANSACTION('D','M','P')
|
||||
|
||||
#define RET_OK (0)
|
||||
#define RET_NOTFOUND (1)
|
||||
#define RET_INVARG (2)
|
||||
@@ -49,6 +52,7 @@ typedef struct app_options {
|
||||
char* dev;
|
||||
char* iface;
|
||||
const char* name;
|
||||
gboolean async;
|
||||
} AppOptions;
|
||||
|
||||
typedef struct app {
|
||||
@@ -59,6 +63,11 @@ typedef struct app {
|
||||
int ret;
|
||||
} App;
|
||||
|
||||
typedef struct response {
|
||||
GBinderRemoteRequest* req;
|
||||
GBinderLocalReply* reply;
|
||||
} Response;
|
||||
|
||||
static const char pname[] = "binder-service";
|
||||
|
||||
static
|
||||
@@ -73,6 +82,29 @@ app_signal(
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_async_resp(
|
||||
gpointer user_data)
|
||||
{
|
||||
Response* resp = user_data;
|
||||
|
||||
gbinder_remote_request_complete(resp->req, resp->reply, 0);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
app_async_free(
|
||||
gpointer user_data)
|
||||
{
|
||||
Response* resp = user_data;
|
||||
|
||||
gbinder_local_reply_unref(resp->reply);
|
||||
gbinder_remote_request_unref(resp->req);
|
||||
g_free(resp);
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
app_reply(
|
||||
@@ -83,15 +115,52 @@ app_reply(
|
||||
int* status,
|
||||
void* user_data)
|
||||
{
|
||||
char* str = gbinder_remote_request_read_string16(req);
|
||||
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
|
||||
App* app = user_data;
|
||||
GBinderReader reader;
|
||||
|
||||
GVERBOSE("\"%s\" %u", gbinder_remote_request_interface(req), code);
|
||||
GDEBUG("\"%s\"", str);
|
||||
gbinder_local_reply_append_string16(reply, str);
|
||||
g_free(str);
|
||||
*status = 0;
|
||||
return reply;
|
||||
gbinder_remote_request_init_reader(req, &reader);
|
||||
if (code == GBINDER_FIRST_CALL_TRANSACTION) {
|
||||
const AppOptions* opt = app->opt;
|
||||
const char* iface = gbinder_remote_request_interface(req);
|
||||
|
||||
if (!g_strcmp0(iface, opt->iface)) {
|
||||
char* str = gbinder_reader_read_string16(&reader);
|
||||
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
|
||||
|
||||
GVERBOSE("\"%s\" %u", iface, code);
|
||||
GDEBUG("\"%s\"", str);
|
||||
*status = 0;
|
||||
gbinder_local_reply_append_string16(reply, str);
|
||||
g_free(str);
|
||||
if (opt->async) {
|
||||
Response* resp = g_new0(Response, 1);
|
||||
|
||||
resp->reply = reply;
|
||||
resp->req = gbinder_remote_request_ref(req);
|
||||
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, app_async_resp,
|
||||
resp, app_async_free);
|
||||
gbinder_remote_request_block(resp->req);
|
||||
return NULL;
|
||||
} else {
|
||||
return reply;
|
||||
}
|
||||
} else {
|
||||
GDEBUG("Unexpected interface \"%s\"", iface);
|
||||
}
|
||||
} else if (code == BINDER_DUMP_TRANSACTION) {
|
||||
int fd = gbinder_reader_read_fd(&reader);
|
||||
const char* dump = "Sorry, I've got nothing to dump...\n";
|
||||
const gssize dump_len = strlen(dump);
|
||||
|
||||
GDEBUG("Dump request from %d", gbinder_remote_request_sender_pid(req));
|
||||
if (write(fd, dump, dump_len) != dump_len) {
|
||||
GERR("Failed to write dump: %s", strerror(errno));
|
||||
}
|
||||
*status = 0;
|
||||
return NULL;
|
||||
}
|
||||
*status = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
@@ -175,6 +244,8 @@ app_init(
|
||||
"Binder device [" DEFAULT_DEVICE "]", "DEVICE" },
|
||||
{ "interface", 'i', 0, G_OPTION_ARG_STRING, &opt->iface,
|
||||
"Local interface [" DEFAULT_IFACE "]", "IFACE" },
|
||||
{ "async", 'a', 0, G_OPTION_ARG_NONE, &opt->async,
|
||||
"Handle calls asynchronously", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
all:
|
||||
%:
|
||||
@$(MAKE) -C unit_buffer $*
|
||||
@$(MAKE) -C unit_cleanup $*
|
||||
@$(MAKE) -C unit_client $*
|
||||
@$(MAKE) -C unit_driver $*
|
||||
@$(MAKE) -C unit_ipc $*
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
TESTS="\
|
||||
unit_buffer \
|
||||
unit_cleanup \
|
||||
unit_client \
|
||||
unit_driver \
|
||||
unit_ipc \
|
||||
|
||||
@@ -47,19 +47,21 @@ test_null(
|
||||
void)
|
||||
{
|
||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||
GBinderBuffer* buf = gbinder_buffer_new(NULL, NULL, 0);
|
||||
GBinderBuffer* buf = gbinder_buffer_new(NULL, NULL, 0, NULL);
|
||||
GBinderBuffer* buf2;
|
||||
gsize size = 1;
|
||||
|
||||
gbinder_buffer_free(buf);
|
||||
|
||||
/* No need to reference the driver if there's no data */
|
||||
buf = gbinder_buffer_new(driver, NULL, 0);
|
||||
buf = gbinder_buffer_new(driver, NULL, 0, NULL);
|
||||
g_assert(!gbinder_buffer_driver(buf));
|
||||
gbinder_buffer_free(buf);
|
||||
|
||||
buf = gbinder_buffer_new_with_parent(NULL, NULL, 0);
|
||||
buf2 = gbinder_buffer_new_with_parent(buf, NULL, 0);
|
||||
g_assert(!gbinder_buffer_objects(buf));
|
||||
g_assert(!gbinder_buffer_objects(buf2));
|
||||
g_assert(!gbinder_buffer_driver(buf));
|
||||
g_assert(!gbinder_buffer_driver(buf2));
|
||||
gbinder_buffer_free(buf);
|
||||
@@ -67,6 +69,7 @@ test_null(
|
||||
|
||||
gbinder_buffer_free(NULL);
|
||||
g_assert(!gbinder_buffer_driver(NULL));
|
||||
g_assert(!gbinder_buffer_objects(NULL));
|
||||
g_assert(!gbinder_buffer_io(NULL));
|
||||
g_assert(!gbinder_buffer_data(NULL, NULL));
|
||||
g_assert(!gbinder_buffer_data(NULL, &size));
|
||||
@@ -87,14 +90,14 @@ test_parent(
|
||||
void* ptr = g_memdup(data, sizeof(data));
|
||||
gsize size = 0;
|
||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||
GBinderBuffer* parent = gbinder_buffer_new(driver, ptr, sizeof(data));
|
||||
GBinderBuffer* parent = gbinder_buffer_new(driver, ptr, sizeof(data), NULL);
|
||||
GBinderBuffer* buf = gbinder_buffer_new_with_parent
|
||||
(parent, ptr, sizeof(data));
|
||||
|
||||
g_assert(gbinder_buffer_driver(buf) == driver);
|
||||
g_assert(gbinder_buffer_io(buf));
|
||||
g_assert(gbinder_buffer_io(buf) == gbinder_driver_io(driver));
|
||||
g_assert(gbinder_buffer_memory(buf));
|
||||
g_assert(gbinder_buffer_contents(buf));
|
||||
g_assert(gbinder_buffer_data(buf, NULL) == ptr);
|
||||
g_assert(gbinder_buffer_data(buf, &size) == ptr);
|
||||
g_assert(size == sizeof(data));
|
||||
|
||||
5
unit/unit_cleanup/Makefile
Normal file
5
unit/unit_cleanup/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
EXE = unit_cleanup
|
||||
|
||||
include ../common/Makefile
|
||||
126
unit/unit_cleanup/unit_cleanup.c
Normal file
126
unit/unit_cleanup/unit_cleanup.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "test_binder.h"
|
||||
|
||||
#include "gbinder_cleanup.h"
|
||||
|
||||
static TestOpt test_opt;
|
||||
|
||||
static
|
||||
void
|
||||
test_cleanup_inc(
|
||||
gpointer data)
|
||||
{
|
||||
(*((int*)data))++;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* null
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_null(
|
||||
void)
|
||||
{
|
||||
g_assert(!gbinder_cleanup_add(NULL, NULL, NULL));
|
||||
gbinder_cleanup_free(NULL);
|
||||
gbinder_cleanup_reset(NULL);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* basic
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_basic(
|
||||
void)
|
||||
{
|
||||
int n1 = 0, n2 =0;
|
||||
GBinderCleanup* cleanup = gbinder_cleanup_add(NULL, test_cleanup_inc, &n1);
|
||||
|
||||
g_assert(cleanup);
|
||||
g_assert(gbinder_cleanup_add(cleanup, test_cleanup_inc, &n2) == cleanup);
|
||||
gbinder_cleanup_free(cleanup);
|
||||
g_assert(n1 == 1);
|
||||
g_assert(n2 == 1);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* reset
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_reset(
|
||||
void)
|
||||
{
|
||||
int n1 = 0, n2 =0;
|
||||
GBinderCleanup* cleanup = gbinder_cleanup_add(NULL, test_cleanup_inc, &n1);
|
||||
|
||||
g_assert(cleanup);
|
||||
g_assert(gbinder_cleanup_add(cleanup, test_cleanup_inc, &n2) == cleanup);
|
||||
gbinder_cleanup_reset(cleanup);
|
||||
g_assert(n1 == 1);
|
||||
g_assert(n2 == 1);
|
||||
|
||||
gbinder_cleanup_free(cleanup);
|
||||
g_assert(n1 == 1);
|
||||
g_assert(n2 == 1);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Common
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_PREFIX "/cleanup/"
|
||||
#define TEST_(t) TEST_PREFIX t
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("reset"), test_reset);
|
||||
test_init(&test_opt, argc, argv);
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -74,16 +74,15 @@ void
|
||||
test_null(
|
||||
void)
|
||||
{
|
||||
GBinderClient* null = NULL;
|
||||
|
||||
g_assert(!gbinder_client_new(NULL, NULL));
|
||||
g_assert(!gbinder_client_ref(null));
|
||||
gbinder_client_unref(null);
|
||||
g_assert(!gbinder_client_ref(NULL));
|
||||
g_assert(!gbinder_client_interface(NULL));
|
||||
gbinder_client_unref(NULL);
|
||||
g_assert(!gbinder_client_new_request(NULL));
|
||||
g_assert(!gbinder_client_transact_sync_reply(null, 0, NULL, NULL));
|
||||
g_assert(gbinder_client_transact_sync_oneway(null, 0, NULL) == (-EINVAL));
|
||||
g_assert(!gbinder_client_transact(null, 0, 0, NULL, NULL, NULL, NULL));
|
||||
gbinder_client_cancel(null, 0);
|
||||
g_assert(!gbinder_client_transact_sync_reply(NULL, 0, NULL, NULL));
|
||||
g_assert(gbinder_client_transact_sync_oneway(NULL, 0, NULL) == (-EINVAL));
|
||||
g_assert(!gbinder_client_transact(NULL, 0, 0, NULL, NULL, NULL, NULL));
|
||||
gbinder_client_cancel(NULL, 0);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
@@ -98,11 +97,12 @@ test_basic(
|
||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0);
|
||||
GBinderClient* client = gbinder_client_new(obj, "foo");
|
||||
const char* iface = "foo";
|
||||
GBinderClient* client = gbinder_client_new(obj, iface);
|
||||
|
||||
g_assert(!gbinder_client_new(obj, NULL));
|
||||
g_assert(client);
|
||||
g_assert(gbinder_client_ref(client) == client);
|
||||
g_assert(!g_strcmp0(gbinder_client_interface(client), iface));
|
||||
gbinder_client_unref(client);
|
||||
gbinder_client_cancel(client, 0); /* does nothing */
|
||||
|
||||
@@ -111,6 +111,25 @@ test_basic(
|
||||
gbinder_ipc_unref(ipc);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* no_header
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_no_header(
|
||||
void)
|
||||
{
|
||||
GBinderClient* client = test_client_new(0, NULL);
|
||||
int fd = gbinder_driver_fd(gbinder_client_ipc(client)->driver);
|
||||
|
||||
test_binder_br_transaction_complete(fd);
|
||||
g_assert(gbinder_client_transact_sync_oneway(client, 0, NULL) ==
|
||||
GBINDER_STATUS_OK);
|
||||
|
||||
gbinder_client_unref(client);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* sync_oneway
|
||||
*==========================================================================*/
|
||||
@@ -326,17 +345,19 @@ test_reply_ok3(
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_PREFIX "/client/"
|
||||
#define TEST_(t) TEST_PREFIX t
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func(TEST_PREFIX "null", test_null);
|
||||
g_test_add_func(TEST_PREFIX "basic", test_basic);
|
||||
g_test_add_func(TEST_PREFIX "sync_oneway", test_sync_oneway);
|
||||
g_test_add_func(TEST_PREFIX "sync_reply", test_sync_reply);
|
||||
g_test_add_func(TEST_PREFIX "reply/ok1", test_reply_ok1);
|
||||
g_test_add_func(TEST_PREFIX "reply/ok2", test_reply_ok2);
|
||||
g_test_add_func(TEST_PREFIX "reply/ok3", test_reply_ok3);
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("no_header"), test_no_header);
|
||||
g_test_add_func(TEST_("sync_oneway"), test_sync_oneway);
|
||||
g_test_add_func(TEST_("sync_reply"), test_sync_reply);
|
||||
g_test_add_func(TEST_("reply/ok1"), test_reply_ok1);
|
||||
g_test_add_func(TEST_("reply/ok2"), test_reply_ok2);
|
||||
g_test_add_func(TEST_("reply/ok3"), test_reply_ok3);
|
||||
test_init(&test_opt, argc, argv);
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
@@ -52,6 +52,24 @@
|
||||
|
||||
static TestOpt test_opt;
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_unref_ipc(
|
||||
gpointer ipc)
|
||||
{
|
||||
gbinder_ipc_unref(ipc);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_quit_when_destroyed(
|
||||
gpointer loop,
|
||||
GObject* obj)
|
||||
{
|
||||
test_quit_later((GMainLoop*)loop);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* null
|
||||
*==========================================================================*/
|
||||
@@ -606,24 +624,6 @@ test_transact_incoming_proc(
|
||||
return gbinder_local_object_new_reply(obj);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_transact_unref_ipc(
|
||||
gpointer ipc)
|
||||
{
|
||||
gbinder_ipc_unref(ipc);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_transact_done(
|
||||
gpointer loop,
|
||||
GObject* ipc)
|
||||
{
|
||||
test_quit_later((GMainLoop*)loop);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_transact_incoming(
|
||||
@@ -651,17 +651,17 @@ test_transact_incoming(
|
||||
|
||||
/* Now we need to wait until GBinderIpc is destroyed */
|
||||
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||
g_object_weak_ref(G_OBJECT(ipc), test_transact_done, loop);
|
||||
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||
gbinder_local_object_unref(obj);
|
||||
gbinder_local_request_unref(req);
|
||||
g_idle_add(test_transact_unref_ipc, ipc);
|
||||
g_idle_add(test_unref_ipc, ipc);
|
||||
test_run(&test_opt, loop);
|
||||
|
||||
g_main_loop_unref(loop);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* transact_incoming_status
|
||||
* transact_status_reply
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
@@ -712,10 +712,184 @@ test_transact_status_reply(
|
||||
|
||||
/* Now we need to wait until GBinderIpc is destroyed */
|
||||
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||
g_object_weak_ref(G_OBJECT(ipc), test_transact_done, loop);
|
||||
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||
gbinder_local_object_unref(obj);
|
||||
gbinder_local_request_unref(req);
|
||||
g_idle_add(test_transact_unref_ipc, ipc);
|
||||
g_idle_add(test_unref_ipc, ipc);
|
||||
test_run(&test_opt, loop);
|
||||
|
||||
g_main_loop_unref(loop);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* transact_async
|
||||
*==========================================================================*/
|
||||
|
||||
typedef struct test_transact_async_req {
|
||||
GBinderLocalObject* obj;
|
||||
GBinderRemoteRequest* req;
|
||||
GMainLoop* loop;
|
||||
} TestTransactAsyncReq;
|
||||
|
||||
static
|
||||
void
|
||||
test_transact_async_done(
|
||||
gpointer data)
|
||||
{
|
||||
TestTransactAsyncReq* test = data;
|
||||
|
||||
gbinder_local_object_unref(test->obj);
|
||||
gbinder_remote_request_unref(test->req);
|
||||
test_quit_later(test->loop);
|
||||
g_free(test);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_transact_async_reply(
|
||||
gpointer data)
|
||||
{
|
||||
TestTransactAsyncReq* test = data;
|
||||
GBinderLocalReply* reply = gbinder_local_object_new_reply(test->obj);
|
||||
|
||||
gbinder_remote_request_complete(test->req, reply, 0);
|
||||
gbinder_local_reply_unref(reply);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
test_transact_async_proc(
|
||||
GBinderLocalObject* obj,
|
||||
GBinderRemoteRequest* req,
|
||||
guint code,
|
||||
guint flags,
|
||||
int* status,
|
||||
void* loop)
|
||||
{
|
||||
TestTransactAsyncReq* test = g_new(TestTransactAsyncReq, 1);
|
||||
|
||||
GVERBOSE_("\"%s\" %u", gbinder_remote_request_interface(req), code);
|
||||
g_assert(!flags);
|
||||
g_assert(gbinder_remote_request_sender_pid(req) == getpid());
|
||||
g_assert(gbinder_remote_request_sender_euid(req) == geteuid());
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), "test"));
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "message"));
|
||||
g_assert(code == 1);
|
||||
|
||||
test->obj = gbinder_local_object_ref(obj);
|
||||
test->req = gbinder_remote_request_ref(req);
|
||||
test->loop = (GMainLoop*)loop;
|
||||
|
||||
gbinder_remote_request_block(req);
|
||||
gbinder_remote_request_block(req); /* wrong state; has no effect */
|
||||
|
||||
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, test_transact_async_reply, test,
|
||||
test_transact_async_done);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_transact_async(
|
||||
void)
|
||||
{
|
||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||
const int fd = gbinder_driver_fd(ipc->driver);
|
||||
const char* dev = gbinder_driver_dev(ipc->driver);
|
||||
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object
|
||||
(ipc, "test", test_transact_async_proc, loop);
|
||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||
GBinderOutputData* data;
|
||||
GBinderWriter writer;
|
||||
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
prot->write_rpc_header(&writer, "test");
|
||||
gbinder_writer_append_string8(&writer, "message");
|
||||
data = gbinder_local_request_data(req);
|
||||
|
||||
test_binder_br_transaction(fd, obj, 1, data->bytes);
|
||||
test_run(&test_opt, loop);
|
||||
|
||||
/* Now we need to wait until GBinderIpc is destroyed */
|
||||
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||
gbinder_local_object_unref(obj);
|
||||
gbinder_local_request_unref(req);
|
||||
g_idle_add(test_unref_ipc, ipc);
|
||||
test_run(&test_opt, loop);
|
||||
|
||||
g_main_loop_unref(loop);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* transact_async_sync
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
test_transact_async_sync_proc(
|
||||
GBinderLocalObject* obj,
|
||||
GBinderRemoteRequest* req,
|
||||
guint code,
|
||||
guint flags,
|
||||
int* status,
|
||||
void* loop)
|
||||
{
|
||||
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
|
||||
|
||||
GVERBOSE_("\"%s\" %u", gbinder_remote_request_interface(req), code);
|
||||
g_assert(!flags);
|
||||
g_assert(gbinder_remote_request_sender_pid(req) == getpid());
|
||||
g_assert(gbinder_remote_request_sender_euid(req) == geteuid());
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), "test"));
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "message"));
|
||||
g_assert(code == 1);
|
||||
|
||||
/* Block and immediately complete the call */
|
||||
gbinder_remote_request_block(req);
|
||||
gbinder_remote_request_complete(req, reply, 0);
|
||||
gbinder_remote_request_complete(req, reply, 0); /* This one is ignored */
|
||||
gbinder_local_reply_unref(reply);
|
||||
|
||||
test_quit_later((GMainLoop*)loop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_transact_async_sync(
|
||||
void)
|
||||
{
|
||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||
const int fd = gbinder_driver_fd(ipc->driver);
|
||||
const char* dev = gbinder_driver_dev(ipc->driver);
|
||||
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object
|
||||
(ipc, "test", test_transact_async_sync_proc, loop);
|
||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||
GBinderOutputData* data;
|
||||
GBinderWriter writer;
|
||||
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
prot->write_rpc_header(&writer, "test");
|
||||
gbinder_writer_append_string8(&writer, "message");
|
||||
data = gbinder_local_request_data(req);
|
||||
|
||||
test_binder_br_transaction(fd, obj, 1, data->bytes);
|
||||
test_run(&test_opt, loop);
|
||||
|
||||
/* Now we need to wait until GBinderIpc is destroyed */
|
||||
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||
gbinder_local_object_unref(obj);
|
||||
gbinder_local_request_unref(req);
|
||||
g_idle_add(test_unref_ipc, ipc);
|
||||
test_run(&test_opt, loop);
|
||||
|
||||
g_main_loop_unref(loop);
|
||||
@@ -726,26 +900,28 @@ test_transact_status_reply(
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_PREFIX "/ipc/"
|
||||
#define TEST_(t) TEST_PREFIX t
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func(TEST_PREFIX "null", test_null);
|
||||
g_test_add_func(TEST_PREFIX "basic", test_basic);
|
||||
g_test_add_func(TEST_PREFIX "sync_oneway", test_sync_oneway);
|
||||
g_test_add_func(TEST_PREFIX "sync_reply_ok", test_sync_reply_ok);
|
||||
g_test_add_func(TEST_PREFIX "sync_reply_error", test_sync_reply_error);
|
||||
g_test_add_func(TEST_PREFIX "transact_ok", test_transact_ok);
|
||||
g_test_add_func(TEST_PREFIX "transact_dead", test_transact_dead);
|
||||
g_test_add_func(TEST_PREFIX "transact_failed", test_transact_failed);
|
||||
g_test_add_func(TEST_PREFIX "transact_status", test_transact_status);
|
||||
g_test_add_func(TEST_PREFIX "transact_custom", test_transact_custom);
|
||||
g_test_add_func(TEST_PREFIX "transact_custom2", test_transact_custom2);
|
||||
g_test_add_func(TEST_PREFIX "transact_cancel", test_transact_cancel);
|
||||
g_test_add_func(TEST_PREFIX "transact_cancel2", test_transact_cancel2);
|
||||
g_test_add_func(TEST_PREFIX "transact_incoming", test_transact_incoming);
|
||||
g_test_add_func(TEST_PREFIX "transact_status_reply",
|
||||
test_transact_status_reply);
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("sync_oneway"), test_sync_oneway);
|
||||
g_test_add_func(TEST_("sync_reply_ok"), test_sync_reply_ok);
|
||||
g_test_add_func(TEST_("sync_reply_error"), test_sync_reply_error);
|
||||
g_test_add_func(TEST_("transact_ok"), test_transact_ok);
|
||||
g_test_add_func(TEST_("transact_dead"), test_transact_dead);
|
||||
g_test_add_func(TEST_("transact_failed"), test_transact_failed);
|
||||
g_test_add_func(TEST_("transact_status"), test_transact_status);
|
||||
g_test_add_func(TEST_("transact_custom"), test_transact_custom);
|
||||
g_test_add_func(TEST_("transact_custom2"), test_transact_custom2);
|
||||
g_test_add_func(TEST_("transact_cancel"), test_transact_cancel);
|
||||
g_test_add_func(TEST_("transact_cancel2"), test_transact_cancel2);
|
||||
g_test_add_func(TEST_("transact_incoming"), test_transact_incoming);
|
||||
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_sync"), test_transact_async_sync);
|
||||
test_init(&test_opt, argc, argv);
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
@@ -73,7 +73,8 @@ test_reader_data_init_for_reply(
|
||||
GUtilIntArray* offsets = gbinder_output_data_offsets(out);
|
||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
|
||||
g_memdup(out->bytes->data, out->bytes->len), out->bytes->len);
|
||||
g_memdup(out->bytes->data, out->bytes->len),
|
||||
out->bytes->len, NULL);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->buffer = buf;
|
||||
@@ -206,8 +207,9 @@ test_ping(
|
||||
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
|
||||
GBinderLocalReply* reply;
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
|
||||
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
|
||||
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
|
||||
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||
sizeof(req_data), NULL));
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), base_interface));
|
||||
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
||||
HIDL_PING_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||
@@ -248,8 +250,9 @@ test_get_descriptor(
|
||||
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
|
||||
GBinderLocalReply* reply;
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
|
||||
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
|
||||
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
|
||||
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||
sizeof(req_data), NULL));
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), base_interface));
|
||||
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
||||
HIDL_GET_DESCRIPTOR_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||
@@ -303,8 +306,9 @@ test_descriptor_chain(
|
||||
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
|
||||
GBinderLocalReply* reply;
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
|
||||
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
|
||||
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
|
||||
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||
sizeof(req_data), NULL));
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), base_interface));
|
||||
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
||||
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||
@@ -374,8 +378,9 @@ test_custom_iface(
|
||||
char** strv;
|
||||
char* str;
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
|
||||
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
|
||||
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
|
||||
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||
sizeof(req_data), NULL));
|
||||
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
||||
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||
g_assert(gbinder_local_object_can_handle_transaction(obj, custom_iface,
|
||||
@@ -474,8 +479,9 @@ test_reply_status(
|
||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object(ipc, custom_iface,
|
||||
test_reply_status_handler, &count);
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
|
||||
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
|
||||
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
|
||||
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||
sizeof(req_data), NULL));
|
||||
|
||||
/* Execute the custom transaction */
|
||||
g_assert(!gbinder_local_object_handle_transaction(obj, req,
|
||||
|
||||
@@ -67,7 +67,7 @@ test_buffer_from_bytes(
|
||||
{
|
||||
/* Prevent double free */
|
||||
test_binder_set_destroy(gbinder_driver_fd(driver), bytes->data, NULL);
|
||||
return gbinder_buffer_new(driver, bytes->data, bytes->len);
|
||||
return gbinder_buffer_new(driver, bytes->data, bytes->len, NULL);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
@@ -88,7 +88,7 @@ test_null(
|
||||
gbinder_local_reply_init_writer(NULL, NULL);
|
||||
gbinder_local_reply_init_writer(NULL, &writer);
|
||||
g_assert(!gbinder_local_reply_data(NULL));
|
||||
g_assert(!gbinder_local_reply_new_from_data(NULL, NULL));
|
||||
g_assert(!gbinder_local_reply_new_from_data(NULL));
|
||||
|
||||
gbinder_local_reply_cleanup(NULL, NULL, &count);
|
||||
gbinder_local_reply_cleanup(NULL, test_int_inc, &count);
|
||||
@@ -359,7 +359,7 @@ test_hidl_string(
|
||||
offsets = gbinder_output_data_offsets(data);
|
||||
g_assert(offsets->count == 1);
|
||||
g_assert(offsets->data[0] == 0);
|
||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlString));
|
||||
g_assert(gbinder_output_data_buffers_size(data)==sizeof(GBinderHidlString));
|
||||
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
||||
gbinder_local_reply_unref(reply);
|
||||
}
|
||||
@@ -382,7 +382,7 @@ test_hidl_string_vec(
|
||||
offsets = gbinder_output_data_offsets(data);
|
||||
g_assert(offsets->count == 1);
|
||||
g_assert(offsets->data[0] == 0);
|
||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlVec));
|
||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(GBinderHidlVec));
|
||||
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
||||
gbinder_local_reply_unref(reply);
|
||||
}
|
||||
@@ -479,7 +479,7 @@ test_remote_reply(
|
||||
|
||||
/* Copy flat structures (no binder objects) */
|
||||
buffer = test_buffer_from_bytes(driver, bytes);
|
||||
req2 = gbinder_local_reply_new_from_data(buffer, NULL);
|
||||
req2 = gbinder_local_reply_new_from_data(buffer);
|
||||
gbinder_buffer_free(buffer);
|
||||
|
||||
data2 = gbinder_local_reply_data(req2);
|
||||
|
||||
@@ -65,7 +65,19 @@ test_buffer_from_bytes(
|
||||
{
|
||||
/* Prevent double free */
|
||||
test_binder_set_destroy(gbinder_driver_fd(driver), bytes->data, NULL);
|
||||
return gbinder_buffer_new(driver, bytes->data, bytes->len);
|
||||
return gbinder_buffer_new(driver, bytes->data, bytes->len, NULL);
|
||||
}
|
||||
|
||||
static
|
||||
GBinderBuffer*
|
||||
test_buffer_from_bytes_and_objects(
|
||||
GBinderDriver* driver,
|
||||
const GByteArray* bytes,
|
||||
void** objects)
|
||||
{
|
||||
/* Prevent double free */
|
||||
test_binder_set_destroy(gbinder_driver_fd(driver), bytes->data, NULL);
|
||||
return gbinder_buffer_new(driver, bytes->data, bytes->len, objects);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
@@ -82,7 +94,7 @@ test_null(
|
||||
|
||||
g_assert(!gbinder_local_request_new(NULL, NULL));
|
||||
g_assert(!gbinder_local_request_ref(NULL));
|
||||
g_assert(!gbinder_local_request_new_from_data(NULL, NULL));
|
||||
g_assert(!gbinder_local_request_new_from_data(NULL));
|
||||
gbinder_local_request_unref(NULL);
|
||||
gbinder_local_request_init_writer(NULL, NULL);
|
||||
gbinder_local_request_init_writer(NULL, &writer);
|
||||
@@ -375,7 +387,7 @@ test_hidl_string(
|
||||
offsets = gbinder_output_data_offsets(data);
|
||||
g_assert(offsets->count == 1);
|
||||
g_assert(offsets->data[0] == 0);
|
||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlString));
|
||||
g_assert(gbinder_output_data_buffers_size(data)==sizeof(GBinderHidlString));
|
||||
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
@@ -398,7 +410,7 @@ test_hidl_string_vec(
|
||||
offsets = gbinder_output_data_offsets(data);
|
||||
g_assert(offsets->count == 1);
|
||||
g_assert(offsets->data[0] == 0);
|
||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlVec));
|
||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(GBinderHidlVec));
|
||||
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
@@ -471,14 +483,14 @@ test_remote_request(
|
||||
const GByteArray* bytes;
|
||||
const GByteArray* bytes2;
|
||||
GBinderBuffer* buffer;
|
||||
void* no_obj = NULL;
|
||||
void** no_obj = g_new0(void*, 1);
|
||||
|
||||
gbinder_local_request_append_string8(req, input);
|
||||
bytes = gbinder_local_request_data(req)->bytes;
|
||||
|
||||
/* Copy flat structures (no binder objects) */
|
||||
buffer = test_buffer_from_bytes(driver, bytes);
|
||||
req2 = gbinder_local_request_new_from_data(buffer, NULL);
|
||||
req2 = gbinder_local_request_new_from_data(buffer);
|
||||
gbinder_buffer_free(buffer);
|
||||
|
||||
data2 = gbinder_local_request_data(req2);
|
||||
@@ -490,8 +502,8 @@ test_remote_request(
|
||||
gbinder_local_request_unref(req2);
|
||||
|
||||
/* Same thing but with non-NULL (albeit empty) array of objects */
|
||||
buffer = test_buffer_from_bytes(driver, bytes);
|
||||
req2 = gbinder_local_request_new_from_data(buffer, &no_obj);
|
||||
buffer = test_buffer_from_bytes_and_objects(driver, bytes, no_obj);
|
||||
req2 = gbinder_local_request_new_from_data(buffer);
|
||||
gbinder_buffer_free(buffer);
|
||||
|
||||
data2 = gbinder_local_request_data(req2);
|
||||
@@ -525,8 +537,9 @@ test_remote_request_obj_validate_data(
|
||||
g_assert(offsets->data[1] == 4 + BUFFER_OBJECT_SIZE_64);
|
||||
g_assert(offsets->data[2] == 4 + 2*BUFFER_OBJECT_SIZE_64);
|
||||
g_assert(bytes->len == 4 + 2*BUFFER_OBJECT_SIZE_64 + BINDER_OBJECT_SIZE_64);
|
||||
/* HidlString + the contents (2 bytes) aligned at 8-byte boundary */
|
||||
g_assert(gbinder_output_data_buffers_size(data) == (sizeof(HidlString)+8));
|
||||
/* GBinderHidlString + the contents (2 bytes) aligned at 8-byte boundary */
|
||||
g_assert(gbinder_output_data_buffers_size(data) ==
|
||||
(sizeof(GBinderHidlString) + 8));
|
||||
}
|
||||
|
||||
static
|
||||
@@ -558,15 +571,15 @@ test_remote_request_obj(
|
||||
objects[i] = bytes->data + offsets->data[i];
|
||||
}
|
||||
|
||||
buffer = test_buffer_from_bytes(driver, data->bytes);
|
||||
req2 = gbinder_local_request_new_from_data(buffer, objects);
|
||||
buffer = test_buffer_from_bytes_and_objects(driver, data->bytes, objects);
|
||||
req2 = gbinder_local_request_new_from_data(buffer);
|
||||
gbinder_buffer_free(buffer);
|
||||
g_free(objects);
|
||||
|
||||
test_remote_request_obj_validate_data(gbinder_local_request_data(req2));
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
/* req2 has to be freed first because req owns data */
|
||||
gbinder_local_request_unref(req2);
|
||||
gbinder_local_request_unref(req);
|
||||
gbinder_driver_unref(driver);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,22 +91,44 @@ test_device(
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* no_header
|
||||
* no_header1
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_no_header(
|
||||
test_no_header1(
|
||||
void)
|
||||
{
|
||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||
gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER), 0, 0);
|
||||
|
||||
gbinder_remote_request_set_data(req, NULL, NULL);
|
||||
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION, NULL);
|
||||
g_assert(!gbinder_remote_request_interface(req));
|
||||
gbinder_remote_request_unref(req);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* no_header2
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_no_header2(
|
||||
void)
|
||||
{
|
||||
const GBinderRpcProtocol* p = &gbinder_rpc_protocol_binder;
|
||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, p);
|
||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL, p, 0, 0);
|
||||
|
||||
gbinder_remote_request_set_data(req, GBINDER_DUMP_TRANSACTION,
|
||||
gbinder_buffer_new(driver,
|
||||
g_memdup(TEST_ARRAY_AND_SIZE(test_header_binder)),
|
||||
sizeof(test_header_binder), NULL));
|
||||
g_assert(!gbinder_remote_request_interface(req));
|
||||
gbinder_remote_request_unref(req);
|
||||
gbinder_driver_unref(driver);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* write_header
|
||||
*==========================================================================*/
|
||||
@@ -144,38 +166,39 @@ test_read_header(
|
||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||
gbinder_rpc_protocol_for_device(test->dev), 0, 0);
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
||||
g_memdup(test->header, test->header_size), test->header_size), NULL);
|
||||
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||
gbinder_buffer_new(driver, g_memdup(test->header, test->header_size),
|
||||
test->header_size, NULL));
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), test->iface));
|
||||
gbinder_remote_request_unref(req);
|
||||
gbinder_driver_unref(driver);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
/*==========================================================================*
|
||||
* Common
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_PREFIX "/protocol/"
|
||||
#define TEST_(t) TEST_PREFIX t
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func(TEST_PREFIX "device", test_device);
|
||||
g_test_add_func(TEST_PREFIX "no_header", test_no_header);
|
||||
g_test_add_func(TEST_("device"), test_device);
|
||||
g_test_add_func(TEST_("no_header1"), test_no_header1);
|
||||
g_test_add_func(TEST_("no_header2"), test_no_header2);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_header_tests); i++) {
|
||||
const TestHeaderData* test = test_header_tests + i;
|
||||
char* path = g_strconcat(TEST_PREFIX, "/", test->name,
|
||||
"/read_header", NULL);
|
||||
char* path;
|
||||
|
||||
path = g_strconcat(TEST_PREFIX, test->name, "/read_header", NULL);
|
||||
g_test_add_data_func(path, test, test_read_header);
|
||||
g_free(path);
|
||||
|
||||
path = g_strconcat(TEST_PREFIX, "/", test->name,
|
||||
"/write_header", NULL);
|
||||
|
||||
path = g_strconcat(TEST_PREFIX, test->name, "/write_header", NULL);
|
||||
g_test_add_data_func(path, test, test_write_header);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -59,7 +59,7 @@ test_null(
|
||||
|
||||
g_assert(!gbinder_remote_reply_ref(NULL));
|
||||
gbinder_remote_reply_unref(NULL);
|
||||
gbinder_remote_reply_set_data(NULL, NULL, NULL);
|
||||
gbinder_remote_reply_set_data(NULL, NULL);
|
||||
gbinder_remote_reply_init_reader(NULL, &reader);
|
||||
g_assert(gbinder_reader_at_end(&reader));
|
||||
g_assert(gbinder_remote_reply_is_empty(NULL));
|
||||
@@ -85,8 +85,8 @@ test_empty(
|
||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
||||
|
||||
gbinder_remote_reply_set_data
|
||||
(reply, gbinder_buffer_new(driver, NULL, 0), NULL);
|
||||
gbinder_remote_reply_set_data(reply,
|
||||
gbinder_buffer_new(driver, NULL, 0, NULL));
|
||||
|
||||
g_assert(gbinder_remote_reply_is_empty(reply));
|
||||
gbinder_remote_reply_unref(reply);
|
||||
@@ -132,8 +132,7 @@ test_int32(
|
||||
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
||||
|
||||
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
|
||||
NULL);
|
||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
|
||||
|
||||
g_assert(!gbinder_remote_reply_is_empty(reply));
|
||||
g_assert(gbinder_remote_reply_read_uint32(reply, &out1));
|
||||
@@ -163,8 +162,7 @@ test_int64(
|
||||
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
||||
|
||||
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
|
||||
NULL);
|
||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
|
||||
|
||||
g_assert(!gbinder_remote_reply_is_empty(reply));
|
||||
g_assert(gbinder_remote_reply_read_uint64(reply, &out1));
|
||||
@@ -192,8 +190,7 @@ test_string8(
|
||||
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
||||
|
||||
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
|
||||
NULL);
|
||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
|
||||
|
||||
g_assert(!gbinder_remote_reply_is_empty(reply));
|
||||
g_assert(!g_strcmp0(gbinder_remote_reply_read_string8(reply), "bar"));
|
||||
@@ -221,8 +218,7 @@ test_string16(
|
||||
char* str;
|
||||
|
||||
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
|
||||
NULL);
|
||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
|
||||
|
||||
g_assert(!gbinder_remote_reply_is_empty(reply));
|
||||
str = gbinder_remote_reply_read_string16(reply);
|
||||
@@ -264,7 +260,7 @@ test_to_local(
|
||||
/* Skip the 32-bit integer */
|
||||
objects[0] = req_data + 4;
|
||||
gbinder_remote_reply_set_data(req, gbinder_buffer_new(driver, req_data,
|
||||
sizeof(reply_data)), objects);
|
||||
sizeof(reply_data), objects));
|
||||
|
||||
/* Convert to GBinderLocalReply */
|
||||
req2 = gbinder_remote_reply_copy_to_local(req);
|
||||
|
||||
@@ -71,8 +71,10 @@ test_null(
|
||||
|
||||
g_assert(!gbinder_remote_request_ref(NULL));
|
||||
gbinder_remote_request_unref(NULL);
|
||||
gbinder_remote_request_set_data(NULL, NULL, NULL);
|
||||
gbinder_remote_request_set_data(NULL, 0, NULL);
|
||||
gbinder_remote_request_init_reader(NULL, &reader);
|
||||
gbinder_remote_request_block(NULL);
|
||||
gbinder_remote_request_complete(NULL, NULL, 0);
|
||||
g_assert(gbinder_reader_at_end(&reader));
|
||||
g_assert(!gbinder_remote_request_interface(NULL));
|
||||
g_assert(!gbinder_remote_request_copy_to_local(NULL));
|
||||
@@ -100,6 +102,10 @@ test_basic(
|
||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||
gbinder_rpc_protocol_for_device(NULL), 0, 0);
|
||||
|
||||
/* These two calls are wrong but won't cause problems: */
|
||||
gbinder_remote_request_block(req);
|
||||
gbinder_remote_request_complete(req, NULL, 0);
|
||||
|
||||
gbinder_remote_request_init_reader(req, &reader);
|
||||
g_assert(gbinder_reader_at_end(&reader));
|
||||
g_assert(!gbinder_remote_request_interface(req));
|
||||
@@ -118,7 +124,7 @@ void
|
||||
test_int32(
|
||||
void)
|
||||
{
|
||||
static const guint8 request_data [] = {
|
||||
static const guint8 req_data [] = {
|
||||
TEST_RPC_HEADER,
|
||||
TEST_INT32_BYTES(42)
|
||||
};
|
||||
@@ -129,9 +135,9 @@ test_int32(
|
||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
||||
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
|
||||
NULL);
|
||||
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
|
||||
sizeof(req_data), NULL));
|
||||
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||
g_assert(gbinder_remote_request_read_uint32(req, &out1));
|
||||
@@ -152,7 +158,7 @@ void
|
||||
test_int64(
|
||||
void)
|
||||
{
|
||||
static const guint8 request_data [] = {
|
||||
static const guint8 req_data [] = {
|
||||
TEST_RPC_HEADER,
|
||||
TEST_INT64_BYTES(42)
|
||||
};
|
||||
@@ -163,9 +169,9 @@ test_int64(
|
||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
||||
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
|
||||
NULL);
|
||||
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
|
||||
sizeof(req_data), NULL));
|
||||
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||
g_assert(gbinder_remote_request_read_uint64(req, &out1));
|
||||
@@ -186,7 +192,7 @@ void
|
||||
test_string8(
|
||||
void)
|
||||
{
|
||||
static const guint8 request_data [] = {
|
||||
static const guint8 req_data [] = {
|
||||
TEST_RPC_HEADER,
|
||||
'b', 'a', 'r', 0x00
|
||||
};
|
||||
@@ -195,9 +201,9 @@ test_string8(
|
||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
||||
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
|
||||
NULL);
|
||||
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
|
||||
sizeof(req_data), NULL));
|
||||
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "bar"));
|
||||
@@ -215,7 +221,7 @@ void
|
||||
test_string16(
|
||||
void)
|
||||
{
|
||||
static const guint8 request_data [] = {
|
||||
static const guint8 req_data [] = {
|
||||
TEST_RPC_HEADER,
|
||||
TEST_INT32_BYTES(3),
|
||||
TEST_INT16_BYTES('b'), TEST_INT16_BYTES('a'),
|
||||
@@ -227,9 +233,9 @@ test_string16(
|
||||
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
||||
char* str;
|
||||
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
||||
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
|
||||
NULL);
|
||||
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
|
||||
sizeof(req_data), NULL));
|
||||
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||
str = gbinder_remote_request_read_string16(req);
|
||||
@@ -272,8 +278,8 @@ test_to_local(
|
||||
|
||||
/* Skip the 32-bit integer */
|
||||
objects[0] = req_data + 4;
|
||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver, req_data,
|
||||
sizeof(request_data)), objects);
|
||||
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||
gbinder_buffer_new(driver, req_data, sizeof(request_data), objects));
|
||||
|
||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
static TestOpt test_opt;
|
||||
|
||||
#define BUFFER_OBJECT_SIZE_32 (24)
|
||||
@@ -74,8 +76,10 @@ test_null(
|
||||
gbinder_writer_append_string16(&writer, NULL);
|
||||
gbinder_writer_append_string16_len(NULL, NULL, 0);
|
||||
gbinder_writer_append_string16_len(&writer, NULL, 0);
|
||||
gbinder_writer_append_string16_utf16(NULL, NULL, 0);
|
||||
gbinder_writer_append_bool(NULL, FALSE);
|
||||
gbinder_writer_append_bool(&writer, FALSE);
|
||||
gbinder_writer_append_fd(NULL, 0);
|
||||
gbinder_writer_append_bytes(NULL, NULL, 0);
|
||||
gbinder_writer_append_bytes(&writer, NULL, 0);
|
||||
gbinder_writer_append_hidl_vec(NULL, NULL, 0, 0);
|
||||
@@ -93,9 +97,51 @@ test_null(
|
||||
gbinder_writer_append_remote_object(&writer, NULL);
|
||||
gbinder_writer_append_byte_array(NULL, NULL, 0);
|
||||
gbinder_writer_append_byte_array(&writer, NULL, 0);
|
||||
gbinder_writer_add_cleanup(NULL, NULL, 0);
|
||||
gbinder_writer_add_cleanup(NULL, g_free, 0);
|
||||
gbinder_writer_overwrite_int32(NULL, 0, 0);
|
||||
|
||||
g_assert(!gbinder_output_data_offsets(NULL));
|
||||
g_assert(!gbinder_output_data_buffers_size(NULL));
|
||||
g_assert(!gbinder_writer_malloc(NULL, 0));
|
||||
g_assert(!gbinder_writer_malloc0(NULL, 0));
|
||||
g_assert(!gbinder_writer_memdup(&writer, NULL, 0));
|
||||
g_assert(!gbinder_writer_memdup(NULL, &writer, 0));
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* cleanup
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_cleanup_fn(
|
||||
gpointer ptr)
|
||||
{
|
||||
(*((int*)ptr))++;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_cleanup(
|
||||
void)
|
||||
{
|
||||
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||
GBinderWriter writer;
|
||||
int cleanup_count = 0;
|
||||
int value = 42;
|
||||
int* zero;
|
||||
int* copy;
|
||||
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
zero = gbinder_writer_new0(&writer, int);
|
||||
copy = gbinder_writer_memdup(&writer, &value, sizeof(value));
|
||||
g_assert(*zero == 0);
|
||||
g_assert(*copy == value);
|
||||
gbinder_writer_add_cleanup(&writer, test_cleanup_fn, &cleanup_count);
|
||||
gbinder_writer_add_cleanup(&writer, test_cleanup_fn, &cleanup_count);
|
||||
gbinder_local_request_unref(req);
|
||||
g_assert(cleanup_count == 2);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
@@ -119,6 +165,19 @@ test_int32(
|
||||
g_assert(!gbinder_output_data_buffers_size(data));
|
||||
g_assert(data->bytes->len == sizeof(value));
|
||||
g_assert(!memcmp(data->bytes->data, &value, data->bytes->len));
|
||||
|
||||
const guint32 value2 = 2345678;
|
||||
gbinder_writer_overwrite_int32(&writer, 0, value2);
|
||||
data = gbinder_local_request_data(req);
|
||||
g_assert(!gbinder_output_data_offsets(data));
|
||||
g_assert(!gbinder_output_data_buffers_size(data));
|
||||
g_assert(data->bytes->len == sizeof(value2));
|
||||
g_assert(!memcmp(data->bytes->data, &value2, data->bytes->len));
|
||||
|
||||
// test overlap over the end of the buffer
|
||||
gbinder_writer_overwrite_int32(&writer, 2, value2);
|
||||
g_assert(data->bytes->len == sizeof(value2));
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -342,6 +401,75 @@ test_string16(
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* utf16
|
||||
*==========================================================================*/
|
||||
|
||||
typedef struct test_utf16_data {
|
||||
const char* name;
|
||||
const gunichar2* in;
|
||||
gssize in_len;
|
||||
const guint8* out;
|
||||
gssize out_len;
|
||||
} TestUtf16Data;
|
||||
|
||||
static const guint8 utf16_tests_data_null[] = {
|
||||
TEST_INT32_BYTES(-1)
|
||||
};
|
||||
|
||||
static const guint8 utf16_tests_data_empty[] = {
|
||||
TEST_INT32_BYTES(0),
|
||||
0x00, 0x00, 0xff, 0xff
|
||||
};
|
||||
|
||||
static const guint8 utf16_tests_data_x[] = {
|
||||
TEST_INT32_BYTES(1),
|
||||
TEST_INT16_BYTES('x'), 0x00, 0x00
|
||||
};
|
||||
|
||||
static const guint8 utf16_tests_data_xy[] = {
|
||||
TEST_INT32_BYTES(2),
|
||||
TEST_INT16_BYTES('x'), TEST_INT16_BYTES('y'),
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const gunichar2 utf16_tests_input_empty[] = { 0 };
|
||||
static const gunichar2 utf16_tests_input_x[] = { 'x', 0 };
|
||||
static const gunichar2 utf16_tests_input_xy[] = { 'x', 'y', 0 };
|
||||
|
||||
static const TestUtf16Data test_utf16_tests[] = {
|
||||
{ "null", NULL, -1,
|
||||
TEST_ARRAY_AND_SIZE(utf16_tests_data_null) },
|
||||
{ "empty", utf16_tests_input_empty, -1,
|
||||
TEST_ARRAY_AND_SIZE(utf16_tests_data_empty) },
|
||||
{ "1", utf16_tests_input_x, -1,
|
||||
TEST_ARRAY_AND_SIZE(utf16_tests_data_x) },
|
||||
{ "2", utf16_tests_input_xy, 1,
|
||||
TEST_ARRAY_AND_SIZE(utf16_tests_data_x) },
|
||||
{ "3", utf16_tests_input_xy, -1,
|
||||
TEST_ARRAY_AND_SIZE(utf16_tests_data_xy) }
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
test_utf16(
|
||||
gconstpointer test_data)
|
||||
{
|
||||
const TestUtf16Data* test = test_data;
|
||||
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||
GBinderOutputData* data;
|
||||
GBinderWriter writer;
|
||||
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
gbinder_writer_append_string16_utf16(&writer, test->in, test->in_len);
|
||||
data = gbinder_local_request_data(req);
|
||||
g_assert(!gbinder_output_data_offsets(data));
|
||||
g_assert(!gbinder_output_data_buffers_size(data));
|
||||
g_assert(data->bytes->len == test->out_len);
|
||||
g_assert(!memcmp(data->bytes->data, test->out, test->out_len));
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* hidl_vec
|
||||
*==========================================================================*/
|
||||
@@ -366,15 +494,15 @@ static guint test_hidl_vec_offsets_64[] =
|
||||
|
||||
static const TestHidlVecData test_hidl_vec_tests[] = {
|
||||
{ "32/null", &gbinder_io_32, NULL, 0, 0,
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(HidlVec) },
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(GBinderHidlVec) },
|
||||
{ "32/2x1", &gbinder_io_32, "xy", 2, 1,
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_32),
|
||||
sizeof(HidlVec) + 8 /* vec data aligned at 8 bytes boundary */ },
|
||||
sizeof(GBinderHidlVec) + 8 /* vec data aligned at 8 bytes boundary */ },
|
||||
{ "64/null", &gbinder_io_64, NULL, 0, 0,
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(HidlVec) },
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(GBinderHidlVec) },
|
||||
{ "64/2x2", &gbinder_io_64, "xxyy", 2, 2,
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_64),
|
||||
sizeof(HidlVec) + 8 /* vec data aligned at 8 bytes boundary */ }
|
||||
sizeof(GBinderHidlVec) + 8 /* vec data aligned at 8 bytes boundary */ }
|
||||
};
|
||||
|
||||
static
|
||||
@@ -425,15 +553,17 @@ static guint test_hidl_string_offsets_64[] =
|
||||
|
||||
static const TestHidlStringData test_hidl_string_tests[] = {
|
||||
{ "32/null", &gbinder_io_32, NULL,
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0), sizeof(HidlString) },
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0),
|
||||
sizeof(GBinderHidlString) },
|
||||
{ "32/xxx", &gbinder_io_32, "xxx",
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_32),
|
||||
sizeof(HidlString) + 8 /* string data aligned at 8 bytes boundary */ },
|
||||
sizeof(GBinderHidlString) + 8 /* string data aligned at 8 bytes */ },
|
||||
{ "64/null", &gbinder_io_64, NULL,
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0), sizeof(HidlString) },
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0),
|
||||
sizeof(GBinderHidlString) },
|
||||
{ "64/xxxxxxx", &gbinder_io_64, "xxxxxxx",
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_64),
|
||||
sizeof(HidlString) + 8 /* string data aligned at 8 bytes boundary */ }
|
||||
sizeof(GBinderHidlString) + 8 /* string data aligned at 8 bytes */ }
|
||||
};
|
||||
|
||||
static
|
||||
@@ -481,8 +611,9 @@ test_hidl_string2(
|
||||
g_assert(offsets->data[0] == 0);
|
||||
g_assert(offsets->data[1] == BUFFER_OBJECT_SIZE_32);
|
||||
g_assert(offsets->data[2] == 2*BUFFER_OBJECT_SIZE_32);
|
||||
/* 2 HidlStrings + "foo" aligned at 8 bytes boundary */
|
||||
g_assert(gbinder_output_data_buffers_size(data) == 2*sizeof(HidlString)+8);
|
||||
/* 2 GBinderHidlStrings + "foo" aligned at 8 bytes boundary */
|
||||
g_assert(gbinder_output_data_buffers_size(data) ==
|
||||
(2 * sizeof(GBinderHidlString) + 8));
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
@@ -513,18 +644,18 @@ static guint test_hidl_string_vec_offsets_1_64[] =
|
||||
static const TestHidlStringVecData test_hidl_string_vec_tests[] = {
|
||||
{ "32/null", &gbinder_io_32, NULL, -1,
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
|
||||
sizeof(HidlVec) },
|
||||
sizeof(GBinderHidlVec) },
|
||||
{ "32/1", &gbinder_io_32,
|
||||
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_1_32),
|
||||
sizeof(HidlVec) + sizeof(HidlString) + 8 },
|
||||
sizeof(GBinderHidlVec) + sizeof(GBinderHidlString) + 8 },
|
||||
{ "64/null", &gbinder_io_64, NULL, -1,
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
|
||||
sizeof(HidlVec) },
|
||||
sizeof(GBinderHidlVec) },
|
||||
{ "64/1", &gbinder_io_64,
|
||||
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),
|
||||
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_1_64),
|
||||
sizeof(HidlVec) + sizeof(HidlString) + 8 },
|
||||
sizeof(GBinderHidlVec) + sizeof(GBinderHidlString) + 8 },
|
||||
};
|
||||
|
||||
static
|
||||
@@ -633,6 +764,76 @@ test_parent(
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* fd
|
||||
* fd_invalid
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_fd2(
|
||||
int fd)
|
||||
{
|
||||
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||
GBinderOutputData* data;
|
||||
GUtilIntArray* offsets;
|
||||
GBinderWriter writer;
|
||||
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
gbinder_writer_append_fd(&writer, fd);
|
||||
data = gbinder_local_request_data(req);
|
||||
offsets = gbinder_output_data_offsets(data);
|
||||
g_assert(offsets);
|
||||
g_assert(offsets->count == 1);
|
||||
g_assert(offsets->data[0] == 0);
|
||||
g_assert(!gbinder_output_data_buffers_size(data));
|
||||
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_fd(
|
||||
void)
|
||||
{
|
||||
test_fd2(0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_fd_invalid(
|
||||
void)
|
||||
{
|
||||
test_fd2(-1);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* fd_close_error
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_fd_close_error(
|
||||
void)
|
||||
{
|
||||
const GBinderIo* io = &gbinder_io_32;
|
||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||
GBinderOutputData* data;
|
||||
GBinderWriter writer;
|
||||
int fd = -1;
|
||||
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
gbinder_writer_append_fd(&writer, STDOUT_FILENO);
|
||||
data = gbinder_local_request_data(req);
|
||||
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
|
||||
|
||||
/* Fetch duplicated fd and close it. That makes the second close
|
||||
* done by gbinder_writer_data_close_fd() fail. */
|
||||
g_assert(io->decode_fd_object(data->bytes->data, data->bytes->len, &fd));
|
||||
g_assert(close(fd) == 0);
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* local_object
|
||||
*==========================================================================*/
|
||||
@@ -737,46 +938,76 @@ test_byte_array(
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* bytes_written
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_bytes_written(
|
||||
void)
|
||||
{
|
||||
const guint32 value = 1234567;
|
||||
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||
GBinderWriter writer;
|
||||
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
g_assert(gbinder_writer_bytes_written(&writer) == 0);
|
||||
gbinder_writer_append_int32(&writer, value);
|
||||
g_assert(gbinder_writer_bytes_written(&writer) == sizeof(value));
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
}
|
||||
/*==========================================================================*
|
||||
* Common
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_PREFIX "/writer/"
|
||||
#define TEST_(t) TEST_PREFIX t
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func(TEST_PREFIX "null", test_null);
|
||||
g_test_add_func(TEST_PREFIX "int32", test_int32);
|
||||
g_test_add_func(TEST_PREFIX "int64", test_int64);
|
||||
g_test_add_func(TEST_PREFIX "float", test_float);
|
||||
g_test_add_func(TEST_PREFIX "double", test_double);
|
||||
g_test_add_func(TEST_PREFIX "bool", test_bool);
|
||||
g_test_add_func(TEST_PREFIX "bytes", test_bytes);
|
||||
g_test_add_func(TEST_PREFIX "string8", test_string8);
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("cleanup"), test_cleanup);
|
||||
g_test_add_func(TEST_("int32"), test_int32);
|
||||
g_test_add_func(TEST_("int64"), test_int64);
|
||||
g_test_add_func(TEST_("float"), test_float);
|
||||
g_test_add_func(TEST_("double"), test_double);
|
||||
g_test_add_func(TEST_("bool"), test_bool);
|
||||
g_test_add_func(TEST_("bytes"), test_bytes);
|
||||
g_test_add_func(TEST_("string8"), test_string8);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_string16_tests); i++) {
|
||||
const TestString16Data* test = test_string16_tests + i;
|
||||
char* path = g_strconcat(TEST_PREFIX "string16/", test->name, NULL);
|
||||
char* path = g_strconcat(TEST_("string16/"), test->name, NULL);
|
||||
|
||||
g_test_add_data_func(path, test, test_string16);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_utf16_tests); i++) {
|
||||
const TestUtf16Data* test = test_utf16_tests + i;
|
||||
char* path = g_strconcat(TEST_("utf16/"), test->name, NULL);
|
||||
|
||||
g_test_add_data_func(path, test, test_utf16);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_hidl_vec_tests); i++) {
|
||||
const TestHidlVecData* test = test_hidl_vec_tests + i;
|
||||
char* path = g_strconcat(TEST_PREFIX "hidl_vec/", test->name, NULL);
|
||||
char* path = g_strconcat(TEST_("hidl_vec/"), test->name, NULL);
|
||||
|
||||
g_test_add_data_func(path, test, test_hidl_vec);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
g_test_add_func(TEST_PREFIX "hidl_string/2strings", test_hidl_string2);
|
||||
g_test_add_func(TEST_("hidl_string/2strings"), test_hidl_string2);
|
||||
for (i = 0; i < G_N_ELEMENTS(test_hidl_string_tests); i++) {
|
||||
const TestHidlStringData* test = test_hidl_string_tests + i;
|
||||
char* path = g_strconcat(TEST_PREFIX "hidl_string/", test->name, NULL);
|
||||
char* path = g_strconcat(TEST_("hidl_string/"), test->name, NULL);
|
||||
|
||||
g_test_add_data_func(path, test, test_hidl_string);
|
||||
g_free(path);
|
||||
@@ -784,18 +1015,21 @@ int main(int argc, char* argv[])
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_hidl_string_vec_tests); i++) {
|
||||
const TestHidlStringVecData* test = test_hidl_string_vec_tests + i;
|
||||
char* path = g_strconcat(TEST_PREFIX "hidl_string_vec/",
|
||||
test->name, NULL);
|
||||
char* path = g_strconcat(TEST_("hidl_string_vec/"), test->name, NULL);
|
||||
|
||||
g_test_add_data_func(path, test, test_hidl_string_vec);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
g_test_add_func(TEST_PREFIX "buffer", test_buffer);
|
||||
g_test_add_func(TEST_PREFIX "parent", test_parent);
|
||||
g_test_add_func(TEST_PREFIX "local_object", test_local_object);
|
||||
g_test_add_func(TEST_PREFIX "remote_object", test_remote_object);
|
||||
g_test_add_func(TEST_PREFIX "byte_array", test_byte_array);
|
||||
g_test_add_func(TEST_("buffer"), test_buffer);
|
||||
g_test_add_func(TEST_("parent"), test_parent);
|
||||
g_test_add_func(TEST_("fd"), test_fd);
|
||||
g_test_add_func(TEST_("fd_invalid"), test_fd_invalid);
|
||||
g_test_add_func(TEST_("fd_close_error"), test_fd_close_error);
|
||||
g_test_add_func(TEST_("local_object"), test_local_object);
|
||||
g_test_add_func(TEST_("remote_object"), test_remote_object);
|
||||
g_test_add_func(TEST_("byte_array"), test_byte_array);
|
||||
g_test_add_func(TEST_("bytes_written"), test_bytes_written);
|
||||
test_init(&test_opt, argc, argv);
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user