Compare commits

...

17 Commits

Author SHA1 Message Date
Slava Monich
eaab366dcb Version 1.1.1 2020-12-22 15:19:03 +02:00
Slava Monich
784f06c415 Merge pull request #57 from monich/sm-test
A few minor tweaks and another unit test
2020-12-22 15:13:09 +02:00
Slava Monich
4b07e80a8f [gbinder] Added couple more looper checks
We must have looper running in order to receive death notifications.
2020-12-19 01:42:42 +02:00
Slava Monich
9f7fac407d [unit] Added unit_servicemanager_aidl. JB#42956
And refactored binder simulator, it can now simulate a lot
more sophisticated scenarious.
2020-12-08 05:03:15 +02:00
Slava Monich
47b6668876 [gbinder] Added internal gbinder_ipc_set_max_threads(). JB#42956
It's needed by unit tests to make sure that asynchronous requests
get executed sequentially. Our binder simulation is too primitive
to handle truely overlapping requests.
2020-12-08 05:02:57 +02:00
Slava Monich
951977961b [gbinder] Pass 0x0f priority to service list request. JB#42956
Based on examination of servicemanager source code, it seems to be
a better idea because it's interpreted as a bitmask.
2020-12-07 18:56:04 +02:00
Slava Monich
f069c3a595 [gbinder] Corner cases for abandoned loopers. JB#42956
If the last GBinderIpc reference was dropped by the looper thread,
the exit flag wasn't set by gbinder_ipc_looper_stop() and such
looper thread kept hanging forever. Also, that flag wasn't checked
by gbinder_driver_read(), and even though it's even less likely
to cause any trouble in real life, let's fix that too.
2020-12-07 05:19:14 +02:00
Slava Monich
b84194e8c7 Version 1.1.0 2020-12-04 13:50:42 +02:00
Slava Monich
e06e989aa5 [gbinder] Updated README 2020-12-04 13:44:41 +02:00
Slava Monich
ab75505437 Merge pull request #56 from monich/config
Make protocol and service managers configurable per binder device
2020-12-04 13:33:10 +02:00
Slava Monich
e97663b58e [gbinder] Added support for API level presets. JB#51844
API level can be configured via libgbinder config file like this:

  [General]
  ApiLevel = 28

and that adds protocol and servicemanager values appropriate for
the specified Android API level.

Presets are currently defined for API levels 28 and 29.
2020-12-04 03:09:37 +02:00
Slava Monich
a92f57a30c [gbinder] Added "aidl2" variant of RPC protocol. JB#51844
It first appeared in Android 10 (API level 29)
2020-12-03 20:57:09 +02:00
Slava Monich
ebb9381e46 [gbinder] Added "aidl2" variant of service manager. JB#51844
It first appeared in Android 9 (API level 28)
2020-12-03 20:26:50 +02:00
Slava Monich
5fb441fb81 [gbinder] Support for multiple config files. JB#51844
In additions to loading /etc/gbinder.conf, directory /etc/gbinder.d is
searched for .conf files and those overwrite the configuration found
in /etc/gbinder.conf (or more likely, provide entries of their own)
2020-12-03 20:25:21 +02:00
Slava Monich
f3a00fe8a2 [gbinder] Made service managers configurable. JB#51844
Custom device-to-protocol mapping can be provided via /etc/gbinder.conf
and the default config looks like this:

  [ServiceManager]
  Default = aidl
  /dev/binder = aidl
  /dev/hwbinder = hidl

gbinder_defaultservicemanager_new() and gbinder_hwservicemanager_new()
have beed deprecated and should no longer be used. They will keep
returning the same original servicemanagers no matter what's specified
in the configuration files.

Those calls should be replaced with gbinder_servicemanager_new() which
picks the right servicemanager implementation for the specified device.
2020-12-03 20:22:06 +02:00
Slava Monich
573494570c [gbinder] Renamed service managers. JB#51844
It's become clear that more of those are coming, consistent naming
scheme is needed. For now it's just this:

  defaultservicemanager => servicemanager_aidl
  hwservicemanager => servicemanager_hidl
2020-12-03 20:15:47 +02:00
Slava Monich
92392f5c9a [gbinder] Made RPC protocol configurable per device. JB#51844
Custom device-to-protocol mapping can be provided via /etc/gbinder.conf
and the default config looks like this:

  [Protocol]
  Default = aidl
  /dev/binder = aidl
  /dev/hwbinder = hidl
2020-12-03 20:15:33 +02:00
42 changed files with 3414 additions and 548 deletions

View File

@@ -15,8 +15,8 @@
#
VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_RELEASE = 47
VERSION_MINOR = 1
VERSION_RELEASE = 1
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
@@ -78,6 +78,7 @@ SRC = \
gbinder_buffer.c \
gbinder_cleanup.c \
gbinder_client.c \
gbinder_config.c \
gbinder_driver.c \
gbinder_eventloop.c \
gbinder_io_32.c \
@@ -97,9 +98,10 @@ SRC = \
gbinder_writer.c
SRC += \
gbinder_defaultservicemanager.c \
gbinder_hwservicemanager.c \
gbinder_servicemanager.c
gbinder_servicemanager.c \
gbinder_servicemanager_aidl.c \
gbinder_servicemanager_aidl2.c \
gbinder_servicemanager_hidl.c
SRC += \
gbinder_system.c

39
README
View File

@@ -1,7 +1,44 @@
GLib-style interface to binder (Android IPC mechanism)
Provides:
Key features:
1. Integration with GLib event loop
2. Detection of 32 vs 64 bit kernel at runtime
3. Asynchronous transactions that don't block the event thread
4. Stable service manager and low-level transation APIs
Android keeps changing both low-level RPC and service manager
protocols from version to version. To counter that, libgbinder
implements configirable backends for different variants of those,
and yet keeping its own API unchanged.
Configuration is loaded from [Protocol] and [ServiceManager] sections
of /etc/gbinder.conf file. The keys are binder device names or the
special Default value, the value is the identifier of the protocol
or service manager variant, respectively.
In addition to reading /etc/gbinder.conf if it exists, /etc/gbinder.d
directory is scanned for .conf files, the file list is sorted, files are
loaded one by one, overwriting the entries loaded from /etc/gbinder.conf
or from the previously processed file.
Known protocol and service manager variants are aidl, aidl2 and hidl.
This list is expected to expand further in the future. The default
configuration is as follows:
[Protocol]
Default = aidl
/dev/binder = aidl
/dev/hwbinder = hidl
[ServiceManager]
Default = aidl
/dev/binder = aidl
/dev/hwbinder = hidl
Alternatively, one can specify the desired Android API level:
[General]
ApiLevel = 29
and let libgbinder pick the appropriate preset.

20
debian/changelog vendored
View File

@@ -1,3 +1,23 @@
libgbinder (1.1.1) unstable; urgency=low
* Handle corner cases for abandoned loopers
* Pass 0x0f priority to aidl2 service list request.
* Improved binder simulation for unit tests
* Added servicemanager_aidl unit test
-- Slava Monich <slava.monich@jolla.com> Tue, 22 Dec 2020 15:15:10 +0200
libgbinder (1.1.0) unstable; urgency=low
* Made RPC protocol configurable per binder device
* Made service managers configurable per binder device
* Added support for multiple config files
* Added "aidl2" variant of service manager
* Added "aidl2" variant of RPC protocol
* Added support for API level presets
-- Slava Monich <slava.monich@jolla.com> Fri, 04 Dec 2020 13:47:26 +0200
libgbinder (1.0.47) unstable; urgency=low
* Make library executable on RPM based systems

View File

