1395 lines
41 KiB
C
1395 lines
41 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_ipc.h"
|
|
#include "gbinder_driver.h"
|
|
#include "gbinder_local_object_p.h"
|
|
#include "gbinder_local_reply_p.h"
|
|
#include "gbinder_local_request_p.h"
|
|
#include "gbinder_object_registry.h"
|
|
#include "gbinder_output_data.h"
|
|
#include "gbinder_remote_reply.h"
|
|
#include "gbinder_remote_request.h"
|
|
#include "gbinder_rpc_protocol.h"
|
|
#include "gbinder_writer.h"
|
|
|
|
#include <gutil_log.h>
|
|
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
|
|
static TestOpt test_opt;
|
|
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-ipc-XXXXXX";
|
|
|
|
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);
|
|
}
|
|
|
|
static
|
|
GBinderLocalRequest*
|
|
test_local_request_new(
|
|
GBinderIpc* ipc)
|
|
{
|
|
return gbinder_local_request_new(gbinder_driver_io(ipc->driver),
|
|
gbinder_driver_protocol(ipc->driver), NULL);
|
|
}
|
|
|
|
static
|
|
GBinderLocalReply*
|
|
test_local_reply_new(
|
|
GBinderIpc* ipc)
|
|
{
|
|
return gbinder_local_reply_new(gbinder_driver_io(ipc->driver),
|
|
gbinder_driver_protocol(ipc->driver));
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* null
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_null(
|
|
void)
|
|
{
|
|
int status = INT_MAX;
|
|
|
|
g_assert(!gbinder_ipc_ref(NULL));
|
|
gbinder_ipc_unref(NULL);
|
|
g_assert(!gbinder_ipc_sync_main.sync_reply(NULL, 0, 0, NULL, NULL));
|
|
g_assert(!gbinder_ipc_sync_main.sync_reply(NULL, 0, 0, NULL, &status));
|
|
g_assert_cmpint(status, == ,-EINVAL);
|
|
g_assert(!gbinder_ipc_sync_worker.sync_reply(NULL, 0, 0, NULL, NULL));
|
|
g_assert(!gbinder_ipc_sync_worker.sync_reply(NULL, 0, 0, NULL, &status));
|
|
g_assert_cmpint(status, == ,-EINVAL);
|
|
g_assert_cmpint(gbinder_ipc_sync_main.sync_oneway(NULL, 0, 0, NULL), == ,
|
|
-EINVAL);
|
|
g_assert_cmpint(gbinder_ipc_sync_worker.sync_oneway(NULL, 0, 0, NULL), == ,
|
|
-EINVAL);
|
|
g_assert(!gbinder_ipc_transact(NULL, 0, 0, 0, NULL, NULL, NULL, NULL));
|
|
g_assert(!gbinder_ipc_transact_custom(NULL, NULL, NULL, NULL, NULL));
|
|
g_assert(!gbinder_ipc_object_registry(NULL));
|
|
gbinder_ipc_looper_check(NULL);
|
|
gbinder_ipc_cancel(NULL, 0);
|
|
|
|
g_assert(!gbinder_object_registry_ref(NULL));
|
|
gbinder_object_registry_unref(NULL);
|
|
g_assert(!gbinder_object_registry_get_local(NULL, NULL));
|
|
g_assert(!gbinder_object_registry_get_remote(NULL, 0, FALSE));
|
|
g_assert(!gbinder_ipc_find_local_object(NULL, NULL, NULL));
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* basic
|
|
*==========================================================================*/
|
|
|
|
static
|
|
gboolean
|
|
test_basic_find_none(
|
|
GBinderLocalObject* obj,
|
|
void* user_data)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static
|
|
gboolean
|
|
test_basic_find(
|
|
GBinderLocalObject* obj,
|
|
void* user_data)
|
|
{
|
|
return obj == user_data;
|
|
}
|
|
|
|
static
|
|
void
|
|
test_basic(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
|
|
GBinderLocalObject* obj;
|
|
|
|
g_assert(ipc);
|
|
g_assert(ipc2);
|
|
g_assert(ipc != ipc2);
|
|
gbinder_ipc_cancel(ipc2, 0); /* not a valid transaction */
|
|
gbinder_ipc_unref(ipc2);
|
|
|
|
g_assert(!gbinder_ipc_find_local_object(NULL, test_basic_find_none, NULL));
|
|
g_assert(!gbinder_ipc_find_local_object(ipc, test_basic_find_none, NULL));
|
|
obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
|
|
g_assert(obj);
|
|
g_assert(!gbinder_ipc_find_local_object(ipc, test_basic_find_none, NULL));
|
|
g_assert(gbinder_ipc_find_local_object(ipc, test_basic_find, obj) == obj);
|
|
gbinder_local_object_unref(obj); /* Above call added a reference */
|
|
gbinder_local_object_unref(obj);
|
|
|
|
/* Second gbinder_ipc_new returns the same (default) object */
|
|
g_assert(gbinder_ipc_new(NULL, NULL) == ipc);
|
|
g_assert(gbinder_ipc_new("", NULL) == ipc);
|
|
gbinder_ipc_unref(ipc);
|
|
gbinder_ipc_unref(ipc);
|
|
gbinder_ipc_unref(ipc);
|
|
|
|
/* Invalid path */
|
|
g_assert(!gbinder_ipc_new("invalid path", NULL));
|
|
|
|
test_binder_exit_wait(&test_opt, NULL);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* protocol
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_protocol(
|
|
void)
|
|
{
|
|
/* GBinderIpc objects are identified by device + protocol combination */
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, "aidl");
|
|
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, "hidl");
|
|
|
|
g_assert(ipc);
|
|
g_assert(ipc2);
|
|
g_assert(ipc != ipc2);
|
|
gbinder_ipc_unref(ipc);
|
|
gbinder_ipc_unref(ipc2);
|
|
|
|
test_binder_exit_wait(&test_opt, NULL);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* async_oneway
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_async_oneway_done(
|
|
GBinderIpc* ipc,
|
|
GBinderRemoteReply* reply,
|
|
int status,
|
|
void* user_data)
|
|
{
|
|
g_assert(!status);
|
|
g_assert(!reply);
|
|
test_quit_later((GMainLoop*)user_data);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_async_oneway(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
const int fd = gbinder_driver_fd(ipc->driver);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
gulong id;
|
|
|
|
test_binder_br_transaction_complete(fd, TX_THREAD);
|
|
id = gbinder_ipc_transact(ipc, 0, 1, GBINDER_TX_FLAG_ONEWAY,
|
|
req, test_async_oneway_done, NULL, loop);
|
|
g_assert(id);
|
|
test_run(&test_opt, loop);
|
|
|
|
gbinder_local_request_unref(req);
|
|
gbinder_ipc_unref(ipc);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* sync_oneway
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_sync_oneway(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
const int fd = gbinder_driver_fd(ipc->driver);
|
|
|
|
test_binder_br_transaction_complete(fd, THIS_THREAD);
|
|
g_assert_cmpint(gbinder_ipc_sync_main.sync_oneway(ipc, 0, 1, req), == ,0);
|
|
gbinder_local_request_unref(req);
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, NULL);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* sync_reply_ok
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_sync_reply_ok_status(
|
|
int* status)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
GBinderLocalReply* reply = test_local_reply_new(ipc);
|
|
GBinderRemoteReply* tx_reply;
|
|
GBinderOutputData* data;
|
|
const int fd = gbinder_driver_fd(ipc->driver);
|
|
const guint32 handle = 0;
|
|
const guint32 code = 1;
|
|
const char* result_in = "foo";
|
|
char* result_out;
|
|
|
|
g_assert(gbinder_local_reply_append_string16(reply, result_in));
|
|
data = gbinder_local_reply_data(reply);
|
|
g_assert(data);
|
|
|
|
test_binder_br_noop(fd, THIS_THREAD);
|
|
test_binder_br_transaction_complete(fd, THIS_THREAD);
|
|
test_binder_br_noop(fd, THIS_THREAD);
|
|
test_binder_br_reply(fd, THIS_THREAD, handle, code, data->bytes);
|
|
|
|
tx_reply = gbinder_ipc_sync_main.sync_reply(ipc, handle, code, req, status);
|
|
g_assert(tx_reply);
|
|
|
|
result_out = gbinder_remote_reply_read_string16(tx_reply);
|
|
g_assert(!g_strcmp0(result_out, result_in));
|
|
g_free(result_out);
|
|
|
|
gbinder_remote_reply_unref(tx_reply);
|
|
gbinder_local_request_unref(req);
|
|
gbinder_local_reply_unref(reply);
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, NULL);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_sync_reply_ok(
|
|
void)
|
|
{
|
|
int status = -1;
|
|
|
|
test_sync_reply_ok_status(NULL);
|
|
test_sync_reply_ok_status(&status);
|
|
g_assert(status == GBINDER_STATUS_OK);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* sync_reply_error
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_sync_reply_error(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
const int fd = gbinder_driver_fd(ipc->driver);
|
|
const guint32 handle = 0;
|
|
const guint32 code = 1;
|
|
const gint expected_status = (-EINVAL);
|
|
const gint unexpected_status = GBINDER_STATUS_FAILED;
|
|
int status = INT_MAX;
|
|
|
|
test_binder_ignore_dead_object(fd);
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_transaction_complete(fd, TX_THREAD);
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_reply_status(fd, TX_THREAD, expected_status);
|
|
|
|
g_assert(!gbinder_ipc_sync_main.sync_reply(ipc,handle,code,req,&status));
|
|
g_assert_cmpint(status, == ,expected_status);
|
|
|
|
/* GBINDER_STATUS_FAILED gets replaced with -EFAULT */
|
|
test_binder_ignore_dead_object(fd);
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_transaction_complete(fd, TX_THREAD);
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_reply_status(fd, TX_THREAD, unexpected_status);
|
|
|
|
g_assert(!gbinder_ipc_sync_main.sync_reply(ipc,handle,code,req,&status));
|
|
g_assert_cmpint(status, == ,-EFAULT);
|
|
|
|
gbinder_local_request_unref(req);
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, NULL);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_ok
|
|
*==========================================================================*/
|
|
|
|
#define TEST_REQ_PARAM_STR "foo"
|
|
|
|
static
|
|
void
|
|
test_transact_ok_destroy(
|
|
void* user_data)
|
|
{
|
|
test_quit_later((GMainLoop*)user_data);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_ok_done(
|
|
GBinderIpc* ipc,
|
|
GBinderRemoteReply* reply,
|
|
int status,
|
|
void* user_data)
|
|
{
|
|
char* result;
|
|
|
|
GVERBOSE_("");
|
|
result = gbinder_remote_reply_read_string16(reply);
|
|
g_assert(!g_strcmp0(result, TEST_REQ_PARAM_STR));
|
|
g_free(result);
|
|
g_assert(status == GBINDER_STATUS_OK);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_ok(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
GBinderLocalReply* reply = test_local_reply_new(ipc);
|
|
GBinderOutputData* data;
|
|
const guint32 handle = 0;
|
|
const guint32 code = 1;
|
|
const int fd = gbinder_driver_fd(ipc->driver);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
gulong id;
|
|
|
|
g_assert(gbinder_local_reply_append_string16(reply, TEST_REQ_PARAM_STR));
|
|
data = gbinder_local_reply_data(reply);
|
|
g_assert(data);
|
|
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_transaction_complete(fd, TX_THREAD);
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_reply(fd, TX_THREAD, handle, code, data->bytes);
|
|
|
|
id = gbinder_ipc_transact(ipc, handle, code, 0, req,
|
|
test_transact_ok_done, test_transact_ok_destroy, loop);
|
|
g_assert(id);
|
|
|
|
test_run(&test_opt, loop);
|
|
|
|
/* Transaction id is not valid anymore: */
|
|
gbinder_ipc_cancel(ipc, id);
|
|
gbinder_local_request_unref(req);
|
|
gbinder_local_reply_unref(reply);
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_dead
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_transact_dead_done(
|
|
GBinderIpc* ipc,
|
|
GBinderRemoteReply* reply,
|
|
int status,
|
|
void* user_data)
|
|
{
|
|
GVERBOSE_("%d", status);
|
|
g_assert(!reply);
|
|
g_assert(status == GBINDER_STATUS_DEAD_OBJECT);
|
|
test_quit_later((GMainLoop*)user_data);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_dead(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
const int fd = gbinder_driver_fd(ipc->driver);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
gulong id;
|
|
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_dead_reply(fd, TX_THREAD);
|
|
|
|
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_dead_done,
|
|
NULL, loop);
|
|
g_assert(id);
|
|
|
|
test_run(&test_opt, loop);
|
|
|
|
/* Transaction id is not valid anymore: */
|
|
gbinder_ipc_cancel(ipc, id);
|
|
gbinder_local_request_unref(req);
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_failed
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_transact_failed_done(
|
|
GBinderIpc* ipc,
|
|
GBinderRemoteReply* reply,
|
|
int status,
|
|
void* user_data)
|
|
{
|
|
GVERBOSE_("%d", status);
|
|
g_assert(!reply);
|
|
g_assert(status == GBINDER_STATUS_FAILED);
|
|
test_quit_later((GMainLoop*)user_data);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_failed(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
const int fd = gbinder_driver_fd(ipc->driver);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
gulong id;
|
|
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_failed_reply(fd, TX_THREAD);
|
|
|
|
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_failed_done,
|
|
NULL, loop);
|
|
g_assert(id);
|
|
|
|
test_run(&test_opt, loop);
|
|
|
|
/* Transaction id is not valid anymore: */
|
|
gbinder_ipc_cancel(ipc, id);
|
|
gbinder_local_request_unref(req);
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_status
|
|
*==========================================================================*/
|
|
|
|
#define EXPECTED_STATUS (0x42424242)
|
|
|
|
static
|
|
void
|
|
test_transact_status_done(
|
|
GBinderIpc* ipc,
|
|
GBinderRemoteReply* reply,
|
|
int status,
|
|
void* user_data)
|
|
{
|
|
GVERBOSE_("%d", status);
|
|
g_assert(!reply);
|
|
g_assert(status == EXPECTED_STATUS);
|
|
test_quit_later((GMainLoop*)user_data);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_status(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
const int fd = gbinder_driver_fd(ipc->driver);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
gulong id;
|
|
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_reply_status(fd, TX_THREAD, EXPECTED_STATUS);
|
|
|
|
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_status_done,
|
|
NULL, loop);
|
|
g_assert(id);
|
|
|
|
test_run(&test_opt, loop);
|
|
|
|
/* Transaction id is not valid anymore: */
|
|
gbinder_ipc_cancel(ipc, id);
|
|
gbinder_local_request_unref(req);
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_custom
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_transact_custom_done(
|
|
const GBinderIpcTx* tx)
|
|
{
|
|
GVERBOSE_("");
|
|
test_quit_later((GMainLoop*)tx->user_data);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_custom(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
gulong id = gbinder_ipc_transact_custom(ipc, NULL,
|
|
test_transact_custom_done, NULL, loop);
|
|
|
|
g_assert(id);
|
|
test_run(&test_opt, loop);
|
|
|
|
gbinder_ipc_exit();
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_custom2
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_transact_custom_destroy(
|
|
void* user_data)
|
|
{
|
|
GVERBOSE_("");
|
|
test_quit_later((GMainLoop*)user_data);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_custom2(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
gulong id = gbinder_ipc_transact_custom(ipc, NULL, NULL,
|
|
test_transact_custom_destroy, loop);
|
|
|
|
g_assert(id);
|
|
test_run(&test_opt, loop);
|
|
|
|
gbinder_ipc_exit();
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_custom3
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_transact_custom3_exec(
|
|
const GBinderIpcTx* tx)
|
|
{
|
|
GVERBOSE_("");
|
|
gbinder_ipc_unref(tx->ipc);
|
|
test_quit_later((GMainLoop*)tx->user_data);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_custom3(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
/* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
|
|
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_custom3_exec,
|
|
NULL, NULL, loop);
|
|
|
|
g_assert(id);
|
|
test_run(&test_opt, loop);
|
|
|
|
/* Reference to GBinderIpc is released by test_transact_custom3_exec */
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_cancel
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_transact_cancel_destroy(
|
|
void* user_data)
|
|
{
|
|
GVERBOSE_("");
|
|
test_quit_later((GMainLoop*)user_data);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_cancel_exec(
|
|
const GBinderIpcTx* tx)
|
|
{
|
|
GVERBOSE_("");
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_cancel_done(
|
|
const GBinderIpcTx* tx)
|
|
{
|
|
GVERBOSE_("");
|
|
g_assert(tx->cancelled);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_cancel(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel_exec,
|
|
test_transact_cancel_done, test_transact_cancel_destroy, loop);
|
|
|
|
g_assert(id);
|
|
gbinder_ipc_cancel(ipc, id);
|
|
test_run(&test_opt, loop);
|
|
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_cancel2
|
|
*==========================================================================*/
|
|
|
|
static
|
|
gboolean
|
|
test_transact_cancel2_cancel(
|
|
gpointer data)
|
|
{
|
|
const GBinderIpcTx* tx = data;
|
|
|
|
GVERBOSE_("");
|
|
gbinder_ipc_cancel(tx->ipc, tx->id);
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_cancel2_exec(
|
|
const GBinderIpcTx* tx)
|
|
{
|
|
GVERBOSE_("");
|
|
g_assert(!tx->cancelled);
|
|
g_main_context_invoke(NULL, test_transact_cancel2_cancel, (void*)tx);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_cancel2(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
/* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
|
|
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel2_exec,
|
|
test_transact_cancel_done, test_transact_cancel_destroy, loop);
|
|
|
|
g_assert(id);
|
|
test_run(&test_opt, loop);
|
|
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_2way
|
|
*==========================================================================*/
|
|
|
|
static
|
|
GBinderLocalReply*
|
|
test_transact_2way_incoming_proc(
|
|
GBinderLocalObject* obj,
|
|
GBinderRemoteRequest* req,
|
|
guint code,
|
|
guint flags,
|
|
int* status,
|
|
void* user_data)
|
|
{
|
|
int* incoming_call = user_data;
|
|
|
|
GVERBOSE_("\"%s\" %u", gbinder_remote_request_interface(req), code);
|
|
g_assert_cmpuint(flags, == ,0);
|
|
g_assert_cmpint(gbinder_remote_request_sender_pid(req), == ,getpid());
|
|
g_assert_cmpint(gbinder_remote_request_sender_euid(req), == ,geteuid());
|
|
g_assert_cmpstr(gbinder_remote_request_interface(req), == ,"test");
|
|
g_assert_cmpstr(gbinder_remote_request_read_string8(req), == ,"message");
|
|
g_assert_cmpuint(code, == ,2);
|
|
g_assert_cmpint(*incoming_call, == ,0);
|
|
(*incoming_call)++;
|
|
|
|
*status = GBINDER_STATUS_OK;
|
|
return gbinder_local_object_new_reply(obj);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_2way_run(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
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);
|
|
const char* const ifaces[] = { "test", NULL };
|
|
const guint32 handle = 0;
|
|
const guint32 code = 1;
|
|
int incoming_call = 0;
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
GBinderLocalObject* obj = gbinder_local_object_new
|
|
(ipc, ifaces, test_transact_2way_incoming_proc, &incoming_call);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
GBinderLocalRequest* incoming_req = test_local_request_new(ipc);
|
|
GBinderLocalReply* reply = test_local_reply_new(ipc);
|
|
GBinderWriter writer;
|
|
|
|
/* Prepare reply */
|
|
g_assert(gbinder_local_reply_append_string16(reply, TEST_REQ_PARAM_STR));
|
|
|
|
/* Prepare incoming request */
|
|
gbinder_local_request_init_writer(req, &writer);
|
|
prot->write_rpc_header(&writer, "test");
|
|
gbinder_writer_append_string8(&writer, "message");
|
|
|
|
test_binder_ignore_dead_object(fd);
|
|
test_binder_br_transaction(fd, TX_THREAD, obj, 2,
|
|
gbinder_local_request_data(req)->bytes);
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_transaction_complete(fd, TX_THREAD);
|
|
test_binder_br_noop(fd, TX_THREAD);
|
|
test_binder_br_reply(fd, TX_THREAD, handle, code,
|
|
gbinder_local_reply_data(reply)->bytes);
|
|
|
|
/* NB. Reusing test_transact_ok_done and test_transact_ok_destroy */
|
|
g_assert(gbinder_ipc_transact(ipc, handle, code, 0, req,
|
|
test_transact_ok_done, test_transact_ok_destroy, loop));
|
|
|
|
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);
|
|
gbinder_local_request_unref(incoming_req);
|
|
gbinder_local_reply_unref(reply);
|
|
g_idle_add(test_unref_ipc, ipc);
|
|
test_run(&test_opt, loop);
|
|
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_2way(
|
|
void)
|
|
{
|
|
test_run_in_context(&test_opt, test_transact_2way_run);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_unhandled
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_transact_unhandled_done(
|
|
GBinderIpc* ipc,
|
|
GBinderRemoteReply* reply,
|
|
int status,
|
|
void* user_data)
|
|
{
|
|
g_assert(!reply);
|
|
g_assert_cmpint(status, == ,GBINDER_STATUS_DEAD_OBJECT);
|
|
test_quit_later((GMainLoop*)user_data);
|
|
}
|
|
|
|
|
|
static
|
|
void
|
|
test_transact_unhandled_run(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderDriver* driver = ipc->driver;
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
GBinderLocalRequest* req = gbinder_driver_local_request_new_ping(driver);
|
|
|
|
g_assert(gbinder_ipc_transact(ipc, 1 /* Non-existent object */,
|
|
gbinder_driver_protocol(driver)->ping_tx, 0, req,
|
|
test_transact_unhandled_done, NULL, loop));
|
|
gbinder_local_request_unref(req);
|
|
test_run(&test_opt, loop);
|
|
|
|
gbinder_ipc_unref(ipc);
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_unhandled(
|
|
void)
|
|
{
|
|
test_run_in_context(&test_opt, test_transact_unhandled_run);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_incoming
|
|
*==========================================================================*/
|
|
|
|
static
|
|
GBinderLocalReply*
|
|
test_transact_incoming_proc(
|
|
GBinderLocalObject* obj,
|
|
GBinderRemoteRequest* req,
|
|
guint code,
|
|
guint flags,
|
|
int* status,
|
|
void* user_data)
|
|
{
|
|
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_quit_later((GMainLoop*)user_data);
|
|
|
|
*status = GBINDER_STATUS_OK;
|
|
return gbinder_local_object_new_reply(obj);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_incoming_run(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
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);
|
|
const char* const ifaces[] = { "test", NULL };
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
GBinderLocalObject* obj = gbinder_local_object_new
|
|
(ipc, ifaces, test_transact_incoming_proc, loop);
|
|
GBinderLocalRequest* ping = test_local_request_new(ipc);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
GBinderWriter writer;
|
|
|
|
gbinder_local_request_init_writer(ping, &writer);
|
|
prot->write_ping(&writer);
|
|
|
|
gbinder_local_request_init_writer(req, &writer);
|
|
prot->write_rpc_header(&writer, "test");
|
|
gbinder_writer_append_string8(&writer, "message");
|
|
|
|
test_binder_br_transaction(fd, LOOPER_THREAD, obj, prot->ping_tx,
|
|
gbinder_local_request_data(ping)->bytes);
|
|
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
|
|
test_binder_br_transaction(fd, LOOPER_THREAD, obj, 1,
|
|
gbinder_local_request_data(req)->bytes);
|
|
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
|
|
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(ping);
|
|
gbinder_local_request_unref(req);
|
|
g_idle_add(test_unref_ipc, ipc);
|
|
test_run(&test_opt, loop);
|
|
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_incoming(
|
|
void)
|
|
{
|
|
test_run_in_context(&test_opt, test_transact_incoming_run);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_status_reply
|
|
*==========================================================================*/
|
|
|
|
static
|
|
GBinderLocalReply*
|
|
test_transact_status_reply_proc(
|
|
GBinderLocalObject* obj,
|
|
GBinderRemoteRequest* req,
|
|
guint code,
|
|
guint flags,
|
|
int* status,
|
|
void* user_data)
|
|
{
|
|
GVERBOSE_("\"%s\" %u", gbinder_remote_request_interface(req), code);
|
|
g_assert(!flags);
|
|
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_quit_later((GMainLoop*)user_data);
|
|
|
|
*status = EXPECTED_STATUS;
|
|
return NULL;
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_status_reply_run(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
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);
|
|
const char* const ifaces[] = { "test", NULL };
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
GBinderLocalObject* obj = gbinder_local_object_new
|
|
(ipc, ifaces, test_transact_status_reply_proc, loop);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
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, LOOPER_THREAD, obj, 1, data->bytes);
|
|
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
|
|
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);
|
|
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_status_reply(
|
|
void)
|
|
{
|
|
test_run_in_context(&test_opt, test_transact_status_reply_run);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_async
|
|
*==========================================================================*/
|
|
|
|
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_run(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
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);
|
|
const char* const ifaces[] = { "test", NULL };
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
GBinderLocalObject* obj = gbinder_local_object_new
|
|
(ipc, ifaces, test_transact_async_proc, loop);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
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, LOOPER_THREAD, obj, 1, data->bytes);
|
|
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
|
|
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);
|
|
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_async(
|
|
void)
|
|
{
|
|
test_run_in_context(&test_opt, test_transact_async_run);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* transact_async_sync
|
|
*==========================================================================*/
|
|
|
|
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_run(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
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);
|
|
const char* const ifaces[] = { "test", NULL };
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
GBinderLocalObject* obj = gbinder_local_object_new
|
|
(ipc, ifaces, test_transact_async_sync_proc, loop);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
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, LOOPER_THREAD, obj, 1, data->bytes);
|
|
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
|
|
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);
|
|
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_transact_async_sync(
|
|
void)
|
|
{
|
|
test_run_in_context(&test_opt, test_transact_async_sync_run);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* drop_remote_refs
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_drop_remote_refs_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_drop_remote_refs_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_drop_remote_refs_cb, loop);
|
|
|
|
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_exit will drop the remote reference */
|
|
gbinder_ipc_unref(ipc);
|
|
gbinder_ipc_exit();
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
static
|
|
void
|
|
test_drop_remote_refs(
|
|
void)
|
|
{
|
|
test_run_in_context(&test_opt, test_drop_remote_refs_run);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* cancel_on_exit
|
|
*==========================================================================*/
|
|
|
|
static
|
|
void
|
|
test_cancel_on_exit_not_reached(
|
|
GBinderIpc* ipc,
|
|
GBinderRemoteReply* reply,
|
|
int status,
|
|
void* user_data)
|
|
{
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
static
|
|
void
|
|
test_cancel_on_exit(
|
|
void)
|
|
{
|
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
|
GBinderLocalRequest* req = test_local_request_new(ipc);
|
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
|
int fd = gbinder_driver_fd(ipc->driver);
|
|
|
|
/* This transaction will be cancelled by gbinder_ipc_exit */
|
|
test_binder_br_transaction_complete(fd, TX_THREAD);
|
|
gbinder_ipc_transact(ipc, 0, 1, GBINDER_TX_FLAG_ONEWAY,
|
|
req, test_cancel_on_exit_not_reached, NULL, NULL);
|
|
|
|
gbinder_local_request_unref(req);
|
|
gbinder_ipc_unref(ipc);
|
|
gbinder_ipc_exit();
|
|
test_binder_exit_wait(&test_opt, loop);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*==========================================================================*
|
|
* Common
|
|
*==========================================================================*/
|
|
|
|
#define TEST_PREFIX "/ipc/"
|
|
#define TEST_(t) TEST_PREFIX t
|
|
|
|
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_("null"), test_null);
|
|
g_test_add_func(TEST_("basic"), test_basic);
|
|
g_test_add_func(TEST_("protocol"), test_protocol);
|
|
g_test_add_func(TEST_("async_oneway"), test_async_oneway);
|
|
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_custom3"), test_transact_custom3);
|
|
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_2way"), test_transact_2way);
|
|
g_test_add_func(TEST_("transact_incoming"), test_transact_incoming);
|
|
g_test_add_func(TEST_("transact_unhandled"), test_transact_unhandled);
|
|
g_test_add_func(TEST_("transact_status_reply"), test_transact_status_reply);
|
|
g_test_add_func(TEST_("transact_async"), test_transact_async);
|
|
g_test_add_func(TEST_("transact_async_sync"), test_transact_async_sync);
|
|
g_test_add_func(TEST_("drop_remote_refs"), test_drop_remote_refs);
|
|
g_test_add_func(TEST_("cancel_on_exit"), test_cancel_on_exit);
|
|
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:
|
|
*/
|