Files
libgbinder/unit/unit_local_object/unit_local_object.c
2024-07-18 05:32:36 +03:00

859 lines
30 KiB
C

/*
* Copyright (C) 2018-2024 Slava Monich <slava@monich.com>
* Copyright (C) 2018-2022 Jolla Ltd.
*
* 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_buffer_p.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_output_data.h"
#include "gbinder_reader_p.h"
#include "gbinder_remote_request_p.h"
#include "gbinder_rpc_protocol.h"
#include <gutil_intarray.h>
#include <gutil_strv.h>
#include <gutil_log.h>
#include <errno.h>
static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-local-object-XXXXXX";
/* android.hidl.base@1.0::IBase */
#define TEST_BASE_INTERFACE_BYTES \
'a', 'n', 'd', 'r', 'o', 'i', 'd', '.', \
'h', 'i', 'd', 'l', '.', 'b', 'a', 's', \
'e', '@', '1', '.', '0', ':', ':', 'I', \
'B', 'a', 's', 'e'
#define TEST_BASE_INTERFACE_HEADER_BYTES \
TEST_BASE_INTERFACE_BYTES, 0x00, 0x00, 0x00, 0x00
static const char base_interface[] = { TEST_BASE_INTERFACE_BYTES, 0x00 };
static
void
test_reader_data_init_for_reply(
GBinderReaderData* data,
GBinderLocalObject* obj,
GBinderLocalReply* reply)
{
GBinderIpc* ipc = obj->ipc;
GBinderOutputData* out = gbinder_local_reply_data(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, NULL);
memset(data, 0, sizeof(*data));
data->buffer = buf;
data->reg = gbinder_object_registry_ref(reg);
g_assert(!gbinder_object_registry_get_local(reg, NULL));
g_assert(gbinder_object_registry_get_local(reg, obj) == obj);
gbinder_local_object_unref(obj); /* ref added by the above call */
if (offsets && offsets->count > 0) {
guint i;
data->objects = g_new(void*, offsets->count + 1);
for (i = 0; i < offsets->count; i++) {
data->objects[i] = (guint8*)buf->data + offsets->data[i];
}
data->objects[i] = NULL;
}
}
static
void
test_reader_data_cleanup(
GBinderReaderData* data)
{
gbinder_object_registry_unref(data->reg);
gbinder_buffer_free(data->buffer);
g_free(data->objects);
}
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
int status = 0;
g_assert(!gbinder_local_object_new(NULL, NULL, NULL, NULL));
g_assert(!gbinder_local_object_ref(NULL));
gbinder_local_object_unref(NULL);
gbinder_local_object_drop(NULL);
g_assert(!gbinder_local_object_new_reply(NULL));
g_assert(!gbinder_local_object_add_weak_refs_changed_handler(NULL,
NULL, NULL));
g_assert(!gbinder_local_object_add_strong_refs_changed_handler(NULL,
NULL, NULL));
gbinder_local_object_remove_handler(NULL, 0);
g_assert(gbinder_local_object_can_handle_transaction(NULL, NULL, 0) ==
GBINDER_LOCAL_TRANSACTION_NOT_SUPPORTED);
g_assert(!gbinder_local_object_handle_transaction(NULL, NULL, 0, 0, NULL));
g_assert(!gbinder_local_object_handle_transaction(NULL, NULL, 0, 0,
&status));
g_assert(!gbinder_local_object_handle_looper_transaction(NULL, NULL, 0, 0,
NULL));
g_assert(!gbinder_local_object_handle_looper_transaction(NULL, NULL, 0, 0,
&status));
g_assert(status == (-EBADMSG));
g_assert(!gbinder_ipc_transact_custom(NULL, NULL, NULL, NULL, NULL));
gbinder_local_object_handle_increfs(NULL);
gbinder_local_object_handle_decrefs(NULL);
gbinder_local_object_handle_acquire(NULL, NULL);
gbinder_local_object_handle_release(NULL);
gbinder_local_object_handle_release(NULL);
gbinder_local_object_set_stability(NULL, GBINDER_STABILITY_UNDECLARED);
}
/*==========================================================================*
* basic
*==========================================================================*/
static
void
test_basic(
void)
{
const char* const ifaces_foo[] = { "foo", NULL };
const char* const ifaces_bar[] = { "bar", NULL };
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderLocalObject* foo;
GBinderLocalObject* bar;
/* ipc is not a local object */
g_assert(!gbinder_object_registry_get_local(reg, ipc));
/* Create a new local objects */
foo = gbinder_local_object_new(ipc, ifaces_foo, NULL, NULL);
bar = gbinder_local_object_new(ipc, ifaces_bar, NULL, NULL);
/* But ipc is still not a local object! */
g_assert(!gbinder_object_registry_get_local(reg, ipc));
gbinder_ipc_unref(ipc);
g_assert(foo);
g_assert(!gbinder_local_object_add_weak_refs_changed_handler(foo,
NULL, NULL));
g_assert(!gbinder_local_object_add_strong_refs_changed_handler(foo,
NULL, NULL));
gbinder_local_object_remove_handler(foo, 0);
g_assert(gbinder_local_object_can_handle_transaction(foo,
base_interface, -1) == GBINDER_LOCAL_TRANSACTION_NOT_SUPPORTED);
gbinder_local_object_handle_increfs(foo);
gbinder_local_object_handle_decrefs(foo);
gbinder_local_object_handle_acquire(foo, NULL);
gbinder_local_object_handle_release(foo);
gbinder_local_object_unref(foo);
g_assert(bar);
g_assert(gbinder_local_object_ref(bar) == bar);
gbinder_local_object_drop(bar);
gbinder_local_object_unref(bar);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* ping
*==========================================================================*/
static
void
test_ping(
void)
{
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GBinderLocalReply* reply;
GBinderOutputData* out_data;
static const guint8 result[] = { 0x00, 0x00, 0x00, 0x00 };
g_assert(gbinder_local_object_can_handle_transaction(obj, NULL,
GBINDER_PING_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
* handled by handle_looper_transaction() */
g_assert(!gbinder_local_object_handle_transaction(obj, req,
GBINDER_PING_TRANSACTION, 0, &status));
g_assert(status == (-EBADMSG));
reply = gbinder_local_object_handle_looper_transaction(obj, req,
GBINDER_PING_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
out_data = gbinder_local_reply_data(reply);
g_assert(out_data);
g_assert(out_data->bytes);
g_assert(out_data->bytes->len == sizeof(result));
g_assert(!memcmp(out_data->bytes->data, result, sizeof(result)));
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* interface
*==========================================================================*/
static
void
test_interface(
void)
{
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
const char* const ifaces[] = { "x", NULL };
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
GBinderLocalReply* reply;
GBinderOutputData* out_data;
static const guint8 result[] = {
TEST_INT32_BYTES(1),
TEST_INT16_BYTES('x'), 0x00, 0x00
};
g_assert(gbinder_local_object_can_handle_transaction(obj, NULL,
GBINDER_INTERFACE_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
* handled by handle_looper_transaction() */
g_assert(!gbinder_local_object_handle_transaction(obj, req,
GBINDER_INTERFACE_TRANSACTION, 0, &status));
g_assert(status == (-EBADMSG));
reply = gbinder_local_object_handle_looper_transaction(obj, req,
GBINDER_INTERFACE_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
out_data = gbinder_local_reply_data(reply);
g_assert(out_data);
g_assert(out_data->bytes);
g_assert(out_data->bytes->len == sizeof(result));
g_assert(!memcmp(out_data->bytes->data, result, sizeof(result)));
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* hidl_ping
*==========================================================================*/
static
void
test_hidl_ping(
void)
{
static const guint8 req_data [] = { TEST_BASE_INTERFACE_HEADER_BYTES };
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GBinderLocalReply* reply;
GBinderOutputData* out_data;
static const guint8 result[] = { 0x00, 0x00, 0x00, 0x00 };
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);
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
* handled by handle_looper_transaction() */
g_assert(!gbinder_local_object_handle_transaction(obj, req,
HIDL_PING_TRANSACTION, 0, &status));
g_assert(status == (-EBADMSG));
reply = gbinder_local_object_handle_looper_transaction(obj, req,
HIDL_PING_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
out_data = gbinder_local_reply_data(reply);
g_assert(out_data);
g_assert(out_data->bytes);
g_assert(out_data->bytes->len == sizeof(result));
g_assert(!memcmp(out_data->bytes->data, result, sizeof(result)));
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* get_descriptor
*==========================================================================*/
static
void
test_get_descriptor(
void)
{
static const guint8 req_data [] = { TEST_BASE_INTERFACE_HEADER_BYTES };
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GBinderLocalReply* reply;
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);
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
* handled by handle_looper_transaction() */
g_assert(!gbinder_local_object_handle_transaction(obj, req,
HIDL_GET_DESCRIPTOR_TRANSACTION, 0, &status));
g_assert(status == (-EBADMSG));
reply = gbinder_local_object_handle_looper_transaction(obj, req,
HIDL_GET_DESCRIPTOR_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
/* Unsupported transaction */
g_assert(!gbinder_local_object_handle_looper_transaction
(obj, req, -1, 0, NULL));
g_assert(!gbinder_local_object_handle_looper_transaction
(obj, req, -1, 0, &status));
g_assert(status == (-EBADMSG));
g_assert(!gbinder_local_object_handle_transaction(obj, req, -1, 0, NULL));
g_assert(!gbinder_local_object_handle_transaction(obj, req, -1, 0,
&status));
g_assert(status == (-EBADMSG));
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* descriptor_chain
*==========================================================================*/
static
void
test_descriptor_chain(
void)
{
static const guint8 req_data [] = {
TEST_BASE_INTERFACE_HEADER_BYTES
};
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
GBinderLocalReply* reply;
GBinderOutputData* reply_data;
gbinder_remote_request_set_data(req, HIDL_DESCRIPTOR_CHAIN_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);
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
* handled by handle_looper_transaction() */
g_assert(!gbinder_local_object_handle_transaction(obj, req,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION, 0, &status));
g_assert(status == (-EBADMSG));
reply = gbinder_local_object_handle_looper_transaction(obj, req,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
/* Should get 3 buffers - vector, string and its contents */
reply_data = gbinder_local_reply_data(reply);
g_assert(gbinder_output_data_offsets(reply_data)->count == 3);
g_assert(gbinder_output_data_buffers_size(reply_data) == 64);
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* custom_call
*==========================================================================*/
#define CUSTOM_TRANSACTION (GBINDER_FIRST_CALL_TRANSACTION + 1)
#define CUSTOM_INTERFACE_BYTES 'f', 'o', 'o'
#define CUSTOM_INTERFACE_HEADER_BYTES CUSTOM_INTERFACE_BYTES, 0x00
static const char custom_iface[] = { CUSTOM_INTERFACE_BYTES, 0x00 };
static
GBinderLocalReply*
test_custom_iface_handler(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
int* count = user_data;
g_assert(!flags);
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), custom_iface));
g_assert(code == CUSTOM_TRANSACTION);
*status = GBINDER_STATUS_OK;
(*count)++;
return gbinder_local_object_new_reply(obj);
}
static
void
test_custom_iface(
void)
{
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
const char* const ifaces[] = { custom_iface, NULL };
int count = 0, status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
test_custom_iface_handler, &count);
GBinderLocalReply* reply;
GBinderReaderData reader_data;
GBinderReader reader;
char** strv;
char* str;
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,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) ==
GBINDER_LOCAL_TRANSACTION_SUPPORTED);
g_assert(gbinder_local_object_can_handle_transaction(obj, custom_iface,
CUSTOM_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_SUPPORTED);
/* This returns the custom interface */
reply = gbinder_local_object_handle_looper_transaction(obj, req,
HIDL_GET_DESCRIPTOR_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
/* Parse the reply and check the interface */
test_reader_data_init_for_reply(&reader_data, obj, reply);
gbinder_reader_init(&reader, &reader_data, 0, reader_data.buffer->size);
g_assert(gbinder_reader_read_int32(&reader, &status));
g_assert(status == GBINDER_STATUS_OK);
str = gbinder_reader_read_hidl_string(&reader);
g_assert(!g_strcmp0(str, custom_iface));
g_free(str);
test_reader_data_cleanup(&reader_data);
gbinder_local_reply_unref(reply);
/* And this returns two interfaces */
reply = gbinder_local_object_handle_looper_transaction(obj, req,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
/* Parse the reply and check the interface */
test_reader_data_init_for_reply(&reader_data, obj, reply);
gbinder_reader_init(&reader, &reader_data, 0, reader_data.buffer->size);
g_assert(gbinder_reader_read_int32(&reader, &status));
g_assert(status == GBINDER_STATUS_OK);
strv = gbinder_reader_read_hidl_string_vec(&reader);
g_assert(gutil_strv_length(strv) == 2);
g_assert(!g_strcmp0(strv[0], custom_iface));
g_assert(!g_strcmp0(strv[1], base_interface));
g_strfreev(strv);
test_reader_data_cleanup(&reader_data);
gbinder_local_reply_unref(reply);
/* Execute the custom transaction */
reply = gbinder_local_object_handle_transaction(obj, req,
CUSTOM_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
g_assert(count == 1);
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* reply_status
*==========================================================================*/
#define EXPECTED_STATUS (424242)
static
GBinderLocalReply*
test_reply_status_handler(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
int* count = user_data;
g_assert(!flags);
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), custom_iface));
g_assert(code == CUSTOM_TRANSACTION);
*status = EXPECTED_STATUS;
(*count)++;
return NULL;
}
static
void
test_reply_status(
void)
{
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
const char* const ifaces[] = { custom_iface, NULL };
int count = 0, status = 0;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
test_reply_status_handler, &count);
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,
CUSTOM_TRANSACTION, 0, &status));
g_assert(status == EXPECTED_STATUS);
g_assert(count == 1);
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* increfs
*==========================================================================*/
static
void
test_increfs_cb(
GBinderLocalObject* obj,
void* user_data)
{
GVERBOSE_("%d", obj->weak_refs);
g_assert(obj->weak_refs == 1);
test_quit_later((GMainLoop*)user_data);
}
static
void
test_increfs_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
gulong id = gbinder_local_object_add_weak_refs_changed_handler(obj,
test_increfs_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_increfs(fd, ANY_THREAD, ipc);
test_binder_br_increfs(fd, ANY_THREAD, obj);
test_run(&test_opt, loop);
g_assert(obj->weak_refs == 1);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
static
void
test_increfs(
void)
{
test_run_in_context(&test_opt, test_increfs_run);
}
/*==========================================================================*
* decrefs
*==========================================================================*/
static
void
test_decrefs_cb(
GBinderLocalObject* obj,
void* user_data)
{
GVERBOSE_("%d", obj->weak_refs);
if (!obj->weak_refs) {
test_quit_later((GMainLoop*)user_data);
}
}
static
void
test_decrefs_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
gulong id = gbinder_local_object_add_weak_refs_changed_handler(obj,
test_decrefs_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_decrefs(fd, ANY_THREAD, ipc);
test_binder_br_increfs(fd, ANY_THREAD, obj);
test_binder_br_decrefs(fd, ANY_THREAD, obj);
test_run(&test_opt, loop);
g_assert(obj->weak_refs == 0);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
static
void
test_decrefs(
void)
{
test_run_in_context(&test_opt, test_decrefs_run);
}
/*==========================================================================*
* acquire
*==========================================================================*/
static
void
test_acquire_cb(
GBinderLocalObject* obj,
void* user_data)
{
GVERBOSE_("%d", obj->strong_refs);
g_assert(obj->strong_refs == 1);
test_quit_later((GMainLoop*)user_data);
}
static
void
test_acquire_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
gulong id = gbinder_local_object_add_strong_refs_changed_handler(obj,
test_acquire_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_acquire(fd, ANY_THREAD, ipc);
test_binder_br_acquire(fd, ANY_THREAD, obj);
test_run(&test_opt, loop);
g_assert(obj->strong_refs == 1);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
static
void
test_acquire(
void)
{
test_run_in_context(&test_opt, test_acquire_run);
}
/*==========================================================================*
* release
*==========================================================================*/
static
void
test_release_cb(
GBinderLocalObject* obj,
void* user_data)
{
GVERBOSE_("%d", obj->strong_refs);
if (!obj->strong_refs) {
test_quit_later((GMainLoop*)user_data);
}
}
static
void
test_release_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
gulong id = gbinder_local_object_add_strong_refs_changed_handler(obj,
test_release_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_release(fd, ANY_THREAD, ipc);
test_binder_br_acquire(fd, ANY_THREAD, obj);
test_binder_br_release(fd, ANY_THREAD, obj);
test_run(&test_opt, loop);
g_assert(obj->strong_refs == 0);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
static
void
test_release(
void)
{
test_run_in_context(&test_opt, test_release_run);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/local_object/"
int main(int argc, char* argv[])
{
TestConfig test_config;
int result;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
g_type_init();
G_GNUC_END_IGNORE_DEPRECATIONS;
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 "ping", test_ping);
g_test_add_func(TEST_PREFIX "interface", test_interface);
g_test_add_func(TEST_PREFIX "hidl_ping", test_hidl_ping);
g_test_add_func(TEST_PREFIX "get_descriptor", test_get_descriptor);
g_test_add_func(TEST_PREFIX "descriptor_chain", test_descriptor_chain);
g_test_add_func(TEST_PREFIX "custom_iface", test_custom_iface);
g_test_add_func(TEST_PREFIX "reply_status", test_reply_status);
g_test_add_func(TEST_PREFIX "increfs", test_increfs);
g_test_add_func(TEST_PREFIX "decrefs", test_decrefs);
g_test_add_func(TEST_PREFIX "acquire", test_acquire);
g_test_add_func(TEST_PREFIX "release", test_release);
test_init(&test_opt, argc, argv);
test_config_init(&test_config, TMP_DIR_TEMPLATE);
result = g_test_run();
test_config_cleanup(&test_config);
return result;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/