@@ -80,11 +80,13 @@ gbinder_servicemanager_new(
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev);
const char* dev)
G_DEPRECATED_FOR(gbinder_servicemanager_new);
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev);
const char* dev)
G_DEPRECATED_FOR(gbinder_servicemanager_new);
GBinderLocalObject*
gbinder_servicemanager_new_local_object(

View File

@@ -1,5 +1,5 @@
Name: libgbinder
Version: 1.0.47
Version: 1.1.1
Release: 0
Summary: Binder client library
License: BSD

384
src/gbinder_config.c Normal file
View File

@@ -0,0 +1,384 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 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_config.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_log.h"
#include <gutil_strv.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/*
* The contents of the config file is queried from (at least) two places,
* and pretty much always this happens the same stack. Which means that
* we can avoid reading the same file twice if we delay dereferencing of
* GKeyFile until the next idle loop.
*/
static GKeyFile* gbinder_config_keyfile = NULL;
static GBinderEventLoopCallback* gbinder_config_autorelease = NULL;
static const char gbinder_config_suffix[] = ".conf";
static const char gbinder_config_default_file[] = "/etc/gbinder.conf";
static const char gbinder_config_default_dir[] = "/etc/gbinder.d";
const char* gbinder_config_file = gbinder_config_default_file;
const char* gbinder_config_dir = gbinder_config_default_dir;
/*
* Presets for particular API level can be chosen with ApiLevel
* setting, e.g.
*
* [General]
* ApiLevel=29
*
*/
static const char CONF_GENERAL[] = "General";
static const char CONG_API_LEVEL[] = "ApiLevel";
typedef struct gbinder_config_preset_entry {
const char* key;
const char* value;
} GBinderConfigPresetEntry;
typedef struct gbinder_config_preset_group {
const char* name;
const GBinderConfigPresetEntry* entries;
} GBinderConfigPresetGroup;
typedef struct gbinder_config_preset {
guint api_level;
const GBinderConfigPresetGroup* groups;
} GBinderConfigPreset;
/* API level 28 */
static const GBinderConfigPresetEntry gbinder_config_28_servicemanager[] = {
{ "/dev/binder", "aidl2" },
{ "/dev/vndbinder", "aidl2" },
{ NULL, NULL }
};
static const GBinderConfigPresetGroup gbinder_config_28[] = {
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_28_servicemanager },
{ NULL, NULL }
};
/* API level 29 */
static const GBinderConfigPresetEntry gbinder_config_29_protocol[] = {
{ "/dev/binder", "aidl2" },
{ "/dev/vndbinder", "aidl2" },
{ NULL, NULL }
};
#define gbinder_config_29_servicemanager gbinder_config_28_servicemanager
static const GBinderConfigPresetGroup gbinder_config_29[] = {
{ GBINDER_CONFIG_GROUP_PROTOCOL, gbinder_config_29_protocol },
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_29_servicemanager },
{ NULL, NULL }
};
/* Presets sorted by API level in descending order */
static const GBinderConfigPreset gbinder_config_presets[] = {
{ 29, gbinder_config_29 },
{ 28, gbinder_config_28 }
};
static
char**
gbinder_config_collect_files(
const char* path,
const char* suffix)
{
/*
* Returns sorted list of regular files in the directory,
* optionally having the specified suffix (e.g. ".conf").
* Returns NULL if nothing appropriate has been found.
*/
char** files = NULL;
if (path) {
GDir* dir = g_dir_open(path, 0, NULL);
if (dir) {
GPtrArray* list = g_ptr_array_new();
const gchar* name;
while ((name = g_dir_read_name(dir)) != NULL) {
if (g_str_has_suffix(name, suffix)) {
char* fullname = g_build_filename(path, name, NULL);
struct stat st;
if (!stat(fullname, &st) && S_ISREG(st.st_mode)) {
g_ptr_array_add(list, fullname);
} else {
g_free(fullname);
}
}
}
if (list->len > 0) {
g_ptr_array_add(list, NULL);
files = (char**) g_ptr_array_free(list, FALSE);
gutil_strv_sort(files, TRUE);
} else {
g_ptr_array_free(list, TRUE);
}
g_dir_close(dir);
}
}
return files;
}
static
GKeyFile*
gbinder_config_merge_keyfiles(
GKeyFile* dest,
GKeyFile* src)
{
gsize i, ngroups;
gchar** groups = g_key_file_get_groups(src, &ngroups);
for (i = 0; i < ngroups; i++) {
gsize k, nkeys;
const char* group = groups[i];
char** keys = g_key_file_get_keys(src, group, &nkeys, NULL);
for (k = 0; k < nkeys; k++) {
const char* key = keys[k];
char* value = g_key_file_get_value(src, group, key, NULL);
g_key_file_set_value(dest, group, key, value);
g_free(value);
}
g_strfreev(keys);
}
g_strfreev(groups);
return dest;
}
static
void
gbinder_config_apply_presets(
GKeyFile* config,
const GBinderConfigPreset* preset)
{
const GBinderConfigPresetGroup* g;
GDEBUG("Applying presets for API level %d", preset->api_level);
for (g = preset->groups; g->name; g++) {
const GBinderConfigPresetEntry* e;
for (e = g->entries; e->key; e++) {
if (!g_key_file_has_key(config, g->name, e->key, NULL)) {
g_key_file_set_value(config, g->name, e->key, e->value);
}
}
}
}
static
GKeyFile*
gbinder_config_load_files()
{
GError* error = NULL;
GKeyFile* out = NULL;
char** files = gbinder_config_collect_files(gbinder_config_dir,
gbinder_config_suffix);
if (gbinder_config_file &&
g_file_test(gbinder_config_file, G_FILE_TEST_EXISTS)) {
out = g_key_file_new();
if (g_key_file_load_from_file(out, gbinder_config_file,
G_KEY_FILE_NONE, &error)) {
GDEBUG("Loaded %s", gbinder_config_file);
} else {
GERR("Error loading %s: %s", gbinder_config_file, error->message);
g_error_free(error);
error = NULL;
gbinder_config_file = NULL; /* Don't retry */
g_key_file_unref(out);
out = NULL;
}
}
/* Files in the config directory overwrite /etc/gbinder.conf */
if (files) {
char** ptr;
GKeyFile* override = NULL;
for (ptr = files; *ptr; ptr++) {
const char* file = *ptr;
if (!override) {
override = g_key_file_new();
}
if (g_key_file_load_from_file(override, file,
G_KEY_FILE_NONE, &error)) {
GDEBUG("Loaded %s", file);
if (!out) {
out = override;
override = NULL;
} else {
out = gbinder_config_merge_keyfiles(out, override);
}
} else {
GERR("Error loading %s: %s", file, error->message);
g_error_free(error);
error = NULL;
}
}
g_strfreev(files);
if (override) {
g_key_file_unref(override);
}
}
if (out) {
/* Apply presets */
const int api_level = g_key_file_get_integer(out,
CONF_GENERAL, CONG_API_LEVEL, NULL);
if (api_level > 0) {
int i;
GDEBUG("API level %d", api_level);
for (i = 0; i < G_N_ELEMENTS(gbinder_config_presets); i++) {
const GBinderConfigPreset* preset = gbinder_config_presets + i;
if (api_level >= preset->api_level) {
gbinder_config_apply_presets(out, preset);
break;
}
}
}
}
return out;
}
static
void
gbinder_config_autorelease_cb(
gpointer data)
{
GASSERT(gbinder_config_keyfile == data);
gbinder_config_keyfile = NULL;
g_key_file_unref(data);
}
GKeyFile* /* autoreleased */
gbinder_config_get()
{
if (!gbinder_config_keyfile &&
(gbinder_config_file || gbinder_config_dir)) {
gbinder_config_keyfile = gbinder_config_load_files();
if (gbinder_config_keyfile) {
/* See the comment at the top of the file why this is needed */
gbinder_config_autorelease = gbinder_idle_callback_schedule_new
(gbinder_config_autorelease_cb, gbinder_config_keyfile, NULL);
}
}
return gbinder_config_keyfile;
}
/* Helper for loading config group in device = ident format */
GHashTable*
gbinder_config_load(
const char* group,
GBinderConfigValueMapFunc mapper)
{
GKeyFile* k = gbinder_config_get();
GHashTable* map = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
if (k) {
gsize n;
char** devs = g_key_file_get_keys(k, group, &n, NULL);
if (devs) {
gsize i;
for (i = 0; i < n; i++) {
char* dev = devs[i];
char* sval = g_key_file_get_value(k, group, dev, NULL);
gconstpointer val = mapper(sval);
if (val) {
g_hash_table_replace(map, dev, (gpointer) val);
} else {
GWARN("Unknown gbinder config '%s' for %s in group [%s]",
sval, dev, group);
g_free(dev);
}
g_free(sval);
}
/* Shallow delete (contents got stolen or freed) */
g_free(devs);
}
}
return map;
}
void
gbinder_config_exit()
{
if (gbinder_config_autorelease) {
gbinder_idle_callback_destroy(gbinder_config_autorelease);
gbinder_config_autorelease = NULL;
}
if (gbinder_config_keyfile) {
g_key_file_unref(gbinder_config_keyfile);
gbinder_config_keyfile = NULL;
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

78
src/gbinder_config.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_CONFIG_H
#define GBINDER_CONFIG_H
#include "gbinder_types_p.h"
typedef
gconstpointer
(*GBinderConfigValueMapFunc)(
const char* value);
GHashTable*
gbinder_config_load(
const char* group,
GBinderConfigValueMapFunc map)
GBINDER_INTERNAL;
GKeyFile* /* autoreleased */
gbinder_config_get(
void)
GBINDER_INTERNAL;
/* This one declared strictly for unit tests */
void
gbinder_config_exit(
void)
GBINDER_INTERNAL
GBINDER_DESTRUCTOR;
/* And these too */
extern const char* gbinder_config_file GBINDER_INTERNAL;
extern const char* gbinder_config_dir GBINDER_INTERNAL;
/* Configuration groups and special value */
#define GBINDER_CONFIG_GROUP_PROTOCOL "Protocol"
#define GBINDER_CONFIG_GROUP_SERVICEMANAGER "ServiceManager"
#define GBINDER_CONFIG_VALUE_DEFAULT "Default"
#endif /* GBINDER_CONFIG_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -953,7 +953,7 @@ gbinder_driver_read(
if (ret >= 0) {
/* Loop until we have handled all the incoming commands */
gbinder_driver_handle_commands(self, reg, handler, &rb);
while (rb.buf.consumed) {
while (rb.buf.consumed && gbinder_handler_can_loop(handler)) {
ret = gbinder_driver_write_read(self, NULL, &rb.buf);
if (ret >= 0) {
gbinder_driver_handle_commands(self, reg, handler, &rb);

View File

@@ -36,6 +36,7 @@
#include "gbinder_types_p.h"
typedef struct gbinder_handler_functions {
gboolean (*can_loop)(GBinderHandler* handler);
GBinderLocalReply* (*transact)(GBinderHandler* handler,
GBinderLocalObject* obj, GBinderRemoteRequest* req, guint code,
guint flags, int* status);
@@ -47,6 +48,14 @@ struct gbinder_handler {
/* Inline wrappers */
GBINDER_INLINE_FUNC
gboolean
gbinder_handler_can_loop(
GBinderHandler* self)
{
return self && self->f->can_loop && self->f->can_loop(self);
}
GBINDER_INLINE_FUNC
GBinderLocalReply*
gbinder_handler_transact(

View File

@@ -36,6 +36,7 @@
#include "gbinder_driver.h"
#include "gbinder_handler.h"
#include "gbinder_io.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_object_registry.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply.h"
@@ -605,6 +606,16 @@ gbinder_ipc_looper_count_primary(
return n;
}
static
gboolean
gbinder_ipc_looper_can_loop(
GBinderHandler* handler)
{
GBinderIpcLooper* looper = G_CAST(handler,GBinderIpcLooper,handler);
return !g_atomic_int_get(&looper->exit);
}
static
GBinderLocalReply*
gbinder_ipc_looper_transact(
@@ -823,6 +834,7 @@ gbinder_ipc_looper_new(
/* Note: this call can actually fail */
if (!pipe(fd)) {
static const GBinderHandlerFunctions handler_functions = {
.can_loop = gbinder_ipc_looper_can_loop,
.transact = gbinder_ipc_looper_transact
};
GError* error = NULL;
@@ -895,13 +907,15 @@ gbinder_ipc_looper_stop(
GBinderIpcLooper* looper)
{
/* Caller checks looper for NULL */
if (looper->thread && looper->thread != g_thread_self()) {
guint8 done = TX_DONE;
if (looper->thread) {
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;
if (looper->thread != g_thread_self()) {
guint8 done = TX_DONE;
if (write(looper->pipefd[1], &done, sizeof(done)) <= 0) {
looper->thread = NULL;
}
}
}
}
@@ -1420,7 +1434,8 @@ gbinder_ipc_tx_internal_exec(
GBinderIpcTxPriv* priv)
{
static const GBinderHandlerFunctions handler_fn = {
gbinder_ipc_tx_handler_transact
.can_loop = NULL,
.transact = gbinder_ipc_tx_handler_transact
};
GBinderIpcTxInternal* tx = gbinder_ipc_tx_internal_cast(priv);
GBinderIpcTx* pub = &priv->pub;
@@ -1570,12 +1585,14 @@ gbinder_ipc_tx_proc(
GBinderIpc*
gbinder_ipc_new(
const char* dev,
const GBinderRpcProtocol* protocol)
const char* dev)
{
GBinderIpc* self = NULL;
const GBinderRpcProtocol* protocol;
if (!dev || !dev[0]) dev = GBINDER_DEFAULT_BINDER;
protocol = gbinder_rpc_protocol_for_device(dev); /* Never returns NULL */
/* Lock */
pthread_mutex_lock(&gbinder_ipc_mutex);
if (gbinder_ipc_table) {
@@ -1746,6 +1763,14 @@ gbinder_ipc_cancel(
}
}
gboolean
gbinder_ipc_set_max_threads(
GBinderIpc* self,
gint max)
{
return g_thread_pool_set_max_threads(self->priv->tx_pool, max, NULL);
}
/*==========================================================================*
* Internals
*==========================================================================*/

View File

@@ -69,8 +69,7 @@ void
GBinderIpc*
gbinder_ipc_new(
const char* dev,
const GBinderRpcProtocol* protocol)
const char* dev)
GBINDER_INTERNAL;
GBinderIpc*
@@ -170,12 +169,19 @@ gbinder_ipc_remote_object_disposed(
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
/* Needed by unit tests */
gboolean
gbinder_ipc_set_max_threads(
GBinderIpc* self,
gint max_threads)
GBINDER_INTERNAL;
/* Declared for unit tests */
__attribute__((destructor))
void
gbinder_ipc_exit(
void)
GBINDER_INTERNAL;
GBINDER_INTERNAL
GBINDER_DESTRUCTOR;
#endif /* GBINDER_IPC_H */

View File

@@ -115,6 +115,7 @@ gbinder_remote_object_reanimate(
if (gbinder_driver_ping(ipc->driver, reg, self->handle) == 0) {
/* Wow, it's alive! */
self->dead = FALSE;
gbinder_ipc_looper_check(self->ipc); /* For death notifications */
gbinder_driver_acquire(ipc->driver, self->handle);
gbinder_driver_request_death_notification(ipc->driver, self);
}
@@ -151,6 +152,7 @@ gbinder_remote_object_new(
self->ipc = gbinder_ipc_ref(ipc);
self->handle = handle;
if (!(self->dead = dead)) {
gbinder_ipc_looper_check(self->ipc); /* For death notifications */
gbinder_driver_acquire(ipc->driver, handle);
gbinder_driver_request_death_notification(ipc->driver, self);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* 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.
* 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
@@ -33,6 +33,12 @@
#include "gbinder_rpc_protocol.h"
#include "gbinder_reader.h"
#include "gbinder_writer.h"
#include "gbinder_config.h"
#include "gbinder_log.h"
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
#define UNSET_WORK_SOURCE (-1)
/*==========================================================================*
* GBinderIpcProtocol callbacks (see Parcel::writeInterfaceToken in Android)
@@ -40,19 +46,39 @@
*
* platform/system/libhwbinder/Parcel.cpp
* platform/frameworks/native/libs/binder/Parcel.cpp
*
* which mutate from version to version. Specific device => protocol
* mapping can be optionally configured in /etc/gbinder.conf file.
* The default protocol configuration looks like this:
*
* [Protocol]
* Default = aidl
* /dev/binder = aidl
* /dev/hwbinder = hidl
*
*==========================================================================*/
#define CONF_GROUP GBINDER_CONFIG_GROUP_PROTOCOL
#define CONF_DEFAULT GBINDER_CONFIG_VALUE_DEFAULT
static GHashTable* gbinder_rpc_protocol_map = NULL;
/*
* Default protocol for those binder devices which which haven't been
* explicitely mapped.
*/
#define DEFAULT_PROTOCOL gbinder_rpc_protocol_aidl
static const GBinderRpcProtocol DEFAULT_PROTOCOL;
static const GBinderRpcProtocol* gbinder_rpc_protocol_default =
&DEFAULT_PROTOCOL;
/*==========================================================================*
* /dev/binder
* The original AIDL protocol.
*==========================================================================*/
/* No idea what that is... */
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
static
void
gbinder_rpc_protocol_binder_write_ping(
gbinder_rpc_protocol_aidl_write_ping(
GBinderWriter* writer)
{
/* No payload */
@@ -60,7 +86,7 @@ gbinder_rpc_protocol_binder_write_ping(
static
void
gbinder_rpc_protocol_binder_write_rpc_header(
gbinder_rpc_protocol_aidl_write_rpc_header(
GBinderWriter* writer,
const char* iface)
{
@@ -75,7 +101,7 @@ gbinder_rpc_protocol_binder_write_rpc_header(
static
const char*
gbinder_rpc_protocol_binder_read_rpc_header(
gbinder_rpc_protocol_aidl_read_rpc_header(
GBinderReader* reader,
guint32 txcode,
char** iface)
@@ -91,13 +117,69 @@ gbinder_rpc_protocol_binder_read_rpc_header(
return *iface;
}
static const GBinderRpcProtocol gbinder_rpc_protocol_aidl = {
.name = "aidl",
.ping_tx = GBINDER_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_aidl_write_ping,
.write_rpc_header = gbinder_rpc_protocol_aidl_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_aidl_read_rpc_header
};
/*==========================================================================*
* /dev/hwbinder
* AIDL protocol appeared in Android 10 (API level 29)
*==========================================================================*/
static
void
gbinder_rpc_protocol_hwbinder_write_rpc_header(
gbinder_rpc_protocol_aidl2_write_rpc_header(
GBinderWriter* writer,
const char* iface)
{
/*
* writeInt32(IPCThreadState::self()->getStrictModePolicy() |
* STRICT_MODE_PENALTY_GATHER);
* writeInt32(IPCThreadState::kUnsetWorkSource);
* writeString16(interface);
*/
gbinder_writer_append_int32(writer, BINDER_RPC_FLAGS);
gbinder_writer_append_int32(writer, UNSET_WORK_SOURCE);
gbinder_writer_append_string16(writer, iface);
}
static
const char*
gbinder_rpc_protocol_aidl2_read_rpc_header(
GBinderReader* reader,
guint32 txcode,
char** iface)
{
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) /* flags */ &&
gbinder_reader_read_int32(reader, NULL) /* work source */) {
*iface = gbinder_reader_read_string16(reader);
} else {
*iface = NULL;
}
return *iface;
}
static const GBinderRpcProtocol gbinder_rpc_protocol_aidl2 = {
.name = "aidl2",
.ping_tx = GBINDER_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_aidl_write_ping, /* no payload */
.write_rpc_header = gbinder_rpc_protocol_aidl2_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_aidl2_read_rpc_header
};
/*==========================================================================*
* The original /dev/hwbinder protocol.
*==========================================================================*/
static
void
gbinder_rpc_protocol_hidl_write_rpc_header(
GBinderWriter* writer,
const char* iface)
{
@@ -109,16 +191,16 @@ gbinder_rpc_protocol_hwbinder_write_rpc_header(
static
void
gbinder_rpc_protocol_hwbinder_write_ping(
gbinder_rpc_protocol_hidl_write_ping(
GBinderWriter* writer)
{
gbinder_rpc_protocol_hwbinder_write_rpc_header(writer,
gbinder_rpc_protocol_hidl_write_rpc_header(writer,
"android.hidl.base@1.0::IBase");
}
static
const char*
gbinder_rpc_protocol_hwbinder_read_rpc_header(
gbinder_rpc_protocol_hidl_read_rpc_header(
GBinderReader* reader,
guint32 txcode,
char** iface)
@@ -127,30 +209,126 @@ gbinder_rpc_protocol_hwbinder_read_rpc_header(
return gbinder_reader_read_string8(reader);
}
static const GBinderRpcProtocol gbinder_rpc_protocol_hidl = {
.name = "hidl",
.ping_tx = HIDL_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_hidl_write_ping,
.write_rpc_header = gbinder_rpc_protocol_hidl_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_hidl_read_rpc_header
};
/*==========================================================================*
* Implementation
*==========================================================================*/
/* All known protocols */
static const GBinderRpcProtocol* gbinder_rpc_protocol_list[] = {
&gbinder_rpc_protocol_aidl,
&gbinder_rpc_protocol_aidl2,
&gbinder_rpc_protocol_hidl
};
static
const GBinderRpcProtocol*
gbinder_rpc_protocol_find(
const char* name)
{
guint i;
for (i = 0; i < G_N_ELEMENTS(gbinder_rpc_protocol_list); i++) {
if (!g_ascii_strcasecmp(gbinder_rpc_protocol_list[i]->name, name)) {
return gbinder_rpc_protocol_list[i];
}
}
return NULL;
}
static
void
gbinder_rpc_protocol_map_add_default(
GHashTable* map,
const char* dev,
const GBinderRpcProtocol* protocol)
{
if (!g_hash_table_contains(map, dev)) {
g_hash_table_insert(map, g_strdup(dev), (gpointer) protocol);
}
}
static
gconstpointer
gbinder_rpc_protocol_value_map(
const char* name)
{
return gbinder_rpc_protocol_find(name);
}
static
GHashTable*
gbinder_rpc_protocol_load_config()
{
GHashTable* map = gbinder_config_load(CONF_GROUP,
gbinder_rpc_protocol_value_map);
/* Add default configuration if it's not overridden */
gbinder_rpc_protocol_map_add_default(map,
GBINDER_DEFAULT_BINDER, &gbinder_rpc_protocol_aidl);
gbinder_rpc_protocol_map_add_default(map,
GBINDER_DEFAULT_HWBINDER, &gbinder_rpc_protocol_hidl);
return map;
}
/* Runs at exit */
void
gbinder_rpc_protocol_exit()
{
if (gbinder_rpc_protocol_map) {
g_hash_table_destroy(gbinder_rpc_protocol_map);
gbinder_rpc_protocol_map = NULL;
}
/* Reset the default too, mostly for unit testing */
gbinder_rpc_protocol_default = &DEFAULT_PROTOCOL;
}
/*==========================================================================*
* Interface
*==========================================================================*/
const GBinderRpcProtocol gbinder_rpc_protocol_binder = {
.ping_tx = GBINDER_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_binder_write_ping,
.write_rpc_header = gbinder_rpc_protocol_binder_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_binder_read_rpc_header
};
const GBinderRpcProtocol gbinder_rpc_protocol_hwbinder = {
.ping_tx = HIDL_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_hwbinder_write_ping,
.write_rpc_header = gbinder_rpc_protocol_hwbinder_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_hwbinder_read_rpc_header
};
const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device(
const char* dev)
{
return (dev && !strcmp(dev, GBINDER_DEFAULT_HWBINDER)) ?
&gbinder_rpc_protocol_hwbinder : &gbinder_rpc_protocol_binder;
if (dev) {
const GBinderRpcProtocol* protocol;
if (!gbinder_rpc_protocol_map) {
const GBinderRpcProtocol* p;
/* One-time initialization */
gbinder_rpc_protocol_map = gbinder_rpc_protocol_load_config();
/* "Default" is a special value stored in a special variable */
p = g_hash_table_lookup(gbinder_rpc_protocol_map, CONF_DEFAULT);
if (p) {
g_hash_table_remove(gbinder_rpc_protocol_map, CONF_DEFAULT);
gbinder_rpc_protocol_default = p;
} else {
gbinder_rpc_protocol_default = &DEFAULT_PROTOCOL;
}
}
protocol = g_hash_table_lookup(gbinder_rpc_protocol_map, dev);
if (protocol) {
GDEBUG("Using %s protocol for %s", protocol->name, dev);
return protocol;
}
GDEBUG("Using default protocol %s for %s",
gbinder_rpc_protocol_default->name, dev);
} else {
GDEBUG("Using default protocol %s",
gbinder_rpc_protocol_default->name);
}
return gbinder_rpc_protocol_default;
}
/*

View File

@@ -13,7 +13,6 @@
* 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.
* 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.
@@ -37,11 +36,12 @@
#include "gbinder_types_p.h"
/*
* For whatever reason services communicating via /dev/binder
* and /dev/hwbinder use slightly different RPC headers.
* There are several versions of binder RPC protocol with diffferent
* transaction headers and transaction codes.
*/
struct gbinder_rpc_protocol {
const char* name;
guint32 ping_tx;
void (*write_ping)(GBinderWriter* writer);
void (*write_rpc_header)(GBinderWriter* writer, const char* iface);
@@ -49,15 +49,19 @@ struct gbinder_rpc_protocol {
char** iface);
};
extern const GBinderRpcProtocol gbinder_rpc_protocol_binder GBINDER_INTERNAL;
extern const GBinderRpcProtocol gbinder_rpc_protocol_hwbinder GBINDER_INTERNAL;
/* Returns one of the above based on the device name */
const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device(
const char* dev)
GBINDER_INTERNAL;
/* Runs at exit, declared here strictly for unit tests */
void
gbinder_rpc_protocol_exit(
void)
GBINDER_DESTRUCTOR
GBINDER_INTERNAL;
#endif /* GBINDER_RPC_PROTOCOL_H */
/*

View File

@@ -34,6 +34,7 @@
#include "gbinder_servicemanager_p.h"
#include "gbinder_client_p.h"
#include "gbinder_config.h"
#include "gbinder_local_object_p.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_eventloop_p.h"
@@ -47,6 +48,51 @@
#include <errno.h>
/*==========================================================================*
*
* Different versions of Android come with different flavors of service
* managers. They are usually based on these two more or less independent
* variants:
*
* platform/frameworks/native/cmds/servicemanager/ServiceManager.cpp
* platform/system/hwservicemanager/ServiceManager.cpp
*
* They are talking slightly different protocols which slightly mutate
* from version to version. If that's not complex enough, different
* kinds of service managers can be running simultaneously, serving
* different binder devices. Specific device => servicemanager mapping
* can be optionally configured in /etc/gbinder.conf file. The default
* service manager configuration looks like this:
*
* [ServiceManager]
* Default = aidl
* /dev/binder = aidl
* /dev/hwbinder = hidl
*
*==========================================================================*/
#define CONF_GROUP GBINDER_CONFIG_GROUP_SERVICEMANAGER
#define CONF_DEFAULT GBINDER_CONFIG_VALUE_DEFAULT
typedef struct gbinder_servicemanager_type {
const char* name;
GType (*get_type)(void);
} GBinderServiceManagerType;
static const GBinderServiceManagerType gbinder_servicemanager_types[] = {
{ "aidl", gbinder_servicemanager_aidl_get_type },
{ "aidl2", gbinder_servicemanager_aidl2_get_type },
{ "hidl", gbinder_servicemanager_hidl_get_type }
};
#define SERVICEMANAGER_TYPE_AIDL (gbinder_servicemanager_types + 0)
#define SERVICEMANAGER_TYPE_HIDL (gbinder_servicemanager_types + 2)
#define SERVICEMANAGER_TYPE_DEFAULT SERVICEMANAGER_TYPE_AIDL
static GHashTable* gbinder_servicemanager_map = NULL;
static const GBinderServiceManagerType* gbinder_servicemanager_default =
SERVICEMANAGER_TYPE_DEFAULT;
#define PRESENSE_WAIT_MS_MIN (100)
#define PRESENSE_WAIT_MS_MAX (1000)
#define PRESENSE_WAIT_MS_STEP (100)
@@ -75,9 +121,6 @@ G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
#define GBINDER_SERVICEMANAGER(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManager)
#define GBINDER_SERVICEMANAGER_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
#define GBINDER_SERVICEMANAGER_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
@@ -408,6 +451,64 @@ gbinder_servicemanager_autorelease_cb(
g_slist_free_full(list, g_object_unref);
}
static
void
gbinder_servicemanager_map_add_default(
GHashTable* map,
const char* dev,
const GBinderServiceManagerType* type)
{
if (!g_hash_table_contains(map, dev)) {
g_hash_table_insert(map, g_strdup(dev), (gpointer) type);
}
}
static
gconstpointer
gbinder_servicemanager_value_map(
const char* name)
{
guint i;
for (i = 0; i < G_N_ELEMENTS(gbinder_servicemanager_types); i++) {
const GBinderServiceManagerType* t = gbinder_servicemanager_types + i;
if (!g_strcmp0(name, t->name)) {
return t;
}
}
return NULL;
}
static
GHashTable*
gbinder_servicemanager_load_config()
{
GHashTable* map = gbinder_config_load(CONF_GROUP,
gbinder_servicemanager_value_map);
/* Add default configuration if it's not overridden */
gbinder_servicemanager_map_add_default(map,
GBINDER_DEFAULT_BINDER, SERVICEMANAGER_TYPE_AIDL);
gbinder_servicemanager_map_add_default(map,
GBINDER_DEFAULT_HWBINDER, SERVICEMANAGER_TYPE_HIDL);
return map;
}
/* Runs at exit */
void
gbinder_servicemanager_exit(
void)
{
if (gbinder_servicemanager_map) {
g_hash_table_destroy(gbinder_servicemanager_map);
gbinder_servicemanager_map = NULL;
}
/* Reset the default too, mostly for unit testing */
gbinder_servicemanager_default = SERVICEMANAGER_TYPE_DEFAULT;
}
/*==========================================================================*
* Internal interface
*==========================================================================*/
@@ -424,9 +525,9 @@ gbinder_servicemanager_new_with_type(
GBinderIpc* ipc;
if (!dev) dev = klass->default_device;
ipc = gbinder_ipc_new(dev, klass->rpc_protocol);
ipc = gbinder_ipc_new(dev);
if (ipc) {
/* Create a possible dead remote object */
/* Create a possibly dead remote object */
GBinderRemoteObject* object = gbinder_ipc_get_remote_object
(ipc, GBINDER_SERVICEMANAGER_HANDLE, TRUE);
@@ -517,11 +618,35 @@ GBinderServiceManager*
gbinder_servicemanager_new(
const char* dev)
{
if (!g_strcmp0(dev, GBINDER_DEFAULT_HWBINDER)) {
return gbinder_hwservicemanager_new(dev);
} else {
return gbinder_defaultservicemanager_new(dev);
if (dev) {
const GBinderServiceManagerType* type = NULL;
if (!gbinder_servicemanager_map) {
const GBinderServiceManagerType* t;
/* One-time initialization */
gbinder_servicemanager_map = gbinder_servicemanager_load_config();
/* "Default" is a special value stored in a special variable */
t = g_hash_table_lookup(gbinder_servicemanager_map, CONF_DEFAULT);
if (t) {
g_hash_table_remove(gbinder_servicemanager_map, CONF_DEFAULT);
gbinder_servicemanager_default = t;
} else {
gbinder_servicemanager_default = SERVICEMANAGER_TYPE_DEFAULT;
}
}
type = g_hash_table_lookup(gbinder_servicemanager_map, dev);
if (type) {
GDEBUG("Using %s service manager for %s", type->name, dev);
} else {
type = gbinder_servicemanager_default;
GDEBUG("Using default service manager %s for %s", type->name, dev);
}
return gbinder_servicemanager_new_with_type(type->get_type(), dev);
}
return NULL;
}
GBinderLocalObject*
@@ -870,6 +995,28 @@ gbinder_servicemanager_remove_handlers(
}
}
/*
* These two exist mostly for backward compatibility. Normally,
* gbinder_servicemanager_new() should be used, to allow the type of
* service manager to be configurable per device via /etc/gbinder.conf
*/
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_servicemanager_aidl_get_type(), dev);
}
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_servicemanager_hidl_get_type(), dev);
}
/*==========================================================================*
* Internals
*==========================================================================*/

View File

@@ -30,8 +30,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_servicemanager_p.h"
#include "gbinder_rpc_protocol.h"
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_servicemanager_aidl.h"
#include "gbinder_servicepoll.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_log.h"
@@ -40,61 +41,47 @@
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
#include <gutil_macros.h>
#include <errno.h>
#include <pthread.h>
typedef struct gbinder_defaultservicemanager_watch {
typedef struct gbinder_servicemanager_aidl_watch {
GBinderServicePoll* poll;
char* name;
gulong handler_id;
GBinderEventLoopTimeout* notify;
} GBinderDefaultServiceManagerWatch;
} GBinderServiceManagerAidlWatch;
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass;
typedef struct gbinder_defaultservicemanager {
GBinderServiceManager manager;
struct gbinder_servicemanager_aidl_priv {
GBinderServicePoll* poll;
GHashTable* watch_table;
} GBinderDefaultServiceManager;
};
G_DEFINE_TYPE(GBinderDefaultServiceManager,
gbinder_defaultservicemanager,
G_DEFINE_TYPE(GBinderServiceManagerAidl,
gbinder_servicemanager_aidl,
GBINDER_TYPE_SERVICEMANAGER)
#define PARENT_CLASS gbinder_defaultservicemanager_parent_class
#define GBINDER_TYPE_DEFAULTSERVICEMANAGER \
gbinder_defaultservicemanager_get_type()
#define GBINDER_DEFAULTSERVICEMANAGER(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_DEFAULTSERVICEMANAGER, \
GBinderDefaultServiceManager)
#define PARENT_CLASS gbinder_servicemanager_aidl_parent_class
#define GBINDER_SERVICEMANAGER_AIDL(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
GBinderServiceManagerAidl)
#define GBINDER_SERVICEMANAGER_AIDL_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
GBinderServiceManagerAidlClass)
enum gbinder_defaultservicemanager_calls {
enum gbinder_servicemanager_aidl_calls {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION
};
#define DEFAULTSERVICEMANAGER_IFACE "android.os.IServiceManager"
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(GBINDER_TYPE_DEFAULTSERVICEMANAGER, dev);
}
#define SERVICEMANAGER_AIDL_IFACE "android.os.IServiceManager"
static
void
gbinder_defaultservicemanager_watch_proc(
gbinder_servicemanager_aidl_watch_proc(
GBinderServicePoll* poll,
const char* name_added,
void* user_data)
{
GBinderDefaultServiceManagerWatch* watch = user_data;
GBinderServiceManagerAidlWatch* watch = user_data;
if (!g_strcmp0(name_added, watch->name)) {
GBinderServiceManager* manager =
@@ -110,10 +97,10 @@ gbinder_defaultservicemanager_watch_proc(
static
gboolean
gbinder_defaultservicemanager_watch_notify(
gbinder_servicemanager_aidl_watch_notify(
gpointer user_data)
{
GBinderDefaultServiceManagerWatch* watch = user_data;
GBinderServiceManagerAidlWatch* watch = user_data;
GBinderServiceManager* manager = gbinder_servicepoll_manager(watch->poll);
char* name = g_strdup(watch->name);
@@ -126,54 +113,75 @@ gbinder_defaultservicemanager_watch_notify(
static
void
gbinder_defaultservicemanager_watch_free(
gbinder_servicemanager_aidl_watch_free(
gpointer user_data)
{
GBinderDefaultServiceManagerWatch* watch = user_data;
GBinderServiceManagerAidlWatch* watch = user_data;
gbinder_timeout_remove(watch->notify);
gbinder_servicepoll_remove_handler(watch->poll, watch->handler_id);
gbinder_servicepoll_unref(watch->poll);
g_free(watch->name);
g_slice_free(GBinderDefaultServiceManagerWatch, watch);
g_slice_free(GBinderServiceManagerAidlWatch, watch);
}
static
GBinderDefaultServiceManagerWatch*
gbinder_defaultservicemanager_watch_new(
GBinderDefaultServiceManager* manager,
GBinderServiceManagerAidlWatch*
gbinder_servicemanager_aidl_watch_new(
GBinderServiceManagerAidl* self,
const char* name)
{
GBinderDefaultServiceManagerWatch* watch =
g_slice_new0(GBinderDefaultServiceManagerWatch);
GBinderServiceManagerAidlPriv* priv = self->priv;
GBinderServiceManagerAidlWatch* watch =
g_slice_new0(GBinderServiceManagerAidlWatch);
watch->name = g_strdup(name);
watch->poll = gbinder_servicepoll_new(&manager->manager, &manager->poll);
watch->handler_id = gbinder_servicepoll_add_handler(watch->poll,
gbinder_defaultservicemanager_watch_proc, watch);
watch->poll = gbinder_servicepoll_new(&self->manager, &priv->poll);
watch->handler_id = gbinder_servicepoll_add_handler(priv->poll,
gbinder_servicemanager_aidl_watch_proc, watch);
return watch;
}
static
GBinderLocalRequest*
gbinder_servicemanager_list_services_req(
GBinderServiceManager* self,
gbinder_servicemanager_aidl_list_services_req(
GBinderClient* client,
gint32 index)
{
return gbinder_local_request_append_int32
(gbinder_client_new_request(self->client), index);
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_int32(req, index);
return req;
}
static
GBinderLocalRequest*
gbinder_servicemanager_aidl_add_service_req(
GBinderClient* client,
const char* name,
GBinderLocalObject* obj)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
return req;
}
static
char**
gbinder_defaultservicemanager_list(
GBinderServiceManager* self)
gbinder_servicemanager_aidl_list(
GBinderServiceManager* manager)
{
GPtrArray* list = g_ptr_array_new();
GBinderLocalRequest* req = gbinder_servicemanager_list_services_req(self,0);
GBinderClient* client = manager->client;
GBinderServiceManagerAidlClass* klass =
GBINDER_SERVICEMANAGER_AIDL_GET_CLASS(manager);
GBinderLocalRequest* req = klass->list_services_req(client, 0);
GBinderRemoteReply* reply;
while ((reply = gbinder_client_transact_sync_reply(self->client,
while ((reply = gbinder_client_transact_sync_reply(client,
LIST_SERVICES_TRANSACTION, req, NULL)) != NULL) {
char* service = gbinder_remote_reply_read_string16(reply);
@@ -181,7 +189,7 @@ gbinder_defaultservicemanager_list(
if (service) {
g_ptr_array_add(list, service);
gbinder_local_request_unref(req);
req = gbinder_servicemanager_list_services_req(self, list->len);
req = klass->list_services_req(client, list->len);
} else {
break;
}
@@ -194,7 +202,7 @@ gbinder_defaultservicemanager_list(
static
GBinderRemoteObject*
gbinder_defaultservicemanager_get_service(
gbinder_servicemanager_aidl_get_service(
GBinderServiceManager* self,
const char* name,
int* status)
@@ -215,20 +223,16 @@ gbinder_defaultservicemanager_get_service(
static
int
gbinder_defaultservicemanager_add_service(
GBinderServiceManager* self,
gbinder_servicemanager_aidl_add_service(
GBinderServiceManager* manager,
const char* name,
GBinderLocalObject* obj)
{
int status;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
reply = gbinder_client_transact_sync_reply(self->client,
GBinderClient* client = manager->client;
GBinderLocalRequest* req = GBINDER_SERVICEMANAGER_AIDL_GET_CLASS
(manager)->add_service_req(client, name, obj);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply(client,
ADD_SERVICE_TRANSACTION, req, &status);
gbinder_remote_reply_unref(reply);
@@ -238,7 +242,7 @@ gbinder_defaultservicemanager_add_service(
static
GBINDER_SERVICEMANAGER_NAME_CHECK
gbinder_defaultservicemanager_check_name(
gbinder_servicemanager_aidl_check_name(
GBinderServiceManager* self,
const char* name)
{
@@ -247,69 +251,84 @@ gbinder_defaultservicemanager_check_name(
static
gboolean
gbinder_defaultservicemanager_watch(
gbinder_servicemanager_aidl_watch(
GBinderServiceManager* manager,
const char* name)
{
GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(manager);
GBinderDefaultServiceManagerWatch* watch =
gbinder_defaultservicemanager_watch_new(self, name);
GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
GBinderServiceManagerAidlPriv* priv = self->priv;
GBinderServiceManagerAidlWatch* watch =
gbinder_servicemanager_aidl_watch_new(self, name);
g_hash_table_replace(self->watch_table, watch->name, watch);
g_hash_table_replace(priv->watch_table, watch->name, watch);
if (gbinder_servicepoll_is_known_name(watch->poll, name)) {
watch->notify = gbinder_idle_add
(gbinder_defaultservicemanager_watch_notify, watch);
(gbinder_servicemanager_aidl_watch_notify, watch);
}
return TRUE;
}
static
void
gbinder_defaultservicemanager_unwatch(
gbinder_servicemanager_aidl_unwatch(
GBinderServiceManager* manager,
const char* name)
{
g_hash_table_remove(GBINDER_DEFAULTSERVICEMANAGER(manager)->watch_table,
name);
GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
GBinderServiceManagerAidlPriv* priv = self->priv;
g_hash_table_remove(priv->watch_table, name);
}
static
void
gbinder_defaultservicemanager_init(
GBinderDefaultServiceManager* self)
gbinder_servicemanager_aidl_init(
GBinderServiceManagerAidl* self)
{
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, gbinder_defaultservicemanager_watch_free);
GBinderServiceManagerAidlPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
GBINDER_TYPE_SERVICEMANAGER_AIDL, GBinderServiceManagerAidlPriv);
self->priv = priv;
priv->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, gbinder_servicemanager_aidl_watch_free);
}
static
void
gbinder_defaultservicemanager_finalize(
gbinder_servicemanager_aidl_finalize(
GObject* object)
{
GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(object);
GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(object);
GBinderServiceManagerAidlPriv* priv = self->priv;
g_hash_table_destroy(self->watch_table);
g_hash_table_destroy(priv->watch_table);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
gbinder_defaultservicemanager_class_init(
GBinderDefaultServiceManagerClass* klass)
gbinder_servicemanager_aidl_class_init(
GBinderServiceManagerAidlClass* klass)
{
klass->iface = DEFAULTSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_BINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
GBinderServiceManagerClass* manager = GBINDER_SERVICEMANAGER_CLASS(klass);
GObjectClass* object = G_OBJECT_CLASS(klass);
klass->list = gbinder_defaultservicemanager_list;
klass->get_service = gbinder_defaultservicemanager_get_service;
klass->add_service = gbinder_defaultservicemanager_add_service;
klass->check_name = gbinder_defaultservicemanager_check_name;
g_type_class_add_private(klass, sizeof(GBinderServiceManagerAidlPriv));
klass->list_services_req = gbinder_servicemanager_aidl_list_services_req;
klass->add_service_req = gbinder_servicemanager_aidl_add_service_req;
manager->iface = SERVICEMANAGER_AIDL_IFACE;
manager->default_device = GBINDER_DEFAULT_BINDER;
manager->list = gbinder_servicemanager_aidl_list;
manager->get_service = gbinder_servicemanager_aidl_get_service;
manager->add_service = gbinder_servicemanager_aidl_add_service;
manager->check_name = gbinder_servicemanager_aidl_check_name;
/* normalize_name is not needed */
klass->watch = gbinder_defaultservicemanager_watch;
klass->unwatch = gbinder_defaultservicemanager_unwatch;
G_OBJECT_CLASS(klass)->finalize = gbinder_defaultservicemanager_finalize;
manager->watch = gbinder_servicemanager_aidl_watch;
manager->unwatch = gbinder_servicemanager_aidl_unwatch;
object->finalize = gbinder_servicemanager_aidl_finalize;
}
/*

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_SERVICEMANAGER_AIDL_H
#define GBINDER_SERVICEMANAGER_AIDL_H
#include "gbinder_servicemanager_p.h"
typedef struct gbinder_servicemanager_aidl_priv GBinderServiceManagerAidlPriv;
typedef struct gbinder_servicemanager_aidl {
GBinderServiceManager manager;
GBinderServiceManagerAidlPriv* priv;
} GBinderServiceManagerAidl;
typedef struct gbinder_servicemanager_aidl_class {
GBinderServiceManagerClass parent;
GBinderLocalRequest* (*list_services_req)
(GBinderClient* client, gint32 index);
GBinderLocalRequest* (*add_service_req)
(GBinderClient* client, const char* name, GBinderLocalObject* obj);
} GBinderServiceManagerAidlClass;
#define GBINDER_TYPE_SERVICEMANAGER_AIDL \
gbinder_servicemanager_aidl_get_type()
#define GBINDER_SERVICEMANAGER_AIDL_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
GBinderServiceManagerAidlClass)
#endif /* GBINDER_SERVICEMANAGER_AIDL_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 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_servicemanager_aidl.h"
#include <gbinder_client.h>
#include <gbinder_local_request.h>
/* Variant of AIDL servicemanager appeared in Android 9 (API level 28) */
typedef GBinderServiceManagerAidl GBinderServiceManagerAidl2;
typedef GBinderServiceManagerAidlClass GBinderServiceManagerAidl2Class;
G_DEFINE_TYPE(GBinderServiceManagerAidl2,
gbinder_servicemanager_aidl2,
GBINDER_TYPE_SERVICEMANAGER_AIDL)
#define PARENT_CLASS gbinder_servicemanager_aidl2_parent_class
#define DUMP_FLAG_PRIORITY_DEFAULT (0x08)
#define DUMP_FLAG_PRIORITY_ALL (0x0f)
static
GBinderLocalRequest*
gbinder_servicemanager_aidl2_list_services_req(
GBinderClient* client,
gint32 index)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_int32(req, index);
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_ALL);
return req;
}
static
GBinderLocalRequest*
gbinder_servicemanager_aidl2_add_service_req(
GBinderClient* client,
const char* name,
GBinderLocalObject* obj)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT);
return req;
}
static
void
gbinder_servicemanager_aidl2_init(
GBinderServiceManagerAidl* self)
{
}
static
void
gbinder_servicemanager_aidl2_class_init(
GBinderServiceManagerAidl2Class* cls)
{
cls->list_services_req = gbinder_servicemanager_aidl2_list_services_req;
cls->add_service_req = gbinder_servicemanager_aidl2_add_service_req;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* 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.
* 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
@@ -31,7 +31,6 @@
*/
#include "gbinder_servicemanager_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
@@ -42,30 +41,30 @@
#include <gbinder_reader.h>
#include <errno.h>
#include <pthread.h>
typedef struct gbinder_hwservicemanager_watch {
typedef struct gbinder_servicemanager_hidl_watch {
char* name;
GBinderLocalObject* callback;
} GBinderHwServiceManagerWatch;
} GBinderServiceManagerHidlWatch;
typedef GBinderServiceManagerClass GBinderHwServiceManagerClass;
typedef struct gbinder_hwservicemanager {
typedef GBinderServiceManagerClass GBinderServiceManagerHidlClass;
typedef struct gbinder_servicemanager_hidl {
GBinderServiceManager manager;
GHashTable* watch_table;
} GBinderHwServiceManager;
} GBinderServiceManagerHidl;
G_DEFINE_TYPE(GBinderHwServiceManager,
gbinder_hwservicemanager,
G_DEFINE_TYPE(GBinderServiceManagerHidl,
gbinder_servicemanager_hidl,
GBINDER_TYPE_SERVICEMANAGER)
#define PARENT_CLASS gbinder_hwservicemanager_parent_class
#define GBINDER_TYPE_HWSERVICEMANAGER (gbinder_hwservicemanager_get_type())
#define GBINDER_HWSERVICEMANAGER(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_HWSERVICEMANAGER, \
GBinderHwServiceManager)
#define PARENT_CLASS gbinder_servicemanager_hidl_parent_class
#define GBINDER_TYPE_SERVICEMANAGER_HIDL \
gbinder_servicemanager_hidl_get_type()
#define GBINDER_SERVICEMANAGER_HIDL(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER_HIDL, \
GBinderServiceManagerHidl)
enum gbinder_hwservicemanager_calls {
enum gbinder_servicemanager_hidl_calls {
GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
ADD_TRANSACTION,
GET_TRANSPORT_TRANSACTION,
@@ -76,18 +75,18 @@ enum gbinder_hwservicemanager_calls {
REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
};
enum gbinder_hwservicemanager_notifications {
enum gbinder_servicemanager_hidl_notifications {
ON_REGISTRATION_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION
};
#define HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager"
#define HWSERVICEMANAGER_NOTIFICATION_IFACE \
#define SERVICEMANAGER_HIDL_IFACE "android.hidl.manager@1.0::IServiceManager"
#define SERVICEMANAGER_HIDL_NOTIFICATION_IFACE \
"android.hidl.manager@1.0::IServiceNotification"
static
void
gbinder_hwservicemanager_handle_registration(
GBinderHwServiceManager* self,
gbinder_servicemanager_hidl_handle_registration(
GBinderServiceManagerHidl* self,
GBinderReader* reader)
{
char* fqname = gbinder_reader_read_hidl_string(reader);
@@ -111,7 +110,7 @@ gbinder_hwservicemanager_handle_registration(
static
GBinderLocalReply*
gbinder_hwservicemanager_notification(
gbinder_servicemanager_hidl_notification(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
@@ -119,22 +118,22 @@ gbinder_hwservicemanager_notification(
int* status,
void* user_data)
{
GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(user_data);
GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(user_data);
const char* iface = gbinder_remote_request_interface(req);
if (!g_strcmp0(iface, HWSERVICEMANAGER_NOTIFICATION_IFACE)) {
if (!g_strcmp0(iface, SERVICEMANAGER_HIDL_NOTIFICATION_IFACE)) {
GBinderReader reader;
gbinder_remote_request_init_reader(req, &reader);
switch (code) {
case ON_REGISTRATION_TRANSACTION:
GDEBUG(HWSERVICEMANAGER_NOTIFICATION_IFACE " %u onRegistration",
GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u onRegistration",
code);
gbinder_hwservicemanager_handle_registration(self, &reader);
gbinder_servicemanager_hidl_handle_registration(self, &reader);
*status = GBINDER_STATUS_OK;
break;
default:
GDEBUG(HWSERVICEMANAGER_NOTIFICATION_IFACE " %u", code);
GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u", code);
*status = GBINDER_STATUS_FAILED;
break;
}
@@ -145,17 +144,9 @@ gbinder_hwservicemanager_notification(
return NULL;
}
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_hwservicemanager_get_type(), dev);
}
static
char**
gbinder_hwservicemanager_list(
gbinder_servicemanager_hidl_list(
GBinderServiceManager* self)
{
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
@@ -184,7 +175,7 @@ gbinder_hwservicemanager_list(
static
GBinderRemoteObject*
gbinder_hwservicemanager_get_service(
gbinder_servicemanager_hidl_get_service(
GBinderServiceManager* self,
const char* fqinstance,
int* status)
@@ -231,7 +222,7 @@ gbinder_hwservicemanager_get_service(
static
int
gbinder_hwservicemanager_add_service(
gbinder_servicemanager_hidl_add_service(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* obj)
@@ -254,10 +245,10 @@ gbinder_hwservicemanager_add_service(
static
void
gbinder_hwservicemanager_watch_free(
gbinder_servicemanager_hidl_watch_free(
gpointer data)
{
GBinderHwServiceManagerWatch* watch = data;
GBinderServiceManagerHidlWatch* watch = data;
g_free(watch->name);
gbinder_local_object_drop(watch->callback);
@@ -266,7 +257,7 @@ gbinder_hwservicemanager_watch_free(
static
GBINDER_SERVICEMANAGER_NAME_CHECK
gbinder_hwservicemanager_check_name(
gbinder_servicemanager_hidl_check_name(
GBinderServiceManager* self,
const char* name)
{
@@ -287,32 +278,32 @@ gbinder_hwservicemanager_check_name(
static
char*
gbinder_hwservicemanager_normalize_name(
gbinder_servicemanager_hidl_normalize_name(
GBinderServiceManager* self,
const char* name)
{
/* Slash must be there, see gbinder_hwservicemanager_check_name() above */
/* Slash must be there, see gbinder_servicemanager_hidl_check_name() */
return g_strndup(name, strchr(name, '/') - name);
}
static
gboolean
gbinder_hwservicemanager_watch(
gbinder_servicemanager_hidl_watch(
GBinderServiceManager* manager,
const char* name)
{
GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(manager);
GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(manager);
GBinderLocalRequest* req = gbinder_client_new_request(manager->client);
GBinderRemoteReply* reply;
GBinderHwServiceManagerWatch* watch =
g_new0(GBinderHwServiceManagerWatch, 1);
GBinderServiceManagerHidlWatch* watch =
g_new0(GBinderServiceManagerHidlWatch, 1);
gboolean success = FALSE;
int status;
watch->name = g_strdup(name);
watch->callback = gbinder_servicemanager_new_local_object(manager,
HWSERVICEMANAGER_NOTIFICATION_IFACE,
gbinder_hwservicemanager_notification, self);
SERVICEMANAGER_HIDL_NOTIFICATION_IFACE,
gbinder_servicemanager_hidl_notification, self);
g_hash_table_replace(self->watch_table, watch->name, watch);
/* registerForNotifications(string fqName, string name,
@@ -344,28 +335,29 @@ gbinder_hwservicemanager_watch(
static
void
gbinder_hwservicemanager_unwatch(
gbinder_servicemanager_hidl_unwatch(
GBinderServiceManager* manager,
const char* name)
{
g_hash_table_remove(GBINDER_HWSERVICEMANAGER(manager)->watch_table, name);
g_hash_table_remove(GBINDER_SERVICEMANAGER_HIDL(manager)->
watch_table, name);
}
static
void
gbinder_hwservicemanager_init(
GBinderHwServiceManager* self)
gbinder_servicemanager_hidl_init(
GBinderServiceManagerHidl* self)
{
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, gbinder_hwservicemanager_watch_free);
NULL, gbinder_servicemanager_hidl_watch_free);
}
static
void
gbinder_hwservicemanager_finalize(
gbinder_servicemanager_hidl_finalize(
GObject* object)
{
GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(object);
GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(object);
g_hash_table_destroy(self->watch_table);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
@@ -373,21 +365,20 @@ gbinder_hwservicemanager_finalize(
static
void
gbinder_hwservicemanager_class_init(
GBinderHwServiceManagerClass* klass)
gbinder_servicemanager_hidl_class_init(
GBinderServiceManagerHidlClass* klass)
{
klass->iface = HWSERVICEMANAGER_IFACE;
klass->iface = SERVICEMANAGER_HIDL_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;
klass->list = gbinder_hwservicemanager_list;
klass->get_service = gbinder_hwservicemanager_get_service;
klass->add_service = gbinder_hwservicemanager_add_service;
klass->check_name = gbinder_hwservicemanager_check_name;
klass->normalize_name = gbinder_hwservicemanager_normalize_name;
klass->watch = gbinder_hwservicemanager_watch;
klass->unwatch = gbinder_hwservicemanager_unwatch;
G_OBJECT_CLASS(klass)->finalize = gbinder_hwservicemanager_finalize;
klass->list = gbinder_servicemanager_hidl_list;
klass->get_service = gbinder_servicemanager_hidl_get_service;
klass->add_service = gbinder_servicemanager_hidl_add_service;
klass->check_name = gbinder_servicemanager_hidl_check_name;
klass->normalize_name = gbinder_servicemanager_hidl_normalize_name;
klass->watch = gbinder_servicemanager_hidl_watch;
klass->unwatch = gbinder_servicemanager_hidl_unwatch;
G_OBJECT_CLASS(klass)->finalize = gbinder_servicemanager_hidl_finalize;
}
/*

View File

@@ -64,7 +64,6 @@ typedef struct gbinder_servicemanager_class {
const char* iface;
const char* default_device;
const GBinderRpcProtocol* rpc_protocol;
/* Methods (synchronous) */
char** (*list)(GBinderServiceManager* self);
@@ -86,6 +85,9 @@ typedef struct gbinder_servicemanager_class {
GType gbinder_servicemanager_get_type(void) GBINDER_INTERNAL;
#define GBINDER_TYPE_SERVICEMANAGER (gbinder_servicemanager_get_type())
#define GBINDER_SERVICEMANAGER_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
GBinderServiceManager*
gbinder_servicemanager_new_with_type(
@@ -99,6 +101,19 @@ gbinder_servicemanager_service_registered(
const char* name)
GBINDER_INTERNAL;
/* Declared for unit tests */
void
gbinder_servicemanager_exit(
void)
GBINDER_INTERNAL
GBINDER_DESTRUCTOR;
/* Derived types */
GType gbinder_servicemanager_aidl_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_aidl2_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_hidl_get_type(void) GBINDER_INTERNAL;
#endif /* GBINDER_SERVICEMANAGER_PRIVATE_H */
/*

View File

@@ -48,6 +48,7 @@ typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
#define GBINDER_INLINE_FUNC static inline
#define GBINDER_INTERNAL G_GNUC_INTERNAL
#define GBINDER_DESTRUCTOR __attribute__((destructor))
#define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
#define GBINDER_PING_TRANSACTION GBINDER_TRANSACTION('P','N','G')

View File

@@ -5,6 +5,7 @@ all:
@$(MAKE) -C unit_buffer $*
@$(MAKE) -C unit_cleanup $*
@$(MAKE) -C unit_client $*
@$(MAKE) -C unit_config $*
@$(MAKE) -C unit_driver $*
@$(MAKE) -C unit_eventloop $*
@$(MAKE) -C unit_ipc $*
@@ -18,6 +19,7 @@ all:
@$(MAKE) -C unit_remote_reply $*
@$(MAKE) -C unit_remote_request $*
@$(MAKE) -C unit_servicemanager $*
@$(MAKE) -C unit_servicemanager_aidl $*
@$(MAKE) -C unit_servicename $*
@$(MAKE) -C unit_servicepoll $*
@$(MAKE) -C unit_writer $*

View File

@@ -44,7 +44,7 @@ COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS += -Wall
WARNINGS += -Wall -Wno-deprecated-declarations
INCLUDES += -I$(COMMON_DIR) -I$(LIB_DIR)/src -I$(LIB_DIR)/include
BASE_FLAGS = -fPIC
BASE_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS)

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* 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.
* 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
@@ -30,6 +30,8 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_binder.h"
#include "gbinder_local_object.h"
#include "gbinder_system.h"
#define GLOG_MODULE_NAME test_binder_log
@@ -47,19 +49,26 @@ static GHashTable* test_fd_map = NULL;
static GHashTable* test_node_map = NULL;
static GPrivate test_looper;
#define public_fd fd[0]
#define private_fd fd[1]
G_LOCK_DEFINE_STATIC(test_binder);
#define PUBLIC (0)
#define PRIVATE (1)
#define public_fd node[PUBLIC].fd
#define private_fd node[PRIVATE].fd
#define BINDER_VERSION _IOWR('b', 9, gint32)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, guint32)
#define B_TYPE_LARGE 0x85
#define BINDER_TYPE_BINDER GBINDER_FOURCC('s', 'b', '*', B_TYPE_LARGE)
#define BINDER_TYPE_HANDLE GBINDER_FOURCC('s', 'h', '*', B_TYPE_LARGE)
#define TF_ONE_WAY 0x01
#define TF_ROOT_OBJECT 0x04
#define TF_STATUS_CODE 0x08
#define TF_ACCEPT_FDS 0x10
typedef struct test_binder_io TestBinderIo;
typedef struct test_binder TestBinder;
typedef
void
@@ -77,23 +86,33 @@ typedef struct test_binder_submit_thread {
} TestBinderSubmitThread;
typedef struct test_binder_node {
int fd;
char* path;
int refcount;
const TestBinderIo* io;
GHashTable* destroy_map;
TestBinder* binder;
gboolean looper_enabled;
} TestBinderNode;
typedef struct test_binder {
typedef struct test_binder_fd {
int fd;
GHashTable* destroy_map;
TestBinderNode* node;
} TestBinderFd;
typedef struct test_binder {
gint refcount;
const TestBinderIo* io;
GHashTable* object_map; /* GBinderLocalObject* => handle */
GHashTable* handle_map; /* handle => GBinderLocalObject* */
TestBinderSubmitThread* submit_thread;
gboolean looper_enabled;
int fd[2];
GMutex mutex;
gboolean passthrough;
TestBinderNode node[2];
} TestBinder;
struct test_binder_io {
int version;
int write_read_request;
int (*handle_write_read)(TestBinder* binder, void* data);
int (*handle_write_read)(TestBinderFd* fd, void* data);
};
typedef struct binder_write_read_64 {
@@ -128,6 +147,13 @@ typedef struct binder_handle_cookie_64 {
guint64 cookie;
} __attribute__((packed)) BinderHandleCookie64;
typedef struct binder_object_64 {
guint32 type;
guint32 flags;
guint64 object;
guint64 cookie;
} BinderObject64;
#define BC_TRANSACTION_64 _IOW('c', 0, BinderTransactionData64)
#define BC_REPLY_64 _IOW('c', 1, BinderTransactionData64)
#define BC_FREE_BUFFER_64 _IOW('c', 3, guint64)
@@ -259,74 +285,202 @@ test_binder_submit_later(
static
void
test_io_free_buffer(
TestBinder* binder,
TestBinderFd* fd,
void* ptr)
{
if (ptr) {
TestBinderNode* node = binder->node;
GDestroyNotify destroy = g_hash_table_lookup(node->destroy_map, ptr);
GDestroyNotify destroy;
G_LOCK(test_binder);
destroy = g_hash_table_lookup(fd->destroy_map, ptr);
if (destroy) {
g_hash_table_remove(node->destroy_map, ptr);
g_hash_table_remove(fd->destroy_map, ptr);
destroy(ptr);
} else {
g_free(ptr);
}
G_UNLOCK(test_binder);
}
}
void
test_binder_exit_wait(
void)
{
struct timespec wait;
wait.tv_nsec = 100 * 1000000; /* 100 ms */
wait.tv_sec = 0;
G_LOCK(test_binder);
while (test_node_map) {
GDEBUG("Waiting for loopers to exit...");
G_UNLOCK(test_binder);
nanosleep(&wait, &wait);
G_LOCK(test_binder);
}
G_UNLOCK(test_binder);
}
static
guint64
test_io_passthough_fix_handle(
TestBinder* binder,
guint64 handle)
{
gpointer key = GSIZE_TO_POINTER(handle);
/* Invoked under lock */
if (g_hash_table_contains(binder->object_map, key)) {
gpointer value = g_hash_table_lookup(binder->object_map, key);
handle = GPOINTER_TO_SIZE(value);
GDEBUG("Object %p => handle %u", key, (guint) handle);
} else if (g_hash_table_contains(binder->handle_map, key)) {
gpointer obj = g_hash_table_lookup(binder->handle_map, key);
GDEBUG("Handle %u => object %p", (guint) handle, obj);
handle = GPOINTER_TO_SIZE(obj);
}
return handle;
}
static
gssize
test_io_passthough_write_64(
TestBinderFd* fd,
const void* bytes,
gsize bytes_to_write)
{
const guint code = *(guint32*)bytes;
TestBinderNode* node = fd->node;
TestBinder* binder = node->binder;
BinderTransactionData64* tx = NULL;
gssize bytes_written;
guint extra;
guint32* cmd;
void* data;
/* Just ignore some codes for now */
switch (code) {
case BC_ACQUIRE:
case BC_RELEASE:
case BC_REQUEST_DEATH_NOTIFICATION_64:
case BC_CLEAR_DEATH_NOTIFICATION_64:
return bytes_to_write;
default:
break;
}
cmd = g_memdup(bytes, bytes_to_write);
data = cmd + 1;
switch (*cmd) {
case BR_TRANSACTION_64:
*cmd = BC_TRANSACTION_64;
tx = data;
break;
case BC_TRANSACTION_64:
*cmd = BR_TRANSACTION_64;
tx = data;
break;
case BR_REPLY_64:
*cmd = BC_REPLY_64;
tx = data;
break;
case BC_REPLY_64:
extra = BR_TRANSACTION_COMPLETE;
write(fd->fd, &extra, sizeof(extra));
*cmd = BR_REPLY_64;
tx = data;
break;
}
if (tx) {
guint32* data_buffer = g_memdup(GSIZE_TO_POINTER(tx->data_buffer),
tx->data_size);
void* data_offsets = g_memdup(GSIZE_TO_POINTER(tx->data_offsets),
tx->offsets_size);
G_LOCK(test_binder);
tx->handle = test_io_passthough_fix_handle(binder, tx->handle);
if (data_buffer && tx->data_size > sizeof(BinderObject64)) {
/* Replace BINDER_TYPE_BINDER with BINDER_TYPE_HANDLE */
guint32* data_ptr = data_buffer;
const guint32* data_end = data_buffer + (tx->data_size -
sizeof(BinderObject64))/sizeof(guint32);
/*
* Objects are supposed to be aligned at 32-bit boundary, so we
* can scanning the data buffer with 4-byte step.
*/
for (data_ptr = data_buffer; data_ptr < data_end; data_ptr++) {
if (*data_ptr == BINDER_TYPE_BINDER) {
BinderObject64* object = (BinderObject64*) data_ptr;
object->type = BINDER_TYPE_HANDLE;
object->object = test_io_passthough_fix_handle(binder,
object->object);
data_ptr += sizeof(object)/sizeof(guint32) - 1;
}
}
}
g_hash_table_replace(fd->destroy_map, data_offsets, NULL);
G_UNLOCK(test_binder);
tx->data_buffer = GPOINTER_TO_SIZE(data_buffer);
tx->data_offsets = GPOINTER_TO_SIZE(data_offsets);
}
bytes_written = write(fd->fd, cmd, bytes_to_write);
g_free(cmd);
return bytes_written;
}
static
int
test_io_handle_write_read_64(
TestBinder* binder,
TestBinderFd* fd,
void* data)
{
TestBinderNode* node = fd->node;
TestBinder* binder = node->binder;
BinderWriteRead64* wr = data;
gssize bytes_left = wr->write_size - wr->write_consumed;
const guint8* write_ptr = (void*)(gsize)
(wr->write_buffer + wr->write_consumed);
const guint8* write_ptr = (void*)(gsize)(wr->write_buffer +
wr->write_consumed);
gboolean is_looper;
while (bytes_left >= sizeof(guint32)) {
const guint cmd = *(guint32*)write_ptr;
const guint cmdsize = _IOC_SIZE(cmd);
const void* cmddata = write_ptr + sizeof(guint32);
const gsize bytes_to_write = sizeof(guint32) + cmdsize;
GASSERT(bytes_left >= (sizeof(guint32) + cmdsize));
if (bytes_left >= (sizeof(guint32) + cmdsize)) {
wr->write_consumed += sizeof(guint32);
write_ptr += sizeof(guint32);
bytes_left -= sizeof(guint32);
GASSERT(bytes_left >= bytes_to_write);
if (bytes_left >= bytes_to_write) {
gssize bytes_written = bytes_to_write;
switch (cmd) {
case BC_TRANSACTION_64:
case BC_REPLY_64:
/* Is there anything special about transactions and replies? */
break;
case BC_FREE_BUFFER_64:
test_io_free_buffer(binder,
GSIZE_TO_POINTER(*(guint64*)write_ptr));
test_io_free_buffer(fd, GSIZE_TO_POINTER(*(guint64*)cmddata));
break;
case BC_ENTER_LOOPER:
g_private_set(&test_looper, GINT_TO_POINTER(TRUE));
break;
g_private_set(&test_looper, GINT_TO_POINTER(TRUE));
break;
case BC_EXIT_LOOPER:
g_private_set(&test_looper, NULL);
break;
case BC_REQUEST_DEATH_NOTIFICATION_64:
case BC_CLEAR_DEATH_NOTIFICATION_64:
case BC_INCREFS:
case BC_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS:
g_private_set(&test_looper, NULL);
break;
default:
#pragma message("TODO: implement more BINDER_WRITE_READ commands")
GDEBUG("Unhandled command 0x%08x", cmd);
if (binder->passthrough) {
bytes_written = test_io_passthough_write_64(fd,
write_ptr, bytes_to_write);
}
break;
}
wr->write_consumed += cmdsize;
write_ptr += cmdsize;
bytes_left -= cmdsize;
if (bytes_written >= 0) {
wr->write_consumed += bytes_written;
write_ptr += bytes_written;
bytes_left -= bytes_written;
} else {
GDEBUG("Write failed, %s", strerror(errno));
return -1;
}
} else {
/* Partial command in the buffer */
errno = EINVAL;
@@ -335,17 +489,17 @@ test_io_handle_write_read_64(
}
is_looper = g_private_get(&test_looper) ? TRUE : FALSE;
if (binder->looper_enabled || !is_looper) {
if (node->looper_enabled || !is_looper) {
/* Now read the data from the socket */
int bytes_available = 0;
int err = ioctl(binder->public_fd, FIONREAD, &bytes_available);
int err = ioctl(fd->fd, FIONREAD, &bytes_available);
if (err >= 0) {
int bytes_read = 0;
if (bytes_available >= 4) {
bytes_read = read(binder->public_fd,
(void*)(gsize)(wr->read_buffer + wr->read_consumed),
bytes_read = read(fd->fd, (void*)(gsize)
(wr->read_buffer + wr->read_consumed),
wr->read_size - wr->read_consumed);
} else {
struct timespec wait;
@@ -387,26 +541,26 @@ test_binder_ioctl_version(
TestBinder* binder,
int* version)
{
*version = binder->node->io->version;
*version = binder->io->version;
return 0;
}
static
void
test_binder_node_unref(
TestBinderNode* node)
TestBinderFd*
test_binder_fd_from_fd(
int fd)
{
node->refcount--;
if (!node->refcount) {
g_hash_table_remove(test_node_map, node->path);
g_hash_table_destroy(node->destroy_map);
g_free(node->path);
g_free(node);
}
if (!g_hash_table_size(test_node_map)) {
g_hash_table_unref(test_node_map);
test_node_map = NULL;
TestBinderFd* binder_fd = NULL;
G_LOCK(test_binder);
GASSERT(test_fd_map);
if (test_fd_map) {
binder_fd = g_hash_table_lookup(test_fd_map, GINT_TO_POINTER(fd));
GASSERT(binder_fd);
}
G_UNLOCK(test_binder);
return binder_fd;
}
static
@@ -414,13 +568,9 @@ TestBinder*
test_binder_from_fd(
int fd)
{
TestBinder* binder = NULL;
GASSERT(test_fd_map);
if (test_fd_map) {
binder = g_hash_table_lookup(test_fd_map, GINT_TO_POINTER(fd));
GASSERT(binder);
}
return binder;
TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
return binder_fd ? binder_fd->node->binder : NULL;
}
static
@@ -435,11 +585,22 @@ void
test_binder_set_looper_enabled(
int fd,
gboolean enabled)
{
TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
g_assert(binder_fd);
binder_fd->node->looper_enabled = enabled;
}
void
test_binder_set_passthrough(
int fd,
gboolean passthrough)
{
TestBinder* binder = test_binder_from_fd(fd);
g_assert(binder);
binder->looper_enabled = enabled;
binder->passthrough = passthrough;
}
void
@@ -448,13 +609,13 @@ test_binder_set_destroy(
gpointer ptr,
GDestroyNotify destroy)
{
TestBinder* binder = test_binder_from_fd(fd);
TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
if (binder) {
TestBinderNode* node = binder->node;
g_hash_table_replace(node->destroy_map, ptr,
if (binder_fd) {
G_LOCK(test_binder);
g_hash_table_replace(binder_fd->destroy_map, ptr,
destroy ? destroy : test_io_destroy_none);
G_UNLOCK(test_binder);
}
}
@@ -704,44 +865,219 @@ test_binder_br_reply_status_later(
test_binder_br_reply_status1(fd, status, test_binder_push_data_later);
}
static
void
test_binder_node_clear(
TestBinderNode* node)
{
GDEBUG("Done with %s", node->path);
g_hash_table_remove(test_node_map, node->path);
if (!g_hash_table_size(test_node_map)) {
g_hash_table_unref(test_node_map);
test_node_map = NULL;
}
close(node->fd);
g_free(node->path);
}
static
TestBinder*
test_binder_ref(
TestBinder* binder)
{
if (binder) {
g_atomic_int_inc(&binder->refcount);
}
return binder;
}
static
void
test_binder_unregister_objects_internal(
TestBinder* binder,
gboolean need_lock)
{
GSList* objects = NULL;
GHashTableIter it;
gpointer value;
if (need_lock) {
G_LOCK(test_binder);
}
g_assert(binder);
g_hash_table_iter_init(&it, binder->handle_map);
while (g_hash_table_iter_next(&it, NULL, &value)) {
objects = g_slist_append(objects, value);
}
g_hash_table_remove_all(binder->object_map);
g_hash_table_remove_all(binder->handle_map);
if (need_lock) {
G_UNLOCK(test_binder);
}
/* Unref GBinderLocalObjects outside the lock */
g_slist_free_full(objects, (GDestroyNotify) gbinder_local_object_unref);
}
static
void
test_binder_unref_internal(
TestBinder* binder,
gboolean need_lock)
{
if (binder && g_atomic_int_dec_and_test(&binder->refcount)) {
if (need_lock) {
G_LOCK(test_binder);
}
test_binder_node_clear(binder->node + 0);
test_binder_node_clear(binder->node + 1);
if (need_lock) {
G_UNLOCK(test_binder);
}
test_binder_submit_thread_free(binder->submit_thread);
test_binder_unregister_objects_internal(binder, need_lock);
g_hash_table_destroy(binder->object_map);
g_hash_table_destroy(binder->handle_map);
g_mutex_clear(&binder->mutex);
g_free(binder);
}
}
guint
test_binder_register_object(
int fd,
GBinderLocalObject* obj,
guint h)
{
TestBinder* binder = test_binder_from_fd(fd);
g_assert(binder);
g_assert(obj);
G_LOCK(test_binder);
g_assert(!g_hash_table_contains(binder->object_map, obj));
g_assert(!g_hash_table_contains(binder->handle_map, GINT_TO_POINTER(h)));
if (h == AUTO_HANDLE) {
h = 1;
while (g_hash_table_contains(binder->handle_map, GINT_TO_POINTER(h)) ||
g_hash_table_contains(binder->object_map, GINT_TO_POINTER(h))) {
h++;
}
}
GDEBUG("Object %p <=> handle %u", obj, h);
g_hash_table_insert(binder->handle_map, GINT_TO_POINTER(h), obj);
g_hash_table_insert(binder->object_map, obj, GINT_TO_POINTER(h));
G_UNLOCK(test_binder);
gbinder_local_object_ref(obj);
return h;
}
void
test_binder_unregister_objects(
int fd)
{
test_binder_unregister_objects_internal(test_binder_from_fd(fd), TRUE);
}
static
void
test_fd_map_free(
gpointer entry)
{
TestBinderFd* binder_fd = entry;
GHashTableIter it;
gpointer key, value;
g_hash_table_iter_init(&it, binder_fd->destroy_map);
while (g_hash_table_iter_next(&it, &key, &value)) {
if (value) {
((GDestroyNotify)value)(key);
} else {
g_free(key);
}
}
g_hash_table_destroy(binder_fd->destroy_map);
test_binder_unref_internal(binder_fd->node->binder, FALSE);
close(binder_fd->fd);
g_free(binder_fd);
}
static
TestBinderFd*
test_binder_fd_new(
TestBinderNode* node)
{
TestBinderFd* binder_fd = g_new0(TestBinderFd, 1);
test_binder_ref(node->binder);
binder_fd->node = node;
binder_fd->fd = dup(node->fd);
binder_fd->destroy_map = g_hash_table_new(g_direct_hash, g_direct_equal);
return binder_fd;
}
int
gbinder_system_open(
const char* path,
int flags)
{
if (path && g_str_has_prefix(path, "/dev") &&
g_str_has_suffix(path, "binder")) {
TestBinderNode* node = NULL;
TestBinder* binder = NULL;
int fd;
static const char binder_suffix[] = "binder";
static const char binder_private_suffix[] = "binder-private";
static const char private_suffix[] = "-private";
if (path && g_str_has_prefix(path, "/dev/") &&
(g_str_has_suffix(path, binder_suffix) ||
g_str_has_suffix(path, binder_private_suffix))) {
TestBinderFd* fd;
TestBinderNode* node;
G_LOCK(test_binder);
node = test_node_map ? g_hash_table_lookup(test_node_map, path) : NULL;
if (!node) {
int i, fds[2];
TestBinder* binder = g_new0(TestBinder, 1);
binder->io = &test_io_64;
g_mutex_init(&binder->mutex);
g_assert(!socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
if (g_str_has_suffix(path, binder_suffix)) {
node = binder->node + PUBLIC;
node->path = g_strdup(path);
binder->node[PRIVATE].path = g_strconcat(path,
private_suffix, NULL);
} else {
node = binder->node + PRIVATE;
node->path = g_strdup(path);
binder->node[PUBLIC].path = g_strndup(path,
strlen(path) - strlen(private_suffix) - 1);
}
if (test_node_map) {
node = g_hash_table_lookup(test_node_map, path);
}
if (node) {
node->refcount++;
} else {
node = g_new0(TestBinderNode, 1);
node->path = g_strdup(path);
node->refcount = 1;
node->io = &test_io_64;
node->destroy_map = g_hash_table_new(g_direct_hash, g_direct_equal);
if (!test_node_map) {
test_node_map = g_hash_table_new(g_str_hash, g_str_equal);
}
g_hash_table_replace(test_node_map, node->path, node);
for (i = 0; i < 2; i++) {
binder->node[i].binder = binder;
binder->node[i].fd = fds[i];
g_hash_table_replace(test_node_map, binder->node[i].path,
binder->node + i);
}
binder->object_map = g_hash_table_new
(g_direct_hash, g_direct_equal);
binder->handle_map = g_hash_table_new
(g_direct_hash, g_direct_equal);
GDEBUG("Created %s <=> %s binder", binder->node[0].path,
binder->node[1].path);
}
binder = g_new0(TestBinder, 1);
binder->node = node;
socketpair(AF_UNIX, SOCK_STREAM, 0, binder->fd);
fd = binder->public_fd;
fd = test_binder_fd_new(node);
if (!test_fd_map) {
test_fd_map = g_hash_table_new(g_direct_hash, g_direct_equal);
test_fd_map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, test_fd_map_free);
}
g_hash_table_replace(test_fd_map, GINT_TO_POINTER(fd), binder);
return fd;
g_hash_table_replace(test_fd_map, GINT_TO_POINTER(fd->fd), fd);
G_UNLOCK(test_binder);
return fd->fd;
} else {
errno = ENOENT;
return -1;
@@ -752,23 +1088,22 @@ int
gbinder_system_close(
int fd)
{
TestBinder* binder = test_binder_from_fd(fd);
int ret;
if (binder) {
g_hash_table_remove(test_fd_map, GINT_TO_POINTER(fd));
G_LOCK(test_binder);
if (g_hash_table_remove(test_fd_map, GINT_TO_POINTER(fd))) {
if (!g_hash_table_size(test_fd_map)) {
g_hash_table_unref(test_fd_map);
test_fd_map = NULL;
}
test_binder_submit_thread_free(binder->submit_thread);
test_binder_node_unref(binder->node);
close(binder->public_fd);
close(binder->private_fd);
g_free(binder);
return 0;
ret = 0;
} else {
errno = EBADF;
ret = -1;
}
errno = EBADF;
return -1;
G_UNLOCK(test_binder);
return ret;
}
int
@@ -777,9 +1112,11 @@ gbinder_system_ioctl(
int request,
void* data)
{
TestBinder* binder = test_binder_from_fd(fd);
if (binder) {
const TestBinderIo* io = binder->node->io;
TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
if (binder_fd) {
TestBinder* binder = binder_fd->node->binder;
const TestBinderIo* io = binder->io;
switch (request) {
case BINDER_VERSION:
@@ -788,7 +1125,7 @@ gbinder_system_ioctl(
return 0;
default:
if (request == io->write_read_request) {
return io->handle_write_read(binder, data);
return io->handle_write_read(binder_fd, data);
} else {
errno = EINVAL;
return -1;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* 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.
* 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
@@ -35,6 +35,8 @@
#include "test_common.h"
typedef struct test_binder TestBinder;
void
test_binder_br_noop(
int fd);
@@ -116,12 +118,33 @@ test_binder_set_looper_enabled(
int fd,
gboolean enabled);
void
test_binder_set_passthrough(
int fd,
gboolean passthrough);
guint
test_binder_register_object(
int fd,
GBinderLocalObject* obj,
guint handle);
#define AUTO_HANDLE ((guint)-1)
void
test_binder_unregister_objects(
int fd);
void
test_binder_set_destroy(
int fd,
gpointer ptr,
GDestroyNotify destroy);
void
test_binder_exit_wait(
void);
#endif /* TEST_BINDER_H */
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 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,12 @@ void
test_quit_later(
GMainLoop* loop);
/* Quits the event loop after n iterations */
void
test_quit_later_n(
GMainLoop* loop,
guint n);
#define TEST_TIMEOUT_SEC (20)
/* Helper macros */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 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
@@ -34,6 +34,11 @@
#include <gutil_log.h>
typedef struct test_quit_later_data{
GMainLoop* loop;
guint n;
} TestQuitLaterData;
static
gboolean
test_timeout_expired(
@@ -43,6 +48,46 @@ test_timeout_expired(
return G_SOURCE_REMOVE;
}
static
void
test_quit_later_n_free(
gpointer user_data)
{
TestQuitLaterData* data = user_data;
g_main_loop_unref(data->loop);
g_free(data);
}
static
gboolean
test_quit_later_n_func(
gpointer user_data)
{
TestQuitLaterData* data = user_data;
if (data->n > 0) {
data->n--;
return G_SOURCE_CONTINUE;
} else {
g_main_loop_quit(data->loop);
return G_SOURCE_REMOVE;
}
}
void
test_quit_later_n(
GMainLoop* loop,
guint n)
{
TestQuitLaterData* data = g_new0(TestQuitLaterData, 1);
data->loop = g_main_loop_ref(loop);
data->n = n;
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, test_quit_later_n_func, data,
test_quit_later_n_free);
}
static
gboolean
test_quit_later_cb(

View File

@@ -1,3 +1,4 @@
#!/bin/bash
#
# This script requires lcov, dirname
@@ -7,6 +8,7 @@ TESTS="\
unit_buffer \
unit_cleanup \
unit_client \
unit_config \
unit_driver \
unit_eventloop \
unit_ipc \
@@ -20,6 +22,7 @@ unit_remote_object \
unit_remote_reply \
unit_remote_request \
unit_servicemanager \
unit_servicemanager_aidl \
unit_servicename \
unit_servicepoll \
unit_writer"

View File

@@ -54,7 +54,7 @@ test_client_new(
guint handle,
const char* iface)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, handle);
GBinderClient* client = gbinder_client_new(obj, iface);
@@ -97,7 +97,7 @@ void
test_basic(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0);
const char* iface = "foo";
@@ -123,7 +123,7 @@ void
test_interfaces(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0);
static const GBinderClientIfaceInfo ifaces[] = {

View File

@@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_config
include ../common/Makefile

View File

@@ -0,0 +1,505 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 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_common.h"
#include "gbinder_config.h"
#include <gutil_strv.h>
#include <gutil_log.h>
#include <sys/stat.h>
#include <sys/types.h>
static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-config-XXXXXX";
static
const char*
test_value(
GKeyFile* keyfile,
const char* group,
const char* key,
GString* buf)
{
char* value = g_key_file_get_value(keyfile, group, key, NULL);
g_string_set_size(buf, 0);
if (value) {
g_string_append(buf, value);
g_free(value);
return buf->str;
} else {
return NULL;
}
}
static
gboolean
test_keyfiles_equal(
GKeyFile* keyfile1,
GKeyFile* keyfile2)
{
gboolean equal = FALSE;
gsize ngroups;
char** groups = g_key_file_get_groups(keyfile1, &ngroups);
char** groups2 = g_key_file_get_groups(keyfile2, NULL);
gutil_strv_sort(groups, TRUE);
gutil_strv_sort(groups2, TRUE);
if (gutil_strv_equal(groups, groups2)) {
gsize i;
equal = TRUE;
for (i = 0; i < ngroups && equal; i++) {
const char* group = groups[i];
gsize nkeys;
char** keys = g_key_file_get_keys(keyfile1, group, &nkeys, NULL);
char** keys2 = g_key_file_get_keys(keyfile2, group, &nkeys, NULL);
equal = FALSE;
gutil_strv_sort(keys, TRUE);
gutil_strv_sort(keys2, TRUE);
if (gutil_strv_equal(keys, keys2)) {
gsize k;
equal = TRUE;
for (k = 0; k < nkeys && equal; k++) {
const char* key = keys[k];
char* v1 = g_key_file_get_value(keyfile1, group, key, NULL);
char* v2 = g_key_file_get_value(keyfile2, group, key, NULL);
if (g_strcmp0(v1, v2)) {
equal = FALSE;
GDEBUG("Values for %s/%s don't match ('%s' vs '%s')",
group, key, v1, v2);
}
g_free(v1);
g_free(v2);
}
} else {
GDEBUG("Keys for %s don't match", group);
}
g_strfreev(keys);
g_strfreev(keys2);
}
} else {
GDEBUG("Groups don't match");
}
g_strfreev(groups);
g_strfreev(groups2);
if (!equal) {
char* data1 = g_key_file_to_data(keyfile1, NULL, NULL);
char* data2 = g_key_file_to_data(keyfile2, NULL, NULL);
GDEBUG("This:");
GDEBUG("%s", data1);
GDEBUG("Doesn't match this:");
GDEBUG("%s", data2);
g_free(data1);
g_free(data2);
}
return equal;
}
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
const char* default_name = gbinder_config_file;
/* Reset the state */
gbinder_config_exit();
gbinder_config_file = NULL;
gbinder_config_dir = NULL;
g_assert(!gbinder_config_get());
/* Reset the state again */
gbinder_config_file = default_name;
}
/*==========================================================================*
* non_exist
*==========================================================================*/
static
void
test_non_exit(
void)
{
const char* default_name = gbinder_config_file;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
/* Reset the state */
gbinder_config_exit();
gbinder_config_file = file;
g_assert(!gbinder_config_get());
/* Reset the state again */
gbinder_config_file = default_name;
g_free(file);
remove(dir);
g_free(dir);
}
/*==========================================================================*
* bad_config
*==========================================================================*/
static
void
test_bad_config(
void)
{
const char* default_name = gbinder_config_file;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
static const char garbage[] = "foo";
/* Reset the state */
gbinder_config_exit();
/* Try to load the garbage */
g_assert(g_file_set_contents(file, garbage, -1, NULL));
gbinder_config_file = file;
g_assert(!gbinder_config_get());
/* Reset the state again */
gbinder_config_file = default_name;
remove(file);
g_free(file);
remove(dir);
g_free(dir);
}
/*==========================================================================*
* dirs
*==========================================================================*/
static
void
test_dirs(
void)
{
GKeyFile* k;
GString* b = g_string_new(NULL);
const char* default_file = gbinder_config_file;
const char* default_dir = gbinder_config_dir;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* subdir = g_build_filename(dir, "d", NULL);
char* notafile = g_build_filename(subdir, "dir.conf", NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
char* file1 = g_build_filename(subdir, "a.conf", NULL);
char* file2 = g_build_filename(subdir, "b.conf", NULL);
char* random_file = g_build_filename(subdir, "foo", NULL);
static const char garbage[] = "foo";
static const char config[] =
"[Protocol]\n"
"/dev/binder = aidl\n"
"/dev/hbinder = hidl\n";
static const char config1[] =
"[Protocol]\n"
"/dev/hwbinder = hidl\n"
"[ServiceManager]\n"
"/dev/binder = aidl\n";
static const char config2[] =
"[Protocol]\n"
"/dev/binder = aidl2\n"
"[ServiceManager]\n"
"/dev/binder = aidl2\n";
g_assert_cmpint(mkdir(subdir, 0700), == ,0);
g_assert_cmpint(mkdir(notafile, 0700), == ,0);
g_assert(g_file_set_contents(file, config, -1, NULL));
g_assert(g_file_set_contents(file1, config1, -1, NULL));
g_assert(g_file_set_contents(file2, config2, -1, NULL));
g_assert(g_file_set_contents(random_file, garbage, -1, NULL));
/* Reset the state */
gbinder_config_exit();
gbinder_config_file = file;
gbinder_config_dir = subdir;
/* Load the config */
k = gbinder_config_get();
g_assert(k);
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"Protocol","/dev/hbinder",b), == ,"hidl");
g_assert_cmpstr(test_value(k,"Protocol","/dev/hwbinder",b), == ,"hidl");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
/* Remove the default file and try again */
gbinder_config_exit();
g_assert_cmpint(remove(file), == ,0);
k = gbinder_config_get();
g_assert(k);
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"Protocol","/dev/hwbinder",b), == ,"hidl");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
/* Damage one of the files and try again */
gbinder_config_exit();
g_assert(g_file_set_contents(file1, garbage, -1, NULL));
k = gbinder_config_get();
g_assert(k);
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert(!test_value(k,"Protocol","/dev/hwbinder",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
/* Disallow access to one of the files and try again */
gbinder_config_exit();
g_assert_cmpint(chmod(file1, 0), == ,0);
k = gbinder_config_get();
g_assert(k);
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert(!test_value(k,"Protocol","/dev/hwbinder",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
/* Delete the remaining files and try again */
gbinder_config_exit();
g_assert_cmpint(remove(file1), == ,0);
g_assert_cmpint(remove(file2), == ,0);
g_assert(!gbinder_config_get());
/* Undo all the damage */
gbinder_config_exit();
gbinder_config_file = default_file;
gbinder_config_dir = default_dir;
remove(random_file);
g_free(file);
g_free(file1);
g_free(file2);
g_free(random_file);
remove(notafile);
remove(subdir);
remove(dir);
g_free(notafile);
g_free(subdir);
g_free(dir);
g_string_free(b, TRUE);
}
/*==========================================================================*
* autorelease
*==========================================================================*/
static
void
test_autorelease(
void)
{
const char* default_file = gbinder_config_file;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GKeyFile* keyfile;
static const char config[] = "[Protocol]";
gbinder_config_exit(); /* Reset the state */
/* Load the file */
g_assert(g_file_set_contents(file, config, -1, NULL));
gbinder_config_file = file;
keyfile = gbinder_config_get();
g_assert(keyfile);
/* Second call returns the same pointer */
g_assert(keyfile == gbinder_config_get());
test_quit_later_n(loop, 2);
test_run(&test_opt, loop);
g_main_loop_unref(loop);
/* Reset the state again */
gbinder_config_exit();
gbinder_config_file = default_file;
remove(file);
g_free(file);
remove(dir);
g_free(dir);
}
/*==========================================================================*
* Presets
*==========================================================================*/
typedef struct test_presets_data {
const char* name;
const char* in;
const char* out;
} TestPresetsData;
static
void
test_presets(
gconstpointer test_data)
{
const TestPresetsData* test = test_data;
const char* default_file = gbinder_config_file;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
GKeyFile* expected = g_key_file_new();
GKeyFile* keyfile;
/* Reset the state */
gbinder_config_exit();
/* Load the file */
if (test->in) {
g_assert(g_file_set_contents(file, test->in, -1, NULL));
gbinder_config_file = file;
} else {
gbinder_config_file = NULL;
}
keyfile = gbinder_config_get();
g_assert(keyfile);
/* Compare it against the expected value */
g_assert(g_key_file_load_from_data(expected, test->out, (gsize)-1,
G_KEY_FILE_NONE, NULL));
g_assert(test_keyfiles_equal(keyfile, expected));
/* Reset the state again */
gbinder_config_exit();
gbinder_config_file = default_file;
remove(file);
g_free(file);
remove(dir);
g_free(dir);
g_key_file_unref(expected);
}
static const TestPresetsData test_presets_data [] = {
{
"override",
"[General]\n"
"ApiLevel = 28\n"
"[ServiceManager]\n"
"/dev/vndbinder = aidl\n",
"[General]\n"
"ApiLevel = 28\n"
"[ServiceManager]\n"
"/dev/binder = aidl2\n"
"/dev/vndbinder = aidl\n" /* Preset is overridden */
},{
"too_small",
"[General]\n"
"ApiLevel = 27\n",
"[General]\n"
"ApiLevel = 27\n"
},{
"28",
"[General]\n"
"ApiLevel = 28",
"[General]\n"
"ApiLevel = 28\n"
"[ServiceManager]\n"
"/dev/binder = aidl2\n"
"/dev/vndbinder = aidl2\n"
},{
"29",
"[General]\n"
"ApiLevel = 29",
"[General]\n"
"ApiLevel = 29\n"
"[Protocol]\n"
"/dev/binder = aidl2\n"
"/dev/vndbinder = aidl2\n"
"[ServiceManager]\n"
"/dev/binder = aidl2\n"
"/dev/vndbinder = aidl2\n"
}
};
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/config/"
#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_("null"), test_null);
g_test_add_func(TEST_("non_exist"), test_non_exit);
g_test_add_func(TEST_("dirs"), test_dirs);
g_test_add_func(TEST_("bad_config"), test_bad_config);
g_test_add_func(TEST_("autorelease"), test_autorelease);
for (i = 0; i < G_N_ELEMENTS(test_presets_data); i++) {
const TestPresetsData* test = test_presets_data + i;
char* path;
path = g_strconcat(TEST_("presets/"), test->name, NULL);
g_test_add_data_func(path, test, test_presets);
g_free(path);
}
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -109,8 +109,8 @@ void
test_basic(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
g_assert(ipc);
g_assert(ipc2);
@@ -119,16 +119,17 @@ test_basic(
gbinder_ipc_unref(ipc2);
/* Second gbinder_ipc_new returns the same (default) object */
g_assert(gbinder_ipc_new(NULL, NULL) == ipc);
g_assert(gbinder_ipc_new("", NULL) == ipc);
g_assert(gbinder_ipc_new(NULL) == ipc);
g_assert(gbinder_ipc_new("") == ipc);
gbinder_ipc_unref(ipc);
gbinder_ipc_unref(ipc);
gbinder_ipc_unref(ipc);
/* Invalid path */
g_assert(!gbinder_ipc_new("invalid path", NULL));
g_assert(!gbinder_ipc_new("invalid path"));
gbinder_ipc_exit();
test_binder_exit_wait();
}
/*==========================================================================*
@@ -153,7 +154,7 @@ void
test_async_oneway(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
@@ -180,7 +181,7 @@ void
test_sync_oneway(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
@@ -191,6 +192,7 @@ test_sync_oneway(
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
}
/*==========================================================================*
@@ -202,7 +204,7 @@ void
test_sync_reply_ok_status(
int* status)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
@@ -235,6 +237,7 @@ test_sync_reply_ok_status(
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
}
static
@@ -258,7 +261,7 @@ void
test_sync_reply_error(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
@@ -278,6 +281,7 @@ test_sync_reply_error(
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
}
/*==========================================================================*
@@ -316,7 +320,7 @@ void
test_transact_ok(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
@@ -348,6 +352,7 @@ test_transact_ok(
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -374,7 +379,7 @@ void
test_transact_dead(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
@@ -395,6 +400,7 @@ test_transact_dead(
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -421,7 +427,7 @@ void
test_transact_failed(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
@@ -442,6 +448,7 @@ test_transact_failed(
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -470,7 +477,7 @@ void
test_transact_status(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
@@ -491,6 +498,7 @@ test_transact_status(
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -512,7 +520,7 @@ void
test_transact_custom(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id = gbinder_ipc_transact_custom(ipc, NULL,
test_transact_custom_done, NULL, loop);
@@ -523,6 +531,7 @@ test_transact_custom(
gbinder_ipc_exit();
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
test_binder_exit_wait();
}
/*==========================================================================*
@@ -543,7 +552,7 @@ void
test_transact_custom2(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id = gbinder_ipc_transact_custom(ipc, NULL, NULL,
test_transact_custom_destroy, loop);
@@ -554,6 +563,7 @@ test_transact_custom2(
gbinder_ipc_exit();
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
test_binder_exit_wait();
}
/*==========================================================================*
@@ -575,7 +585,7 @@ void
test_transact_custom3(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
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,
@@ -586,6 +596,7 @@ test_transact_custom3(
/* Reference to GBinderIpc is released by test_transact_custom3_exec */
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -624,7 +635,7 @@ void
test_transact_cancel(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
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);
@@ -635,6 +646,7 @@ test_transact_cancel(
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -669,7 +681,7 @@ void
test_transact_cancel2(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
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,
@@ -680,6 +692,7 @@ test_transact_cancel2(
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -718,7 +731,7 @@ void
test_transact_2way(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
const char* dev = gbinder_driver_dev(ipc->driver);
@@ -769,6 +782,7 @@ test_transact_2way(
gbinder_ipc_exit();
g_main_loop_unref(loop);
test_binder_exit_wait();
}
/*==========================================================================*
@@ -803,7 +817,7 @@ void
test_transact_incoming(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
const char* dev = gbinder_driver_dev(ipc->driver);
@@ -840,6 +854,7 @@ test_transact_incoming(
test_run(&test_opt, loop);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -873,7 +888,7 @@ void
test_transact_status_reply(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
const char* dev = gbinder_driver_dev(ipc->driver);
@@ -904,6 +919,7 @@ test_transact_status_reply(
test_run(&test_opt, loop);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -980,7 +996,7 @@ void
test_transact_async(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
const char* dev = gbinder_driver_dev(ipc->driver);
@@ -1011,6 +1027,7 @@ test_transact_async(
test_run(&test_opt, loop);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -1053,7 +1070,7 @@ void
test_transact_async_sync(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
const char* dev = gbinder_driver_dev(ipc->driver);
@@ -1084,6 +1101,7 @@ test_transact_async_sync(
test_run(&test_opt, loop);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -1107,7 +1125,7 @@ void
test_drop_remote_refs(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -1126,6 +1144,7 @@ test_drop_remote_refs(
/* gbinder_ipc_exit will drop the remote reference */
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}
@@ -1149,7 +1168,7 @@ void
test_cancel_on_exit(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -1163,6 +1182,7 @@ test_cancel_on_exit(
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait();
g_main_loop_unref(loop);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* 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.
* 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
@@ -152,7 +152,7 @@ test_basic(
{
const char* const ifaces_foo[] = { "foo", NULL };
const char* const ifaces_bar[] = { "bar", NULL };
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderLocalObject* foo;
GBinderLocalObject* bar;
@@ -201,7 +201,7 @@ test_ping(
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);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -247,7 +247,7 @@ test_interface(
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);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -296,7 +296,7 @@ test_hidl_ping(
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);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -346,7 +346,7 @@ test_get_descriptor(
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);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -402,7 +402,7 @@ test_descriptor_chain(
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);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -476,7 +476,7 @@ test_custom_iface(
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);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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,
@@ -583,7 +583,7 @@ test_reply_status(
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);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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,
@@ -624,7 +624,7 @@ void
test_increfs(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -666,7 +666,7 @@ void
test_decrefs(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -708,7 +708,7 @@ void
test_acquire(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -750,7 +750,7 @@ void
test_release(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
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);

View File

@@ -399,7 +399,7 @@ test_local_object(
GBinderLocalReply* reply;
GBinderOutputData* data;
GUtilIntArray* offsets;
GBinderIpc* ipc = gbinder_ipc_new(NULL, NULL);
GBinderIpc* ipc = gbinder_ipc_new(NULL);
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* 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.
* 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
@@ -33,6 +33,7 @@
#include "test_common.h"
#include "gbinder_buffer_p.h"
#include "gbinder_config.h"
#include "gbinder_driver.h"
#include "gbinder_io.h"
#include "gbinder_local_request_p.h"
@@ -43,36 +44,118 @@
#include "gbinder_writer.h"
static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-protocol-XXXXXX";
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
#define UNSET_WORK_SOURCE (-1)
typedef struct test_data {
const char* name;
const char* prot;
const char* dev;
} TestData;
typedef struct test_header_data {
const char* name;
const char* prot;
const char* dev;
const char* iface;
const guint8* header;
guint header_size;
} TestHeaderData;
static const guint8 test_header_binder [] = {
static const guint8 test_header_aidl [] = {
TEST_INT32_BYTES(BINDER_RPC_FLAGS),
TEST_INT32_BYTES(3),
TEST_INT16_BYTES('f'), TEST_INT16_BYTES('o'),
TEST_INT16_BYTES('o'), 0x00, 0x00
};
static const guint8 test_header_hwbinder [] = {
static const guint8 test_header_aidl2 [] = {
TEST_INT32_BYTES(BINDER_RPC_FLAGS),
TEST_INT32_BYTES(UNSET_WORK_SOURCE),
TEST_INT32_BYTES(3),
TEST_INT16_BYTES('f'), TEST_INT16_BYTES('o'),
TEST_INT16_BYTES('o'), 0x00, 0x00
};
static const guint8 test_header_hidl [] = {
'f', 'o', 'o', 0x00
};
static const TestHeaderData test_header_tests[] = {
{ "binder", GBINDER_DEFAULT_BINDER, "foo",
TEST_ARRAY_AND_SIZE(test_header_binder) },
{ "hwbinder", GBINDER_DEFAULT_HWBINDER, "foo",
TEST_ARRAY_AND_SIZE(test_header_hwbinder) }
{ "aidl/ok", "aidl", GBINDER_DEFAULT_BINDER, "foo",
TEST_ARRAY_AND_SIZE(test_header_aidl) },
{ "aidl/short", "aidl", GBINDER_DEFAULT_BINDER, NULL,
test_header_aidl, 8 }, /* Short packet */
{ "aidl2/ok", "aidl2", GBINDER_DEFAULT_BINDER, "foo",
TEST_ARRAY_AND_SIZE(test_header_aidl2) },
{ "aidl2/short/1", "aidl2", GBINDER_DEFAULT_BINDER, NULL,
test_header_aidl2, 1 }, /* Short packet */
{ "aidl2/short/2", "aidl2", GBINDER_DEFAULT_BINDER, NULL,
test_header_aidl2, 5 }, /* Short packet */
{ "aidl2/short/3", "adl2", GBINDER_DEFAULT_BINDER, NULL,
test_header_aidl2, 9 }, /* Short packet */
{ "hidl/ok", "hidl", GBINDER_DEFAULT_HWBINDER, "foo",
TEST_ARRAY_AND_SIZE(test_header_hidl) },
{ "hidl/short", "hidl", GBINDER_DEFAULT_HWBINDER, NULL,
test_header_hidl, 1 }
};
typedef struct test_config {
char* dir;
char* file;
} TestConfig;
static
void
test_config_init(
TestConfig* test,
const char* config)
{
test->dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
test->file = g_build_filename(test->dir, "test.conf", NULL);
/* Reset the state */
gbinder_rpc_protocol_exit();
gbinder_config_exit();
/* Write the config */
g_assert(g_file_set_contents(test->file, config, -1, NULL));
gbinder_config_file = test->file;
}
static
void
test_config_init2(
TestConfig* test,
const char* dev,
const char* prot)
{
char* config = g_strconcat("[Protocol]\n", dev, " = ", prot, "\n", NULL);
test_config_init(test, config);
g_free(config);
}
static
void
test_config_cleanup(
TestConfig* test)
{
/* Undo the damage */
gbinder_rpc_protocol_exit();
gbinder_config_exit();
gbinder_config_file = NULL;
remove(test->file);
g_free(test->file);
remove(test->dir);
g_free(test->dir);
}
/*==========================================================================*
* device
*==========================================================================*/
@@ -82,12 +165,129 @@ void
test_device(
void)
{
g_assert(gbinder_rpc_protocol_for_device(NULL) ==
&gbinder_rpc_protocol_binder);
g_assert(gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER) ==
&gbinder_rpc_protocol_binder);
g_assert(gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_HWBINDER) ==
&gbinder_rpc_protocol_hwbinder);
const GBinderRpcProtocol* p;
p = gbinder_rpc_protocol_for_device(NULL);
g_assert(p);
g_assert_cmpstr(p->name, == ,"aidl");
p = gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER);
g_assert(p);
g_assert_cmpstr(p->name, == ,"aidl");
p = gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_HWBINDER);
g_assert(p);
g_assert_cmpstr(p->name, == ,"hidl");
}
/*==========================================================================*
* config1
*==========================================================================*/
static
void
test_config1(
void)
{
const GBinderRpcProtocol* p;
TestConfig config;
test_config_init(&config,
"[Protocol]\n"
"/dev/binder = hidl\n" /* Redefined name for /dev/binder */
"/dev/hwbinder = foo\n"); /* Invalid protocol name */
p = gbinder_rpc_protocol_for_device(NULL);
g_assert(p);
g_assert_cmpstr(p->name, == ,"aidl");
p = gbinder_rpc_protocol_for_device("/dev/hwbinder");
g_assert(p);
g_assert_cmpstr(p->name, == ,"hidl");
p = gbinder_rpc_protocol_for_device("/dev/binder");
g_assert(p);
g_assert_cmpstr(p->name, == ,"hidl"); /* Redefined by config */
p = gbinder_rpc_protocol_for_device("/dev/someotherbinder");
g_assert(p);
g_assert_cmpstr(p->name, == ,"aidl");
test_config_cleanup(&config);
}
/*==========================================================================*
* config2
*==========================================================================*/
static
void
test_config2(
void)
{
const GBinderRpcProtocol* p;
TestConfig config;
test_config_init(&config,
"[Protocol]\n"
"Default = hidl\n"
"/dev/vndbinder = hidl\n"
"/dev/hwbinder = foo\n"); /* Invalid protocol name */
p = gbinder_rpc_protocol_for_device(NULL);
g_assert(p);
g_assert_cmpstr(p->name, == ,"aidl");
p = gbinder_rpc_protocol_for_device("/dev/vndbinder");
g_assert(p);
g_assert_cmpstr(p->name, == ,"hidl");
p = gbinder_rpc_protocol_for_device("/dev/hwbinder");
g_assert(p);
g_assert_cmpstr(p->name, == ,"hidl");
p = gbinder_rpc_protocol_for_device("/dev/binder");
g_assert(p);
g_assert_cmpstr(p->name, == ,"aidl");
/* The default is redefined */
p = gbinder_rpc_protocol_for_device("/dev/someotherbinder");
g_assert(p);
g_assert_cmpstr(p->name, == ,"hidl");
test_config_cleanup(&config);
}
/*==========================================================================*
* config3
*==========================================================================*/
static
void
test_config3(
void)
{
const GBinderRpcProtocol* p;
TestConfig config;
test_config_init(&config,
"[Whatever]\n"
"/dev/hwbinder = aidl\n"); /* Ignored, wrong section */
/* Just the default config */
p = gbinder_rpc_protocol_for_device(NULL);
g_assert(p);
g_assert_cmpstr(p->name, == ,"aidl");
p = gbinder_rpc_protocol_for_device("/dev/hwbinder");
g_assert(p);
g_assert_cmpstr(p->name, == ,"hidl");
p = gbinder_rpc_protocol_for_device("/dev/binder");
g_assert(p);
g_assert_cmpstr(p->name, == ,"aidl");
test_config_cleanup(&config);
}
/*==========================================================================*
@@ -97,14 +297,21 @@ test_device(
static
void
test_no_header1(
void)
gconstpointer test_data)
{
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER), 0, 0);
const TestData* test = test_data;
GBinderRemoteRequest* req;
TestConfig config;
test_config_init2(&config, test->dev, test->prot);
req = gbinder_remote_request_new(NULL, gbinder_rpc_protocol_for_device
(GBINDER_DEFAULT_BINDER), 0, 0);
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION, NULL);
g_assert(!gbinder_remote_request_interface(req));
gbinder_remote_request_unref(req);
test_config_cleanup(&config);
}
/*==========================================================================*
@@ -114,21 +321,35 @@ test_no_header1(
static
void
test_no_header2(
void)
gconstpointer test_data)
{
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);
const TestData* test = test_data;
const GBinderRpcProtocol* p;
GBinderDriver* driver;
GBinderRemoteRequest* req;
TestConfig config;
test_config_init2(&config, test->dev, test->prot);
p = gbinder_rpc_protocol_for_device(test->dev);
driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, p);
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_memdup(TEST_ARRAY_AND_SIZE(test_header_aidl)),
sizeof(test_header_aidl), NULL));
g_assert(!gbinder_remote_request_interface(req));
gbinder_remote_request_unref(req);
gbinder_driver_unref(driver);
test_config_cleanup(&config);
}
static const TestData test_no_header_data[] = {
{ "aidl", "aidl", GBINDER_DEFAULT_BINDER },
{ "aidl2", "aidl2", GBINDER_DEFAULT_BINDER },
};
/*==========================================================================*
* write_header
*==========================================================================*/
@@ -139,17 +360,24 @@ test_write_header(
gconstpointer test_data)
{
const TestHeaderData* test = test_data;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(test->dev);
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
const GBinderRpcProtocol* prot;
GBinderLocalRequest* req;
GBinderOutputData* data;
GBinderWriter writer;
TestConfig config;
test_config_init2(&config, test->dev, test->prot);
prot = gbinder_rpc_protocol_for_device(test->dev);
req = gbinder_local_request_new(&gbinder_io_32, NULL);
gbinder_local_request_init_writer(req, &writer);
prot->write_rpc_header(&writer, test->iface);
data = gbinder_local_request_data(req);
g_assert(data->bytes->len == test->header_size);
g_assert(!memcmp(data->bytes->data, test->header, test->header_size));
gbinder_local_request_unref(req);
test_config_cleanup(&config);
}
/*==========================================================================*
@@ -162,16 +390,23 @@ test_read_header(
gconstpointer test_data)
{
const TestHeaderData* test = test_data;
GBinderDriver* driver = gbinder_driver_new(test->dev, NULL);
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
gbinder_rpc_protocol_for_device(test->dev), 0, 0);
GBinderDriver* driver;
GBinderRemoteRequest* req;
TestConfig config;
test_config_init2(&config, test->dev, test->prot);
driver = gbinder_driver_new(test->dev, NULL);
req = gbinder_remote_request_new(NULL, gbinder_rpc_protocol_for_device
(test->dev), 0, 0);
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));
g_assert_cmpstr(gbinder_remote_request_interface(req), == ,test->iface);
gbinder_remote_request_unref(req);
gbinder_driver_unref(driver);
test_config_cleanup(&config);
}
/*==========================================================================*
@@ -187,20 +422,36 @@ int main(int argc, char* argv[])
g_test_init(&argc, &argv, NULL);
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);
g_test_add_func(TEST_("config1"), test_config1);
g_test_add_func(TEST_("config2"), test_config2);
g_test_add_func(TEST_("config3"), test_config3);
for (i = 0; i < G_N_ELEMENTS(test_no_header_data); i++) {
const TestData* test = test_no_header_data + i;
char* path;
path = g_strconcat(TEST_("no_header1/"), test->name, NULL);
g_test_add_data_func(path, test, test_no_header1);
g_free(path);
path = g_strconcat(TEST_("no_header2/"), test->name, NULL);
g_test_add_data_func(path, test, test_no_header2);
g_free(path);
}
for (i = 0; i < G_N_ELEMENTS(test_header_tests); i++) {
const TestHeaderData* test = test_header_tests + i;
char* path;
path = g_strconcat(TEST_PREFIX, test->name, "/read_header", NULL);
path = g_strconcat(TEST_("read_header/"), test->name, NULL);
g_test_add_data_func(path, test, test_read_header);
g_free(path);
path = g_strconcat(TEST_PREFIX, test->name, "/write_header", NULL);
g_test_add_data_func(path, test, test_write_header);
g_free(path);
if (test->iface) {
path = g_strconcat(TEST_("write_header/"), test->name, NULL);
g_test_add_data_func(path, test, test_write_header);
g_free(path);
}
}
test_init(&test_opt, argc, argv);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* 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.
* 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
@@ -624,7 +624,7 @@ test_hidl_struct(
gconstpointer test_data)
{
const TestHidlStruct* test = test_data;
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data;
@@ -828,7 +828,7 @@ test_hidl_vec(
gconstpointer test_data)
{
const TestHidlVec* test = test_data;
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data;
@@ -934,7 +934,7 @@ test_hidl_string_err(
gconstpointer test_data)
{
const TestHidlStringErr* test = test_data;
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data;
@@ -968,7 +968,7 @@ test_hidl_string_err_skip(
gconstpointer test_data)
{
const TestHidlStringErr* test = test_data;
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data;
@@ -1013,7 +1013,7 @@ test_fd_ok(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1053,7 +1053,7 @@ test_fd_shortbuf(
TEST_INT32_BYTES(BINDER_TYPE_FD),
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1087,7 +1087,7 @@ test_fd_badtype(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1130,7 +1130,7 @@ test_dupfd_ok(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1177,7 +1177,7 @@ test_dupfd_badtype(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1220,7 +1220,7 @@ test_dupfd_badfd(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1259,7 +1259,7 @@ test_hidl_string(
guint bufcount,
const char* result)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver, g_memdup(input, size),
size, NULL);
GBinderRemoteObject* obj = NULL;
@@ -1530,7 +1530,7 @@ test_buffer(
TEST_INT64_BYTES(0), TEST_INT64_BYTES(0),
TEST_INT64_BYTES(0), TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderRemoteObject* obj = NULL;
@@ -1578,7 +1578,7 @@ test_object(
TEST_INT32_BYTES(BINDER_TYPE_HANDLE), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(1 /* handle*/), TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderRemoteObject* obj = NULL;
@@ -1636,7 +1636,7 @@ test_object_invalid(
TEST_INT32_BYTES(42 /* invalid type */), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(1 /* handle*/), TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderRemoteObject* obj = NULL;
@@ -1670,7 +1670,7 @@ test_vec(
void)
{
/* Using 64-bit I/O */
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderReaderData data;
GBinderReader reader;
BinderObject64 obj;
@@ -1723,7 +1723,7 @@ test_hidl_string_vec(
gsize size,
const char* const* result)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver, g_memdup(input, size),
size, NULL);
GBinderRemoteObject* obj = NULL;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* 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.
* 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
@@ -68,7 +68,7 @@ void
test_basic(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj1 = gbinder_object_registry_get_remote(reg, 1);
GBinderRemoteObject* obj2 = gbinder_object_registry_get_remote(reg, 2);
@@ -112,7 +112,7 @@ test_dead(
{
const guint handle = 1;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderRemoteObject* obj = gbinder_ipc_get_remote_object
(ipc, handle, FALSE);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -34,6 +34,7 @@
#include "gbinder_driver.h"
#include "gbinder_client_p.h"
#include "gbinder_config.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_ipc.h"
#include "gbinder_local_object_p.h"
@@ -47,6 +48,7 @@
#include <errno.h>
static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-servicemanager-XXXXXX";
static
void
@@ -224,7 +226,7 @@ test_hwservicemanager_check_name(
{
TestHwServiceManager* self = TEST_HWSERVICEMANAGER(sm);
return (!name || self->reject_name) ?
return (!name || self->reject_name) ?
GBINDER_SERVICEMANAGER_NAME_INVALID :
GBINDER_SERVICEMANAGER_NAME_NORMALIZE;
}
@@ -281,7 +283,6 @@ test_hwservicemanager_class_init(
{
klass->iface = TEST_HWSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;
klass->list = test_servicemanager_list;
klass->get_service = test_servicemanager_get_service;
klass->add_service = test_servicemanager_add_service;
@@ -292,12 +293,10 @@ test_hwservicemanager_class_init(
G_OBJECT_CLASS(klass)->finalize = test_hwservicemanager_finalize;
}
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev)
GType
gbinder_servicemanager_hidl_get_type()
{
return gbinder_servicemanager_new_with_type(TEST_TYPE_HWSERVICEMANAGER,
dev);
return TEST_TYPE_HWSERVICEMANAGER;
}
/*==========================================================================*
@@ -325,7 +324,7 @@ test_defservicemanager_check_name(
{
TestDefServiceManager* self = TEST_DEFSERVICEMANAGER(sm);
return (!name || self->reject_name) ?
return (!name || self->reject_name) ?
GBINDER_SERVICEMANAGER_NAME_INVALID :
GBINDER_SERVICEMANAGER_NAME_OK;
}
@@ -365,7 +364,6 @@ test_defservicemanager_class_init(
{
klass->iface = TEST_DEFSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_BINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
klass->list = test_servicemanager_list;
klass->get_service = test_servicemanager_get_service;
klass->add_service = test_servicemanager_add_service;
@@ -374,12 +372,17 @@ test_defservicemanager_class_init(
G_OBJECT_CLASS(klass)->finalize = test_defservicemanager_finalize;
}
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev)
GType
gbinder_servicemanager_aidl_get_type()
{
return gbinder_servicemanager_new_with_type(TEST_TYPE_DEFSERVICEMANAGER,
dev);
return TEST_TYPE_DEFSERVICEMANAGER;
}
GType
gbinder_servicemanager_aidl2_get_type()
{
/* Avoid pulling in gbinder_servicemanager_aidl2 object */
return TEST_TYPE_DEFSERVICEMANAGER;
}
/*==========================================================================*
@@ -391,6 +394,7 @@ void
test_null(
void)
{
g_assert(!gbinder_servicemanager_new(NULL));
g_assert(!gbinder_servicemanager_new_with_type(0, NULL));
g_assert(!gbinder_servicemanager_new_local_object(NULL, NULL, NULL, NULL));
g_assert(!gbinder_servicemanager_ref(NULL));
@@ -423,7 +427,7 @@ test_invalid(
{
int status = 0;
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServiceManager* sm;
gulong id = 0;
@@ -466,9 +470,9 @@ static
void
test_basic(
void)
{
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServiceManager* sm;
GBinderLocalObject* obj;
@@ -486,6 +490,122 @@ test_basic(
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* legacy
*==========================================================================*/
static
void
test_legacy(
void)
{
const char* otherdev = "/dev/otherbinder";
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServiceManager* sm;
/* Reset the state */
gbinder_servicemanager_exit();
gbinder_config_exit();
gbinder_config_file = NULL;
test_setup_ping(ipc);
sm = gbinder_hwservicemanager_new(dev);
g_assert(TEST_IS_HWSERVICEMANAGER(sm));
gbinder_servicemanager_unref(sm);
test_setup_ping(ipc);
sm = gbinder_defaultservicemanager_new(dev);
g_assert(TEST_IS_DEFSERVICEMANAGER(sm));
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
/* Legacy default */
ipc = gbinder_ipc_new(otherdev);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(otherdev);
g_assert(TEST_IS_DEFSERVICEMANAGER(sm));
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_servicemanager_exit();
}
/*==========================================================================*
* config
*==========================================================================*/
static
void
test_config(
void)
{
GBinderIpc* ipc;
GBinderServiceManager* sm;
const char* strange_name = "/dev/notbinder";
const char* legacy_name = "/dev/legacybinder";
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
static const char config[] =
"[ServiceManager]\n"
"Default = hidl\n"
"/dev/binder = hidl\n" /* Redefined name for /dev/binder */
"/dev/hwbinder = foo\n" /* Invalid name */
"/dev/legacybinder = aidl\n";
/* Reset the state */
gbinder_servicemanager_exit();
gbinder_config_exit();
/* Write the config file */
g_assert(g_file_set_contents(file, config, -1, NULL));
gbinder_config_file = file;
/* Unknown device instantiates the default */
ipc = gbinder_ipc_new(strange_name);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(strange_name);
g_assert(TEST_IS_HWSERVICEMANAGER(sm));
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
/* This one was redefined */
ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(GBINDER_DEFAULT_BINDER);
g_assert(TEST_IS_HWSERVICEMANAGER(sm));
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
/* This one was not (since name was invalid) */
ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(GBINDER_DEFAULT_HWBINDER);
g_assert(TEST_IS_HWSERVICEMANAGER(sm));
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
/* This one points to legacy manager */
ipc = gbinder_ipc_new(legacy_name);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(legacy_name);
g_assert(TEST_IS_DEFSERVICEMANAGER(sm));
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
/* Clear the state */
gbinder_servicemanager_exit();
gbinder_config_exit();
gbinder_config_file = NULL;
remove(file);
remove(dir);
g_free(file);
g_free(dir);
}
/*==========================================================================*
* not_present
*==========================================================================*/
@@ -494,9 +614,9 @@ static
void
test_not_present(
void)
{
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderServiceManager* sm;
@@ -519,9 +639,9 @@ static
void
test_wait(
void)
{
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
const glong forever = (test_opt.flags & TEST_FLAG_DEBUG) ?
(TEST_TIMEOUT_SEC * 1000) : -1;
@@ -569,9 +689,9 @@ static
void
test_wait_long(
void)
{
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderServiceManager* sm;
gulong id;
@@ -614,9 +734,9 @@ static
void
test_wait_async(
void)
{
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
@@ -658,9 +778,9 @@ static
void
test_death(
void)
{
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
@@ -728,7 +848,7 @@ test_reanimate(
void)
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
@@ -777,13 +897,13 @@ static
void
test_reuse(
void)
{
{
const char* binder_dev = GBINDER_DEFAULT_BINDER;
const char* vndbinder_dev = "/dev/vpnbinder";
const char* hwbinder_dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* binder_ipc = gbinder_ipc_new(binder_dev, NULL);
GBinderIpc* vndbinder_ipc = gbinder_ipc_new(vndbinder_dev, NULL);
GBinderIpc* hwbinder_ipc = gbinder_ipc_new(hwbinder_dev, NULL);
GBinderIpc* binder_ipc = gbinder_ipc_new(binder_dev);
GBinderIpc* vndbinder_ipc = gbinder_ipc_new(vndbinder_dev);
GBinderIpc* hwbinder_ipc = gbinder_ipc_new(hwbinder_dev);
GBinderServiceManager* m1;
GBinderServiceManager* m2;
GBinderServiceManager* vnd1;
@@ -835,7 +955,7 @@ test_notify_type(
GType t,
const char* dev)
{
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServiceManager* sm;
TestHwServiceManager* test;
const char* name = "foo";
@@ -902,7 +1022,7 @@ test_list(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
TestHwServiceManager* test;
@@ -950,7 +1070,7 @@ test_get(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
TestHwServiceManager* test;
@@ -1011,7 +1131,7 @@ test_add(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
TestHwServiceManager* test;
@@ -1048,6 +1168,8 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("invalid"), test_invalid);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("legacy"), test_legacy);
g_test_add_func(TEST_("config"), test_config);
g_test_add_func(TEST_("not_present"), test_not_present);
g_test_add_func(TEST_("wait"), test_wait);
g_test_add_func(TEST_("wait_long"), test_wait_long);

View File

@@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_servicemanager_aidl
include ../common/Makefile

View File

@@ -0,0 +1,444 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 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_driver.h"
#include "gbinder_config.h"
#include "gbinder_ipc.h"
#include "gbinder_reader.h"
#include "gbinder_servicemanager_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_local_object.h"
#include "gbinder_local_reply.h"
#include "gbinder_remote_request.h"
#include "gbinder_remote_object.h"
#include <gutil_strv.h>
#include <gutil_macros.h>
#include <gutil_log.h>
#include <errno.h>
static TestOpt test_opt;
GType
gbinder_servicemanager_hidl_get_type()
{
/* Avoid pulling in gbinder_servicemanager_hidl object */
return 0;
}
GType
gbinder_servicemanager_aidl2_get_type()
{
/* Avoid pulling in gbinder_servicemanager_aidl2 object */
return 0;
}
/*==========================================================================*
* Test service manager
*==========================================================================*/
#define SVCMGR_HANDLE (0)
static const char SVCMGR[] = "android.os.IServiceManager";
enum servicemanager_aidl_tx {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION
};
const char* const servicemanager_aidl_ifaces[] = { SVCMGR, NULL };
typedef struct test_service_manager {
GBinderLocalObject* obj;
GHashTable* objects;
} TestServiceManager;
static
GBinderLocalReply*
servicemanager_aidl_handler(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
TestServiceManager* self = user_data;
GBinderLocalReply* reply = NULL;
GBinderReader reader;
GBinderRemoteObject* remote_obj;
guint32 num;
char* str;
g_assert(!flags);
g_assert_cmpstr(gbinder_remote_request_interface(req), == ,SVCMGR);
*status = -1;
switch (code) {
case GET_SERVICE_TRANSACTION:
case CHECK_SERVICE_TRANSACTION:
gbinder_remote_request_init_reader(req, &reader);
str = gbinder_reader_read_string16(&reader);
if (str) {
reply = gbinder_local_object_new_reply(obj);
remote_obj = g_hash_table_lookup(self->objects, str);
if (remote_obj) {
GDEBUG("Found name '%s' => %p", str, remote_obj);
gbinder_local_reply_append_remote_object(reply, remote_obj);
} else {
GDEBUG("Name '%s' not found", str);
gbinder_local_reply_append_int32(reply, GBINDER_STATUS_OK);
}
g_free(str);
}
break;
case ADD_SERVICE_TRANSACTION:
gbinder_remote_request_init_reader(req, &reader);
str = gbinder_reader_read_string16(&reader);
remote_obj = gbinder_reader_read_object(&reader);
if (str && remote_obj && gbinder_reader_read_uint32(&reader, &num)) {
GDEBUG("Adding '%s'", str);
g_hash_table_replace(self->objects, str, remote_obj);
remote_obj = NULL;
str = NULL;
reply = gbinder_local_object_new_reply(obj);
*status = GBINDER_STATUS_OK;
}
g_free(str);
gbinder_remote_object_unref(remote_obj);
break;
case LIST_SERVICES_TRANSACTION:
if (gbinder_remote_request_read_uint32(req, &num)) {
if (num < g_hash_table_size(self->objects)) {
GList* keys = g_hash_table_get_keys(self->objects);
GList* l = g_list_nth(keys, num);
reply = gbinder_local_object_new_reply(obj);
gbinder_local_reply_append_string16(reply, l->data);
g_list_free(keys);
*status = GBINDER_STATUS_OK;
} else {
GDEBUG("Index %u out of bounds", num);
}
}
break;
default:
GDEBUG("Unhandled command %u", code);
break;
}
return reply;
}
static
TestServiceManager*
servicemanager_aidl_new(
const char* dev)
{
TestServiceManager* self = g_new0(TestServiceManager, 1);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
self->objects = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify) gbinder_remote_object_unref);
self->obj = gbinder_local_object_new(ipc, servicemanager_aidl_ifaces,
servicemanager_aidl_handler, self);
test_binder_set_looper_enabled(fd, TRUE);
test_binder_register_object(fd, self->obj, SVCMGR_HANDLE);
gbinder_ipc_unref(ipc);
return self;
}
static
void
servicemanager_aidl_free(
TestServiceManager* self)
{
gbinder_local_object_drop(self->obj);
g_hash_table_destroy(self->objects);
g_free(self);
}
/*==========================================================================*
* get
*==========================================================================*/
static
void
test_add_cb(
GBinderServiceManager* sm,
int status,
void* user_data)
{
g_assert(status == GBINDER_STATUS_OK);
if (user_data) {
g_main_loop_quit(user_data);
}
}
static
void
test_get_none_cb(
GBinderServiceManager* sm,
GBinderRemoteObject* obj,
int status,
void* user_data)
{
g_assert(!obj);
g_assert(status == GBINDER_STATUS_OK);
g_main_loop_quit(user_data);
}
static
void
test_get_cb(
GBinderServiceManager* sm,
GBinderRemoteObject* obj,
int status,
void* user_data)
{
g_assert(obj);
g_assert(status == GBINDER_STATUS_OK);
g_main_loop_quit(user_data);
}
static
void
test_get()
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
GBinderIpc* ipc = gbinder_ipc_new(dev);
TestServiceManager* smsvc = servicemanager_aidl_new(other_dev);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
const char* name = "name";
GBinderServiceManager* sm;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
sm = gbinder_servicemanager_new(dev);
/* Query the object (it's not there yet) and wait for completion */
GDEBUG("Querying '%s'", name);
g_assert(gbinder_servicemanager_get_service(sm, name, test_get_none_cb,
loop));
test_run(&test_opt, loop);
/* Register object and wait for completion */
GDEBUG("Registering object '%s' => %p", name, obj);
g_assert(gbinder_servicemanager_add_service(sm, name, obj,
test_add_cb, loop));
test_run(&test_opt, loop);
g_assert_cmpuint(g_hash_table_size(smsvc->objects), == ,1);
g_assert(g_hash_table_contains(smsvc->objects, name));
/* Query the object (it should be there not) and wait for completion */
GDEBUG("Querying '%s' again", name);
g_assert(gbinder_servicemanager_get_service(sm, name, test_get_cb, loop));
test_run(&test_opt, loop);
test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj);
servicemanager_aidl_free(smsvc);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
test_binder_exit_wait();
g_main_loop_unref(loop);
}
/*==========================================================================*
* list
*==========================================================================*/
typedef struct test_list {
char** list;
GMainLoop* loop;
} TestList;
static
gboolean
test_list_cb(
GBinderServiceManager* sm,
char** services,
void* user_data)
{
TestList* test = user_data;
GDEBUG("Got %u name(s)", gutil_strv_length(services));
g_strfreev(test->list);
test->list = services;
g_main_loop_quit(test->loop);
return TRUE;
}
static
void
test_list()
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
GBinderIpc* ipc = gbinder_ipc_new(dev);
TestServiceManager* smsvc = servicemanager_aidl_new(other_dev);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
const char* name = "name";
GBinderServiceManager* sm;
TestList test;
memset(&test, 0, sizeof(test));
test.loop = g_main_loop_new(NULL, FALSE);
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
sm = gbinder_servicemanager_new(dev);
/* Request the list and wait for completion */
g_assert(gbinder_servicemanager_list(sm, test_list_cb, &test));
test_run(&test_opt, test.loop);
/* There's nothing there yet */
g_assert(test.list);
g_assert(!test.list[0]);
/* Register object and wait for completion */
g_assert(gbinder_servicemanager_add_service(sm, name, obj,
test_add_cb, test.loop));
test_run(&test_opt, test.loop);
/* Request the list again */
g_assert(gbinder_servicemanager_list(sm, test_list_cb, &test));
test_run(&test_opt, test.loop);
/* Now the name must be there */
g_assert_cmpuint(gutil_strv_length(test.list), == ,1);
g_assert_cmpstr(test.list[0], == ,name);
test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj);
servicemanager_aidl_free(smsvc);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
test_binder_exit_wait();
g_strfreev(test.list);
g_main_loop_unref(test.loop);
}
/*==========================================================================*
* notify
*==========================================================================*/
static
void
test_notify_cb(
GBinderServiceManager* sm,
const char* name,
void* user_data)
{
g_assert(name);
GDEBUG("'%s' is registered", name);
g_main_loop_quit(user_data);
}
static
void
test_notify()
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
GBinderIpc* ipc = gbinder_ipc_new(dev);
TestServiceManager* smsvc = servicemanager_aidl_new(other_dev);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
const char* name = "name";
GBinderServiceManager* sm;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
sm = gbinder_servicemanager_new(dev);
gbinder_ipc_set_max_threads(ipc, 1);
/* Start watching */
id = gbinder_servicemanager_add_registration_handler(sm, name,
test_notify_cb, loop);
g_assert(id);
/* Register the object and wait for completion */
GDEBUG("Registering object '%s' => %p", name, obj);
g_assert(gbinder_servicemanager_add_service(sm, name, obj,
test_add_cb, NULL));
/* test_notify_cb will stop the loop */
test_run(&test_opt, loop);
gbinder_servicemanager_remove_handler(sm, id);
test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj);
servicemanager_aidl_free(smsvc);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
test_binder_exit_wait();
g_main_loop_unref(loop);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_(t) "/servicemanager_aidl/" t
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("get"), test_get);
g_test_add_func(TEST_("list"), test_list);
g_test_add_func(TEST_("notify"), test_notify);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2019-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -202,7 +202,6 @@ test_servicemanager_class_init(
{
klass->iface = TEST_SERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
klass->list = test_servicemanager_list;
klass->get_service = test_servicemanager_get_service;
klass->add_service = test_servicemanager_add_service;
@@ -212,18 +211,24 @@ test_servicemanager_class_init(
G_OBJECT_CLASS(klass)->finalize = test_servicemanager_finalize;
}
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev)
/* Avoid pulling in the actual objects */
GType
gbinder_servicemanager_aidl_get_type()
{
return gbinder_servicemanager_new_with_type(TEST_TYPE_SERVICEMANAGER, dev);
return TEST_TYPE_SERVICEMANAGER;
}
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev)
GType
gbinder_servicemanager_aidl2_get_type()
{
return gbinder_servicemanager_new(dev);
return TEST_TYPE_SERVICEMANAGER;
}
GType
gbinder_servicemanager_hidl_get_type()
{
return TEST_TYPE_SERVICEMANAGER;
}
/*==========================================================================*
@@ -236,7 +241,7 @@ test_null(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServiceManager* sm;
test_setup_ping(ipc);
@@ -263,7 +268,7 @@ test_basic(
const char* obj_name = "test";
const char* dev = GBINDER_DEFAULT_BINDER;
const char* const ifaces[] = { "interface", NULL };
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj;
GBinderServiceManager* sm;
@@ -306,7 +311,7 @@ test_present(
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj;
@@ -371,7 +376,7 @@ test_not_present(
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj;
@@ -421,7 +426,7 @@ test_cancel(
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -174,7 +174,6 @@ test_servicemanager_class_init(
{
klass->iface = TEST_SERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
klass->list = test_servicemanager_list;
klass->get_service = test_servicemanager_get_service;
klass->add_service = test_servicemanager_add_service;
@@ -184,18 +183,24 @@ test_servicemanager_class_init(
G_OBJECT_CLASS(klass)->finalize = test_servicemanager_finalize;
}
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev)
/* Avoid pulling in the actual objects */
GType
gbinder_servicemanager_aidl_get_type()
{
return gbinder_servicemanager_new_with_type(TEST_TYPE_SERVICEMANAGER, dev);
return TEST_TYPE_SERVICEMANAGER;
}
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev)
GType
gbinder_servicemanager_aidl2_get_type()
{
return gbinder_servicemanager_new(dev);
return TEST_TYPE_SERVICEMANAGER;
}
GType
gbinder_servicemanager_hidl_get_type()
{
return TEST_TYPE_SERVICEMANAGER;
}
/*==========================================================================*
@@ -225,7 +230,7 @@ test_basic(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServicePoll* weakptr = NULL;
GBinderServiceManager* manager;
GBinderServicePoll* poll;
@@ -301,7 +306,7 @@ test_notify1(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServicePoll* weakptr = NULL;
GBinderServiceManager* manager;
@@ -375,7 +380,7 @@ test_notify2(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServicePoll* weakptr = NULL;
GBinderServiceManager* manager;
@@ -434,7 +439,7 @@ test_already_there(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServicePoll* weakptr = NULL;
GBinderServiceManager* manager;