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

39
README
View File

@@ -1,7 +1,44 @@
GLib-style interface to binder (Android IPC mechanism) GLib-style interface to binder (Android IPC mechanism)
Provides: Key features:
1. Integration with GLib event loop 1. Integration with GLib event loop
2. Detection of 32 vs 64 bit kernel at runtime 2. Detection of 32 vs 64 bit kernel at runtime
3. Asynchronous transactions that don't block the event thread 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 libgbinder (1.0.47) unstable; urgency=low
* Make library executable on RPM based systems * Make library executable on RPM based systems

View File

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

View File

@@ -1,5 +1,5 @@
Name: libgbinder Name: libgbinder
Version: 1.0.47 Version: 1.1.1
Release: 0 Release: 0
Summary: Binder client library Summary: Binder client library
License: BSD 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) { if (ret >= 0) {
/* Loop until we have handled all the incoming commands */ /* Loop until we have handled all the incoming commands */
gbinder_driver_handle_commands(self, reg, handler, &rb); 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); ret = gbinder_driver_write_read(self, NULL, &rb.buf);
if (ret >= 0) { if (ret >= 0) {
gbinder_driver_handle_commands(self, reg, handler, &rb); gbinder_driver_handle_commands(self, reg, handler, &rb);

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2019 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -33,6 +33,12 @@
#include "gbinder_rpc_protocol.h" #include "gbinder_rpc_protocol.h"
#include "gbinder_reader.h" #include "gbinder_reader.h"
#include "gbinder_writer.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) * GBinderIpcProtocol callbacks (see Parcel::writeInterfaceToken in Android)
@@ -40,19 +46,39 @@
* *
* platform/system/libhwbinder/Parcel.cpp * platform/system/libhwbinder/Parcel.cpp
* platform/frameworks/native/libs/binder/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 static
void void
gbinder_rpc_protocol_binder_write_ping( gbinder_rpc_protocol_aidl_write_ping(
GBinderWriter* writer) GBinderWriter* writer)
{ {
/* No payload */ /* No payload */
@@ -60,7 +86,7 @@ gbinder_rpc_protocol_binder_write_ping(
static static
void void
gbinder_rpc_protocol_binder_write_rpc_header( gbinder_rpc_protocol_aidl_write_rpc_header(
GBinderWriter* writer, GBinderWriter* writer,
const char* iface) const char* iface)
{ {
@@ -75,7 +101,7 @@ gbinder_rpc_protocol_binder_write_rpc_header(
static static
const char* const char*
gbinder_rpc_protocol_binder_read_rpc_header( gbinder_rpc_protocol_aidl_read_rpc_header(
GBinderReader* reader, GBinderReader* reader,
guint32 txcode, guint32 txcode,
char** iface) char** iface)
@@ -91,13 +117,69 @@ gbinder_rpc_protocol_binder_read_rpc_header(
return *iface; 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 static
void 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, GBinderWriter* writer,
const char* iface) const char* iface)
{ {
@@ -109,16 +191,16 @@ gbinder_rpc_protocol_hwbinder_write_rpc_header(
static static
void void
gbinder_rpc_protocol_hwbinder_write_ping( gbinder_rpc_protocol_hidl_write_ping(
GBinderWriter* writer) GBinderWriter* writer)
{ {
gbinder_rpc_protocol_hwbinder_write_rpc_header(writer, gbinder_rpc_protocol_hidl_write_rpc_header(writer,
"android.hidl.base@1.0::IBase"); "android.hidl.base@1.0::IBase");
} }
static static
const char* const char*
gbinder_rpc_protocol_hwbinder_read_rpc_header( gbinder_rpc_protocol_hidl_read_rpc_header(
GBinderReader* reader, GBinderReader* reader,
guint32 txcode, guint32 txcode,
char** iface) char** iface)
@@ -127,30 +209,126 @@ gbinder_rpc_protocol_hwbinder_read_rpc_header(
return gbinder_reader_read_string8(reader); 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 * 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* const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device( gbinder_rpc_protocol_for_device(
const char* dev) const char* dev)
{ {
return (dev && !strcmp(dev, GBINDER_DEFAULT_HWBINDER)) ? if (dev) {
&gbinder_rpc_protocol_hwbinder : &gbinder_rpc_protocol_binder; 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 * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived * contributors may be used to endorse or promote products derived
* from this software without specific prior written permission. * from this software without specific prior written permission.
@@ -37,11 +36,12 @@
#include "gbinder_types_p.h" #include "gbinder_types_p.h"
/* /*
* For whatever reason services communicating via /dev/binder * There are several versions of binder RPC protocol with diffferent
* and /dev/hwbinder use slightly different RPC headers. * transaction headers and transaction codes.
*/ */
struct gbinder_rpc_protocol { struct gbinder_rpc_protocol {
const char* name;
guint32 ping_tx; guint32 ping_tx;
void (*write_ping)(GBinderWriter* writer); void (*write_ping)(GBinderWriter* writer);
void (*write_rpc_header)(GBinderWriter* writer, const char* iface); void (*write_rpc_header)(GBinderWriter* writer, const char* iface);
@@ -49,15 +49,19 @@ struct gbinder_rpc_protocol {
char** iface); 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 */ /* Returns one of the above based on the device name */
const GBinderRpcProtocol* const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device( gbinder_rpc_protocol_for_device(
const char* dev) const char* dev)
GBINDER_INTERNAL; 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 */ #endif /* GBINDER_RPC_PROTOCOL_H */
/* /*

View File

@@ -34,6 +34,7 @@
#include "gbinder_servicemanager_p.h" #include "gbinder_servicemanager_p.h"
#include "gbinder_client_p.h" #include "gbinder_client_p.h"
#include "gbinder_config.h"
#include "gbinder_local_object_p.h" #include "gbinder_local_object_p.h"
#include "gbinder_remote_object_p.h" #include "gbinder_remote_object_p.h"
#include "gbinder_eventloop_p.h" #include "gbinder_eventloop_p.h"
@@ -47,6 +48,51 @@
#include <errno.h> #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_MIN (100)
#define PRESENSE_WAIT_MS_MAX (1000) #define PRESENSE_WAIT_MS_MAX (1000)
#define PRESENSE_WAIT_MS_STEP (100) #define PRESENSE_WAIT_MS_STEP (100)
@@ -75,9 +121,6 @@ G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
#define GBINDER_SERVICEMANAGER(obj) \ #define GBINDER_SERVICEMANAGER(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER, \ G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManager) GBinderServiceManager)
#define GBINDER_SERVICEMANAGER_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
#define GBINDER_SERVICEMANAGER_GET_CLASS(obj) \ #define GBINDER_SERVICEMANAGER_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER, \ G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass) GBinderServiceManagerClass)
@@ -408,6 +451,64 @@ gbinder_servicemanager_autorelease_cb(
g_slist_free_full(list, g_object_unref); 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 * Internal interface
*==========================================================================*/ *==========================================================================*/
@@ -424,9 +525,9 @@ gbinder_servicemanager_new_with_type(
GBinderIpc* ipc; GBinderIpc* ipc;
if (!dev) dev = klass->default_device; if (!dev) dev = klass->default_device;
ipc = gbinder_ipc_new(dev, klass->rpc_protocol); ipc = gbinder_ipc_new(dev);
if (ipc) { if (ipc) {
/* Create a possible dead remote object */ /* Create a possibly dead remote object */
GBinderRemoteObject* object = gbinder_ipc_get_remote_object GBinderRemoteObject* object = gbinder_ipc_get_remote_object
(ipc, GBINDER_SERVICEMANAGER_HANDLE, TRUE); (ipc, GBINDER_SERVICEMANAGER_HANDLE, TRUE);
@@ -517,11 +618,35 @@ GBinderServiceManager*
gbinder_servicemanager_new( gbinder_servicemanager_new(
const char* dev) const char* dev)
{ {
if (!g_strcmp0(dev, GBINDER_DEFAULT_HWBINDER)) { if (dev) {
return gbinder_hwservicemanager_new(dev); const GBinderServiceManagerType* type = NULL;
} else {
return gbinder_defaultservicemanager_new(dev); 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* 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 * Internals
*==========================================================================*/ *==========================================================================*/

View File

@@ -30,8 +30,9 @@
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "gbinder_servicemanager_p.h" #define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_rpc_protocol.h"
#include "gbinder_servicemanager_aidl.h"
#include "gbinder_servicepoll.h" #include "gbinder_servicepoll.h"
#include "gbinder_eventloop_p.h" #include "gbinder_eventloop_p.h"
#include "gbinder_log.h" #include "gbinder_log.h"
@@ -40,61 +41,47 @@
#include <gbinder_local_request.h> #include <gbinder_local_request.h>
#include <gbinder_remote_reply.h> #include <gbinder_remote_reply.h>
#include <gutil_macros.h> typedef struct gbinder_servicemanager_aidl_watch {
#include <errno.h>
#include <pthread.h>
typedef struct gbinder_defaultservicemanager_watch {
GBinderServicePoll* poll; GBinderServicePoll* poll;
char* name; char* name;
gulong handler_id; gulong handler_id;
GBinderEventLoopTimeout* notify; GBinderEventLoopTimeout* notify;
} GBinderDefaultServiceManagerWatch; } GBinderServiceManagerAidlWatch;
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass; struct gbinder_servicemanager_aidl_priv {
typedef struct gbinder_defaultservicemanager {
GBinderServiceManager manager;
GBinderServicePoll* poll; GBinderServicePoll* poll;
GHashTable* watch_table; GHashTable* watch_table;
} GBinderDefaultServiceManager; };
G_DEFINE_TYPE(GBinderDefaultServiceManager, G_DEFINE_TYPE(GBinderServiceManagerAidl,
gbinder_defaultservicemanager, gbinder_servicemanager_aidl,
GBINDER_TYPE_SERVICEMANAGER) GBINDER_TYPE_SERVICEMANAGER)
#define PARENT_CLASS gbinder_defaultservicemanager_parent_class #define PARENT_CLASS gbinder_servicemanager_aidl_parent_class
#define GBINDER_TYPE_DEFAULTSERVICEMANAGER \ #define GBINDER_SERVICEMANAGER_AIDL(obj) \
gbinder_defaultservicemanager_get_type() G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
#define GBINDER_DEFAULTSERVICEMANAGER(obj) \ GBinderServiceManagerAidl)
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_DEFAULTSERVICEMANAGER, \ #define GBINDER_SERVICEMANAGER_AIDL_GET_CLASS(obj) \
GBinderDefaultServiceManager) 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, GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION, CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION, ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION LIST_SERVICES_TRANSACTION
}; };
#define DEFAULTSERVICEMANAGER_IFACE "android.os.IServiceManager" #define SERVICEMANAGER_AIDL_IFACE "android.os.IServiceManager"
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(GBINDER_TYPE_DEFAULTSERVICEMANAGER, dev);
}
static static
void void
gbinder_defaultservicemanager_watch_proc( gbinder_servicemanager_aidl_watch_proc(
GBinderServicePoll* poll, GBinderServicePoll* poll,
const char* name_added, const char* name_added,
void* user_data) void* user_data)
{ {
GBinderDefaultServiceManagerWatch* watch = user_data; GBinderServiceManagerAidlWatch* watch = user_data;
if (!g_strcmp0(name_added, watch->name)) { if (!g_strcmp0(name_added, watch->name)) {
GBinderServiceManager* manager = GBinderServiceManager* manager =
@@ -110,10 +97,10 @@ gbinder_defaultservicemanager_watch_proc(
static static
gboolean gboolean
gbinder_defaultservicemanager_watch_notify( gbinder_servicemanager_aidl_watch_notify(
gpointer user_data) gpointer user_data)
{ {
GBinderDefaultServiceManagerWatch* watch = user_data; GBinderServiceManagerAidlWatch* watch = user_data;
GBinderServiceManager* manager = gbinder_servicepoll_manager(watch->poll); GBinderServiceManager* manager = gbinder_servicepoll_manager(watch->poll);
char* name = g_strdup(watch->name); char* name = g_strdup(watch->name);
@@ -126,54 +113,75 @@ gbinder_defaultservicemanager_watch_notify(
static static
void void
gbinder_defaultservicemanager_watch_free( gbinder_servicemanager_aidl_watch_free(
gpointer user_data) gpointer user_data)
{ {
GBinderDefaultServiceManagerWatch* watch = user_data; GBinderServiceManagerAidlWatch* watch = user_data;
gbinder_timeout_remove(watch->notify); gbinder_timeout_remove(watch->notify);
gbinder_servicepoll_remove_handler(watch->poll, watch->handler_id); gbinder_servicepoll_remove_handler(watch->poll, watch->handler_id);
gbinder_servicepoll_unref(watch->poll); gbinder_servicepoll_unref(watch->poll);
g_free(watch->name); g_free(watch->name);
g_slice_free(GBinderDefaultServiceManagerWatch, watch); g_slice_free(GBinderServiceManagerAidlWatch, watch);
} }
static static
GBinderDefaultServiceManagerWatch* GBinderServiceManagerAidlWatch*
gbinder_defaultservicemanager_watch_new( gbinder_servicemanager_aidl_watch_new(
GBinderDefaultServiceManager* manager, GBinderServiceManagerAidl* self,
const char* name) const char* name)
{ {
GBinderDefaultServiceManagerWatch* watch = GBinderServiceManagerAidlPriv* priv = self->priv;
g_slice_new0(GBinderDefaultServiceManagerWatch); GBinderServiceManagerAidlWatch* watch =
g_slice_new0(GBinderServiceManagerAidlWatch);
watch->name = g_strdup(name); watch->name = g_strdup(name);
watch->poll = gbinder_servicepoll_new(&manager->manager, &manager->poll); watch->poll = gbinder_servicepoll_new(&self->manager, &priv->poll);
watch->handler_id = gbinder_servicepoll_add_handler(watch->poll, watch->handler_id = gbinder_servicepoll_add_handler(priv->poll,
gbinder_defaultservicemanager_watch_proc, watch); gbinder_servicemanager_aidl_watch_proc, watch);
return watch; return watch;
} }
static static
GBinderLocalRequest* GBinderLocalRequest*
gbinder_servicemanager_list_services_req( gbinder_servicemanager_aidl_list_services_req(
GBinderServiceManager* self, GBinderClient* client,
gint32 index) gint32 index)
{ {
return gbinder_local_request_append_int32 GBinderLocalRequest* req = gbinder_client_new_request(client);
(gbinder_client_new_request(self->client), index);
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 static
char** char**
gbinder_defaultservicemanager_list( gbinder_servicemanager_aidl_list(
GBinderServiceManager* self) GBinderServiceManager* manager)
{ {
GPtrArray* list = g_ptr_array_new(); 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; 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) { LIST_SERVICES_TRANSACTION, req, NULL)) != NULL) {
char* service = gbinder_remote_reply_read_string16(reply); char* service = gbinder_remote_reply_read_string16(reply);
@@ -181,7 +189,7 @@ gbinder_defaultservicemanager_list(
if (service) { if (service) {
g_ptr_array_add(list, service); g_ptr_array_add(list, service);
gbinder_local_request_unref(req); gbinder_local_request_unref(req);
req = gbinder_servicemanager_list_services_req(self, list->len); req = klass->list_services_req(client, list->len);
} else { } else {
break; break;
} }
@@ -194,7 +202,7 @@ gbinder_defaultservicemanager_list(
static static
GBinderRemoteObject* GBinderRemoteObject*
gbinder_defaultservicemanager_get_service( gbinder_servicemanager_aidl_get_service(
GBinderServiceManager* self, GBinderServiceManager* self,
const char* name, const char* name,
int* status) int* status)
@@ -215,20 +223,16 @@ gbinder_defaultservicemanager_get_service(
static static
int int
gbinder_defaultservicemanager_add_service( gbinder_servicemanager_aidl_add_service(
GBinderServiceManager* self, GBinderServiceManager* manager,
const char* name, const char* name,
GBinderLocalObject* obj) GBinderLocalObject* obj)
{ {
int status; int status;
GBinderRemoteReply* reply; GBinderClient* client = manager->client;
GBinderLocalRequest* req = gbinder_client_new_request(self->client); GBinderLocalRequest* req = GBINDER_SERVICEMANAGER_AIDL_GET_CLASS
(manager)->add_service_req(client, name, obj);
gbinder_local_request_append_string16(req, name); GBinderRemoteReply* reply = gbinder_client_transact_sync_reply(client,
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
reply = gbinder_client_transact_sync_reply(self->client,
ADD_SERVICE_TRANSACTION, req, &status); ADD_SERVICE_TRANSACTION, req, &status);
gbinder_remote_reply_unref(reply); gbinder_remote_reply_unref(reply);
@@ -238,7 +242,7 @@ gbinder_defaultservicemanager_add_service(
static static
GBINDER_SERVICEMANAGER_NAME_CHECK GBINDER_SERVICEMANAGER_NAME_CHECK
gbinder_defaultservicemanager_check_name( gbinder_servicemanager_aidl_check_name(
GBinderServiceManager* self, GBinderServiceManager* self,
const char* name) const char* name)
{ {
@@ -247,69 +251,84 @@ gbinder_defaultservicemanager_check_name(
static static
gboolean gboolean
gbinder_defaultservicemanager_watch( gbinder_servicemanager_aidl_watch(
GBinderServiceManager* manager, GBinderServiceManager* manager,
const char* name) const char* name)
{ {
GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(manager); GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
GBinderDefaultServiceManagerWatch* watch = GBinderServiceManagerAidlPriv* priv = self->priv;
gbinder_defaultservicemanager_watch_new(self, name); 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)) { if (gbinder_servicepoll_is_known_name(watch->poll, name)) {
watch->notify = gbinder_idle_add watch->notify = gbinder_idle_add
(gbinder_defaultservicemanager_watch_notify, watch); (gbinder_servicemanager_aidl_watch_notify, watch);
} }
return TRUE; return TRUE;
} }
static static
void void
gbinder_defaultservicemanager_unwatch( gbinder_servicemanager_aidl_unwatch(
GBinderServiceManager* manager, GBinderServiceManager* manager,
const char* name) const char* name)
{ {
g_hash_table_remove(GBINDER_DEFAULTSERVICEMANAGER(manager)->watch_table, GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
name); GBinderServiceManagerAidlPriv* priv = self->priv;
g_hash_table_remove(priv->watch_table, name);
} }
static static
void void
gbinder_defaultservicemanager_init( gbinder_servicemanager_aidl_init(
GBinderDefaultServiceManager* self) GBinderServiceManagerAidl* self)
{ {
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal, GBinderServiceManagerAidlPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
NULL, gbinder_defaultservicemanager_watch_free); 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 static
void void
gbinder_defaultservicemanager_finalize( gbinder_servicemanager_aidl_finalize(
GObject* object) 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); G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
} }
static static
void void
gbinder_defaultservicemanager_class_init( gbinder_servicemanager_aidl_class_init(
GBinderDefaultServiceManagerClass* klass) GBinderServiceManagerAidlClass* klass)
{ {
klass->iface = DEFAULTSERVICEMANAGER_IFACE; GBinderServiceManagerClass* manager = GBINDER_SERVICEMANAGER_CLASS(klass);
klass->default_device = GBINDER_DEFAULT_BINDER; GObjectClass* object = G_OBJECT_CLASS(klass);
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
klass->list = gbinder_defaultservicemanager_list; g_type_class_add_private(klass, sizeof(GBinderServiceManagerAidlPriv));
klass->get_service = gbinder_defaultservicemanager_get_service; klass->list_services_req = gbinder_servicemanager_aidl_list_services_req;
klass->add_service = gbinder_defaultservicemanager_add_service; klass->add_service_req = gbinder_servicemanager_aidl_add_service_req;
klass->check_name = gbinder_defaultservicemanager_check_name;
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 */ /* normalize_name is not needed */
klass->watch = gbinder_defaultservicemanager_watch; manager->watch = gbinder_servicemanager_aidl_watch;
klass->unwatch = gbinder_defaultservicemanager_unwatch; manager->unwatch = gbinder_servicemanager_aidl_unwatch;
G_OBJECT_CLASS(klass)->finalize = gbinder_defaultservicemanager_finalize;
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-2020 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -31,7 +31,6 @@
*/ */
#include "gbinder_servicemanager_p.h" #include "gbinder_servicemanager_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_log.h" #include "gbinder_log.h"
#include <gbinder_client.h> #include <gbinder_client.h>
@@ -42,30 +41,30 @@
#include <gbinder_reader.h> #include <gbinder_reader.h>
#include <errno.h> #include <errno.h>
#include <pthread.h>
typedef struct gbinder_hwservicemanager_watch { typedef struct gbinder_servicemanager_hidl_watch {
char* name; char* name;
GBinderLocalObject* callback; GBinderLocalObject* callback;
} GBinderHwServiceManagerWatch; } GBinderServiceManagerHidlWatch;
typedef GBinderServiceManagerClass GBinderHwServiceManagerClass; typedef GBinderServiceManagerClass GBinderServiceManagerHidlClass;
typedef struct gbinder_hwservicemanager { typedef struct gbinder_servicemanager_hidl {
GBinderServiceManager manager; GBinderServiceManager manager;
GHashTable* watch_table; GHashTable* watch_table;
} GBinderHwServiceManager; } GBinderServiceManagerHidl;
G_DEFINE_TYPE(GBinderHwServiceManager, G_DEFINE_TYPE(GBinderServiceManagerHidl,
gbinder_hwservicemanager, gbinder_servicemanager_hidl,
GBINDER_TYPE_SERVICEMANAGER) GBINDER_TYPE_SERVICEMANAGER)
#define PARENT_CLASS gbinder_hwservicemanager_parent_class #define PARENT_CLASS gbinder_servicemanager_hidl_parent_class
#define GBINDER_TYPE_HWSERVICEMANAGER (gbinder_hwservicemanager_get_type()) #define GBINDER_TYPE_SERVICEMANAGER_HIDL \
#define GBINDER_HWSERVICEMANAGER(obj) \ gbinder_servicemanager_hidl_get_type()
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_HWSERVICEMANAGER, \ #define GBINDER_SERVICEMANAGER_HIDL(obj) \
GBinderHwServiceManager) 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, GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
ADD_TRANSACTION, ADD_TRANSACTION,
GET_TRANSPORT_TRANSACTION, GET_TRANSPORT_TRANSACTION,
@@ -76,18 +75,18 @@ enum gbinder_hwservicemanager_calls {
REGISTER_PASSTHROUGH_CLIENT_TRANSACTION REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
}; };
enum gbinder_hwservicemanager_notifications { enum gbinder_servicemanager_hidl_notifications {
ON_REGISTRATION_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION ON_REGISTRATION_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION
}; };
#define HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager" #define SERVICEMANAGER_HIDL_IFACE "android.hidl.manager@1.0::IServiceManager"
#define HWSERVICEMANAGER_NOTIFICATION_IFACE \ #define SERVICEMANAGER_HIDL_NOTIFICATION_IFACE \
"android.hidl.manager@1.0::IServiceNotification" "android.hidl.manager@1.0::IServiceNotification"
static static
void void
gbinder_hwservicemanager_handle_registration( gbinder_servicemanager_hidl_handle_registration(
GBinderHwServiceManager* self, GBinderServiceManagerHidl* self,
GBinderReader* reader) GBinderReader* reader)
{ {
char* fqname = gbinder_reader_read_hidl_string(reader); char* fqname = gbinder_reader_read_hidl_string(reader);
@@ -111,7 +110,7 @@ gbinder_hwservicemanager_handle_registration(
static static
GBinderLocalReply* GBinderLocalReply*
gbinder_hwservicemanager_notification( gbinder_servicemanager_hidl_notification(
GBinderLocalObject* obj, GBinderLocalObject* obj,
GBinderRemoteRequest* req, GBinderRemoteRequest* req,
guint code, guint code,
@@ -119,22 +118,22 @@ gbinder_hwservicemanager_notification(
int* status, int* status,
void* user_data) void* user_data)
{ {
GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(user_data); GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(user_data);
const char* iface = gbinder_remote_request_interface(req); 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; GBinderReader reader;
gbinder_remote_request_init_reader(req, &reader); gbinder_remote_request_init_reader(req, &reader);
switch (code) { switch (code) {
case ON_REGISTRATION_TRANSACTION: case ON_REGISTRATION_TRANSACTION:
GDEBUG(HWSERVICEMANAGER_NOTIFICATION_IFACE " %u onRegistration", GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u onRegistration",
code); code);
gbinder_hwservicemanager_handle_registration(self, &reader); gbinder_servicemanager_hidl_handle_registration(self, &reader);
*status = GBINDER_STATUS_OK; *status = GBINDER_STATUS_OK;
break; break;
default: default:
GDEBUG(HWSERVICEMANAGER_NOTIFICATION_IFACE " %u", code); GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u", code);
*status = GBINDER_STATUS_FAILED; *status = GBINDER_STATUS_FAILED;
break; break;
} }
@@ -145,17 +144,9 @@ gbinder_hwservicemanager_notification(
return NULL; return NULL;
} }
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_hwservicemanager_get_type(), dev);
}
static static
char** char**
gbinder_hwservicemanager_list( gbinder_servicemanager_hidl_list(
GBinderServiceManager* self) GBinderServiceManager* self)
{ {
GBinderLocalRequest* req = gbinder_client_new_request(self->client); GBinderLocalRequest* req = gbinder_client_new_request(self->client);
@@ -184,7 +175,7 @@ gbinder_hwservicemanager_list(
static static
GBinderRemoteObject* GBinderRemoteObject*
gbinder_hwservicemanager_get_service( gbinder_servicemanager_hidl_get_service(
GBinderServiceManager* self, GBinderServiceManager* self,
const char* fqinstance, const char* fqinstance,
int* status) int* status)
@@ -231,7 +222,7 @@ gbinder_hwservicemanager_get_service(
static static
int int
gbinder_hwservicemanager_add_service( gbinder_servicemanager_hidl_add_service(
GBinderServiceManager* self, GBinderServiceManager* self,
const char* name, const char* name,
GBinderLocalObject* obj) GBinderLocalObject* obj)
@@ -254,10 +245,10 @@ gbinder_hwservicemanager_add_service(
static static
void void
gbinder_hwservicemanager_watch_free( gbinder_servicemanager_hidl_watch_free(
gpointer data) gpointer data)
{ {
GBinderHwServiceManagerWatch* watch = data; GBinderServiceManagerHidlWatch* watch = data;
g_free(watch->name); g_free(watch->name);
gbinder_local_object_drop(watch->callback); gbinder_local_object_drop(watch->callback);
@@ -266,7 +257,7 @@ gbinder_hwservicemanager_watch_free(
static static
GBINDER_SERVICEMANAGER_NAME_CHECK GBINDER_SERVICEMANAGER_NAME_CHECK
gbinder_hwservicemanager_check_name( gbinder_servicemanager_hidl_check_name(
GBinderServiceManager* self, GBinderServiceManager* self,
const char* name) const char* name)
{ {
@@ -287,32 +278,32 @@ gbinder_hwservicemanager_check_name(
static static
char* char*
gbinder_hwservicemanager_normalize_name( gbinder_servicemanager_hidl_normalize_name(
GBinderServiceManager* self, GBinderServiceManager* self,
const char* name) 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); return g_strndup(name, strchr(name, '/') - name);
} }
static static
gboolean gboolean
gbinder_hwservicemanager_watch( gbinder_servicemanager_hidl_watch(
GBinderServiceManager* manager, GBinderServiceManager* manager,
const char* name) const char* name)
{ {
GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(manager); GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(manager);
GBinderLocalRequest* req = gbinder_client_new_request(manager->client); GBinderLocalRequest* req = gbinder_client_new_request(manager->client);
GBinderRemoteReply* reply; GBinderRemoteReply* reply;
GBinderHwServiceManagerWatch* watch = GBinderServiceManagerHidlWatch* watch =
g_new0(GBinderHwServiceManagerWatch, 1); g_new0(GBinderServiceManagerHidlWatch, 1);
gboolean success = FALSE; gboolean success = FALSE;
int status; int status;
watch->name = g_strdup(name); watch->name = g_strdup(name);
watch->callback = gbinder_servicemanager_new_local_object(manager, watch->callback = gbinder_servicemanager_new_local_object(manager,
HWSERVICEMANAGER_NOTIFICATION_IFACE, SERVICEMANAGER_HIDL_NOTIFICATION_IFACE,
gbinder_hwservicemanager_notification, self); gbinder_servicemanager_hidl_notification, self);
g_hash_table_replace(self->watch_table, watch->name, watch); g_hash_table_replace(self->watch_table, watch->name, watch);
/* registerForNotifications(string fqName, string name, /* registerForNotifications(string fqName, string name,
@@ -344,28 +335,29 @@ gbinder_hwservicemanager_watch(
static static
void void
gbinder_hwservicemanager_unwatch( gbinder_servicemanager_hidl_unwatch(
GBinderServiceManager* manager, GBinderServiceManager* manager,
const char* name) 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 static
void void
gbinder_hwservicemanager_init( gbinder_servicemanager_hidl_init(
GBinderHwServiceManager* self) GBinderServiceManagerHidl* self)
{ {
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal, 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 static
void void
gbinder_hwservicemanager_finalize( gbinder_servicemanager_hidl_finalize(
GObject* object) GObject* object)
{ {
GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(object); GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(object);
g_hash_table_destroy(self->watch_table); g_hash_table_destroy(self->watch_table);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object); G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
@@ -373,21 +365,20 @@ gbinder_hwservicemanager_finalize(
static static
void void
gbinder_hwservicemanager_class_init( gbinder_servicemanager_hidl_class_init(
GBinderHwServiceManagerClass* klass) GBinderServiceManagerHidlClass* klass)
{ {
klass->iface = HWSERVICEMANAGER_IFACE; klass->iface = SERVICEMANAGER_HIDL_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER; klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;
klass->list = gbinder_hwservicemanager_list; klass->list = gbinder_servicemanager_hidl_list;
klass->get_service = gbinder_hwservicemanager_get_service; klass->get_service = gbinder_servicemanager_hidl_get_service;
klass->add_service = gbinder_hwservicemanager_add_service; klass->add_service = gbinder_servicemanager_hidl_add_service;
klass->check_name = gbinder_hwservicemanager_check_name; klass->check_name = gbinder_servicemanager_hidl_check_name;
klass->normalize_name = gbinder_hwservicemanager_normalize_name; klass->normalize_name = gbinder_servicemanager_hidl_normalize_name;
klass->watch = gbinder_hwservicemanager_watch; klass->watch = gbinder_servicemanager_hidl_watch;
klass->unwatch = gbinder_hwservicemanager_unwatch; klass->unwatch = gbinder_servicemanager_hidl_unwatch;
G_OBJECT_CLASS(klass)->finalize = gbinder_hwservicemanager_finalize; 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* iface;
const char* default_device; const char* default_device;
const GBinderRpcProtocol* rpc_protocol;
/* Methods (synchronous) */ /* Methods (synchronous) */
char** (*list)(GBinderServiceManager* self); char** (*list)(GBinderServiceManager* self);
@@ -86,6 +85,9 @@ typedef struct gbinder_servicemanager_class {
GType gbinder_servicemanager_get_type(void) GBINDER_INTERNAL; GType gbinder_servicemanager_get_type(void) GBINDER_INTERNAL;
#define GBINDER_TYPE_SERVICEMANAGER (gbinder_servicemanager_get_type()) #define GBINDER_TYPE_SERVICEMANAGER (gbinder_servicemanager_get_type())
#define GBINDER_SERVICEMANAGER_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
GBinderServiceManager* GBinderServiceManager*
gbinder_servicemanager_new_with_type( gbinder_servicemanager_new_with_type(
@@ -99,6 +101,19 @@ gbinder_servicemanager_service_registered(
const char* name) const char* name)
GBINDER_INTERNAL; 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 */ #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_INLINE_FUNC static inline
#define GBINDER_INTERNAL G_GNUC_INTERNAL #define GBINDER_INTERNAL G_GNUC_INTERNAL
#define GBINDER_DESTRUCTOR __attribute__((destructor))
#define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4) #define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
#define GBINDER_PING_TRANSACTION GBINDER_TRANSACTION('P','N','G') #define GBINDER_PING_TRANSACTION GBINDER_TRANSACTION('P','N','G')

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2019 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -30,6 +30,8 @@
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "test_binder.h"
#include "gbinder_local_object.h"
#include "gbinder_system.h" #include "gbinder_system.h"
#define GLOG_MODULE_NAME test_binder_log #define GLOG_MODULE_NAME test_binder_log
@@ -47,19 +49,26 @@ static GHashTable* test_fd_map = NULL;
static GHashTable* test_node_map = NULL; static GHashTable* test_node_map = NULL;
static GPrivate test_looper; static GPrivate test_looper;
#define public_fd fd[0] G_LOCK_DEFINE_STATIC(test_binder);
#define private_fd fd[1]
#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_VERSION _IOWR('b', 9, gint32)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, guint32) #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_ONE_WAY 0x01
#define TF_ROOT_OBJECT 0x04 #define TF_ROOT_OBJECT 0x04
#define TF_STATUS_CODE 0x08 #define TF_STATUS_CODE 0x08
#define TF_ACCEPT_FDS 0x10 #define TF_ACCEPT_FDS 0x10
typedef struct test_binder_io TestBinderIo; typedef struct test_binder_io TestBinderIo;
typedef struct test_binder TestBinder;
typedef typedef
void void
@@ -77,23 +86,33 @@ typedef struct test_binder_submit_thread {
} TestBinderSubmitThread; } TestBinderSubmitThread;
typedef struct test_binder_node { typedef struct test_binder_node {
int fd;
char* path; char* path;
int refcount; TestBinder* binder;
const TestBinderIo* io; gboolean looper_enabled;
GHashTable* destroy_map;
} TestBinderNode; } TestBinderNode;
typedef struct test_binder { typedef struct test_binder_fd {
int fd;
GHashTable* destroy_map;
TestBinderNode* node; 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; TestBinderSubmitThread* submit_thread;
gboolean looper_enabled; GMutex mutex;
int fd[2]; gboolean passthrough;
TestBinderNode node[2];
} TestBinder; } TestBinder;
struct test_binder_io { struct test_binder_io {
int version; int version;
int write_read_request; 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 { typedef struct binder_write_read_64 {
@@ -128,6 +147,13 @@ typedef struct binder_handle_cookie_64 {
guint64 cookie; guint64 cookie;
} __attribute__((packed)) BinderHandleCookie64; } __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_TRANSACTION_64 _IOW('c', 0, BinderTransactionData64)
#define BC_REPLY_64 _IOW('c', 1, BinderTransactionData64) #define BC_REPLY_64 _IOW('c', 1, BinderTransactionData64)
#define BC_FREE_BUFFER_64 _IOW('c', 3, guint64) #define BC_FREE_BUFFER_64 _IOW('c', 3, guint64)
@@ -259,74 +285,202 @@ test_binder_submit_later(
static static
void void
test_io_free_buffer( test_io_free_buffer(
TestBinder* binder, TestBinderFd* fd,
void* ptr) void* ptr)
{ {
if (ptr) { if (ptr) {
TestBinderNode* node = binder->node; GDestroyNotify destroy;
GDestroyNotify destroy = g_hash_table_lookup(node->destroy_map, ptr);
G_LOCK(test_binder);
destroy = g_hash_table_lookup(fd->destroy_map, ptr);
if (destroy) { if (destroy) {
g_hash_table_remove(node->destroy_map, ptr); g_hash_table_remove(fd->destroy_map, ptr);
destroy(ptr); destroy(ptr);
} else { } else {
g_free(ptr); 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 static
int int
test_io_handle_write_read_64( test_io_handle_write_read_64(
TestBinder* binder, TestBinderFd* fd,
void* data) void* data)
{ {
TestBinderNode* node = fd->node;
TestBinder* binder = node->binder;
BinderWriteRead64* wr = data; BinderWriteRead64* wr = data;
gssize bytes_left = wr->write_size - wr->write_consumed; gssize bytes_left = wr->write_size - wr->write_consumed;
const guint8* write_ptr = (void*)(gsize) const guint8* write_ptr = (void*)(gsize)(wr->write_buffer +
(wr->write_buffer + wr->write_consumed); wr->write_consumed);
gboolean is_looper; gboolean is_looper;
while (bytes_left >= sizeof(guint32)) { while (bytes_left >= sizeof(guint32)) {
const guint cmd = *(guint32*)write_ptr; const guint cmd = *(guint32*)write_ptr;
const guint cmdsize = _IOC_SIZE(cmd); 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)); GASSERT(bytes_left >= bytes_to_write);
if (bytes_left >= (sizeof(guint32) + cmdsize)) { if (bytes_left >= bytes_to_write) {
wr->write_consumed += sizeof(guint32); gssize bytes_written = bytes_to_write;
write_ptr += sizeof(guint32);
bytes_left -= sizeof(guint32);
switch (cmd) { switch (cmd) {
case BC_TRANSACTION_64:
case BC_REPLY_64:
/* Is there anything special about transactions and replies? */
break;
case BC_FREE_BUFFER_64: case BC_FREE_BUFFER_64:
test_io_free_buffer(binder, test_io_free_buffer(fd, GSIZE_TO_POINTER(*(guint64*)cmddata));
GSIZE_TO_POINTER(*(guint64*)write_ptr));
break; break;
case BC_ENTER_LOOPER: case BC_ENTER_LOOPER:
g_private_set(&test_looper, GINT_TO_POINTER(TRUE)); g_private_set(&test_looper, GINT_TO_POINTER(TRUE));
break; break;
case BC_EXIT_LOOPER: case BC_EXIT_LOOPER:
g_private_set(&test_looper, NULL); 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:
break; break;
default: default:
#pragma message("TODO: implement more BINDER_WRITE_READ commands") if (binder->passthrough) {
GDEBUG("Unhandled command 0x%08x", cmd); bytes_written = test_io_passthough_write_64(fd,
write_ptr, bytes_to_write);
}
break; break;
} }
wr->write_consumed += cmdsize; if (bytes_written >= 0) {
write_ptr += cmdsize; wr->write_consumed += bytes_written;
bytes_left -= cmdsize; write_ptr += bytes_written;
bytes_left -= bytes_written;
} else {
GDEBUG("Write failed, %s", strerror(errno));
return -1;
}
} else { } else {
/* Partial command in the buffer */ /* Partial command in the buffer */
errno = EINVAL; errno = EINVAL;
@@ -335,17 +489,17 @@ test_io_handle_write_read_64(
} }
is_looper = g_private_get(&test_looper) ? TRUE : FALSE; 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 */ /* Now read the data from the socket */
int bytes_available = 0; int bytes_available = 0;
int err = ioctl(binder->public_fd, FIONREAD, &bytes_available); int err = ioctl(fd->fd, FIONREAD, &bytes_available);
if (err >= 0) { if (err >= 0) {
int bytes_read = 0; int bytes_read = 0;
if (bytes_available >= 4) { if (bytes_available >= 4) {
bytes_read = read(binder->public_fd, bytes_read = read(fd->fd, (void*)(gsize)
(void*)(gsize)(wr->read_buffer + wr->read_consumed), (wr->read_buffer + wr->read_consumed),
wr->read_size - wr->read_consumed); wr->read_size - wr->read_consumed);
} else { } else {
struct timespec wait; struct timespec wait;
@@ -387,26 +541,26 @@ test_binder_ioctl_version(
TestBinder* binder, TestBinder* binder,
int* version) int* version)
{ {
*version = binder->node->io->version; *version = binder->io->version;
return 0; return 0;
} }
static static
void TestBinderFd*
test_binder_node_unref( test_binder_fd_from_fd(
TestBinderNode* node) int fd)
{ {
node->refcount--; TestBinderFd* binder_fd = NULL;
if (!node->refcount) {
g_hash_table_remove(test_node_map, node->path); G_LOCK(test_binder);
g_hash_table_destroy(node->destroy_map); GASSERT(test_fd_map);
g_free(node->path); if (test_fd_map) {
g_free(node); binder_fd = g_hash_table_lookup(test_fd_map, GINT_TO_POINTER(fd));
} GASSERT(binder_fd);
if (!g_hash_table_size(test_node_map)) {
g_hash_table_unref(test_node_map);
test_node_map = NULL;
} }
G_UNLOCK(test_binder);
return binder_fd;
} }
static static
@@ -414,13 +568,9 @@ TestBinder*
test_binder_from_fd( test_binder_from_fd(
int fd) int fd)
{ {
TestBinder* binder = NULL; TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
GASSERT(test_fd_map);
if (test_fd_map) { return binder_fd ? binder_fd->node->binder : NULL;
binder = g_hash_table_lookup(test_fd_map, GINT_TO_POINTER(fd));
GASSERT(binder);
}
return binder;
} }
static static
@@ -435,11 +585,22 @@ void
test_binder_set_looper_enabled( test_binder_set_looper_enabled(
int fd, int fd,
gboolean enabled) 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); TestBinder* binder = test_binder_from_fd(fd);
g_assert(binder); g_assert(binder);
binder->looper_enabled = enabled; binder->passthrough = passthrough;
} }
void void
@@ -448,13 +609,13 @@ test_binder_set_destroy(
gpointer ptr, gpointer ptr,
GDestroyNotify destroy) GDestroyNotify destroy)
{ {
TestBinder* binder = test_binder_from_fd(fd); TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
if (binder) { if (binder_fd) {
TestBinderNode* node = binder->node; G_LOCK(test_binder);
g_hash_table_replace(binder_fd->destroy_map, ptr,
g_hash_table_replace(node->destroy_map, ptr,
destroy ? destroy : test_io_destroy_none); 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); 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 int
gbinder_system_open( gbinder_system_open(
const char* path, const char* path,
int flags) int flags)
{ {
if (path && g_str_has_prefix(path, "/dev") && static const char binder_suffix[] = "binder";
g_str_has_suffix(path, "binder")) { static const char binder_private_suffix[] = "binder-private";
TestBinderNode* node = NULL; static const char private_suffix[] = "-private";
TestBinder* binder = NULL;
int fd; 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) { if (!test_node_map) {
test_node_map = g_hash_table_new(g_str_hash, g_str_equal); 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);
} }
fd = test_binder_fd_new(node);
binder = g_new0(TestBinder, 1);
binder->node = node;
socketpair(AF_UNIX, SOCK_STREAM, 0, binder->fd);
fd = binder->public_fd;
if (!test_fd_map) { 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); g_hash_table_replace(test_fd_map, GINT_TO_POINTER(fd->fd), fd);
return fd; G_UNLOCK(test_binder);
return fd->fd;
} else { } else {
errno = ENOENT; errno = ENOENT;
return -1; return -1;
@@ -752,23 +1088,22 @@ int
gbinder_system_close( gbinder_system_close(
int fd) int fd)
{ {
TestBinder* binder = test_binder_from_fd(fd); int ret;
if (binder) { G_LOCK(test_binder);
g_hash_table_remove(test_fd_map, GINT_TO_POINTER(fd)); if (g_hash_table_remove(test_fd_map, GINT_TO_POINTER(fd))) {
if (!g_hash_table_size(test_fd_map)) { if (!g_hash_table_size(test_fd_map)) {
g_hash_table_unref(test_fd_map); g_hash_table_unref(test_fd_map);
test_fd_map = NULL; test_fd_map = NULL;
} }
test_binder_submit_thread_free(binder->submit_thread); ret = 0;
test_binder_node_unref(binder->node); } else {
close(binder->public_fd); errno = EBADF;
close(binder->private_fd); ret = -1;
g_free(binder);
return 0;
} }
errno = EBADF; G_UNLOCK(test_binder);
return -1;
return ret;
} }
int int
@@ -777,9 +1112,11 @@ gbinder_system_ioctl(
int request, int request,
void* data) void* data)
{ {
TestBinder* binder = test_binder_from_fd(fd); TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
if (binder) {
const TestBinderIo* io = binder->node->io; if (binder_fd) {
TestBinder* binder = binder_fd->node->binder;
const TestBinderIo* io = binder->io;
switch (request) { switch (request) {
case BINDER_VERSION: case BINDER_VERSION:
@@ -788,7 +1125,7 @@ gbinder_system_ioctl(
return 0; return 0;
default: default:
if (request == io->write_read_request) { if (request == io->write_read_request) {
return io->handle_write_read(binder, data); return io->handle_write_read(binder_fd, data);
} else { } else {
errno = EINVAL; errno = EINVAL;
return -1; return -1;

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2019 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -35,6 +35,8 @@
#include "test_common.h" #include "test_common.h"
typedef struct test_binder TestBinder;
void void
test_binder_br_noop( test_binder_br_noop(
int fd); int fd);
@@ -116,12 +118,33 @@ test_binder_set_looper_enabled(
int fd, int fd,
gboolean enabled); 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 void
test_binder_set_destroy( test_binder_set_destroy(
int fd, int fd,
gpointer ptr, gpointer ptr,
GDestroyNotify destroy); GDestroyNotify destroy);
void
test_binder_exit_wait(
void);
#endif /* TEST_BINDER_H */ #endif /* TEST_BINDER_H */
/* /*

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may * 3. Neither the names of the copyright holders nor the names of its
* be used to endorse or promote products derived from this software * contributors may be used to endorse or promote products derived
* without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -58,6 +58,12 @@ void
test_quit_later( test_quit_later(
GMainLoop* loop); GMainLoop* loop);
/* Quits the event loop after n iterations */
void
test_quit_later_n(
GMainLoop* loop,
guint n);
#define TEST_TIMEOUT_SEC (20) #define TEST_TIMEOUT_SEC (20)
/* Helper macros */ /* Helper macros */

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may * 3. Neither the names of the copyright holders nor the names of its
* be used to endorse or promote products derived from this software * contributors may be used to endorse or promote products derived
* without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -34,6 +34,11 @@
#include <gutil_log.h> #include <gutil_log.h>
typedef struct test_quit_later_data{
GMainLoop* loop;
guint n;
} TestQuitLaterData;
static static
gboolean gboolean
test_timeout_expired( test_timeout_expired(
@@ -43,6 +48,46 @@ test_timeout_expired(
return G_SOURCE_REMOVE; 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 static
gboolean gboolean
test_quit_later_cb( test_quit_later_cb(

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2019 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -152,7 +152,7 @@ test_basic(
{ {
const char* const ifaces_foo[] = { "foo", NULL }; const char* const ifaces_foo[] = { "foo", NULL };
const char* const ifaces_bar[] = { "bar", 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); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderLocalObject* foo; GBinderLocalObject* foo;
GBinderLocalObject* bar; GBinderLocalObject* bar;
@@ -201,7 +201,7 @@ test_ping(
int status = INT_MAX; int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER; const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev); 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); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0); GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL); GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
@@ -247,7 +247,7 @@ test_interface(
const char* dev = GBINDER_DEFAULT_HWBINDER; const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev); const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
const char* const ifaces[] = { "x", NULL }; 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); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0); GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL); GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
@@ -296,7 +296,7 @@ test_hidl_ping(
int status = INT_MAX; int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER; const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev); 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); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0); GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL); GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
@@ -346,7 +346,7 @@ test_get_descriptor(
int status = INT_MAX; int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER; const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev); 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); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0); GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL); 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* dev = GBINDER_DEFAULT_HWBINDER;
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL }; const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev); 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); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0); GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL); GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
@@ -476,7 +476,7 @@ test_custom_iface(
int count = 0, status = INT_MAX; int count = 0, status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER; const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev); 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); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0); GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
@@ -583,7 +583,7 @@ test_reply_status(
int count = 0, status = 0; int count = 0, status = 0;
const char* dev = GBINDER_DEFAULT_HWBINDER; const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev); 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); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0); GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
@@ -624,7 +624,7 @@ void
test_increfs( test_increfs(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_local_object_new GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL); (ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -666,7 +666,7 @@ void
test_decrefs( test_decrefs(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_local_object_new GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL); (ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -708,7 +708,7 @@ void
test_acquire( test_acquire(
void) void)
{ {
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_local_object_new GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL); (ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -750,7 +750,7 @@ void
test_release( test_release(
void) 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); GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver); int fd = gbinder_driver_fd(ipc->driver);

View File

@@ -399,7 +399,7 @@ test_local_object(
GBinderLocalReply* reply; GBinderLocalReply* reply;
GBinderOutputData* data; GBinderOutputData* data;
GUtilIntArray* offsets; 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 }; const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, 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-2020 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -33,6 +33,7 @@
#include "test_common.h" #include "test_common.h"
#include "gbinder_buffer_p.h" #include "gbinder_buffer_p.h"
#include "gbinder_config.h"
#include "gbinder_driver.h" #include "gbinder_driver.h"
#include "gbinder_io.h" #include "gbinder_io.h"
#include "gbinder_local_request_p.h" #include "gbinder_local_request_p.h"
@@ -43,36 +44,118 @@
#include "gbinder_writer.h" #include "gbinder_writer.h"
static TestOpt test_opt; static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-protocol-XXXXXX";
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16) #define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER) #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 { typedef struct test_header_data {
const char* name; const char* name;
const char* prot;
const char* dev; const char* dev;
const char* iface; const char* iface;
const guint8* header; const guint8* header;
guint header_size; guint header_size;
} TestHeaderData; } TestHeaderData;
static const guint8 test_header_binder [] = { static const guint8 test_header_aidl [] = {
TEST_INT32_BYTES(BINDER_RPC_FLAGS), TEST_INT32_BYTES(BINDER_RPC_FLAGS),
TEST_INT32_BYTES(3), TEST_INT32_BYTES(3),
TEST_INT16_BYTES('f'), TEST_INT16_BYTES('o'), TEST_INT16_BYTES('f'), TEST_INT16_BYTES('o'),
TEST_INT16_BYTES('o'), 0x00, 0x00 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 'f', 'o', 'o', 0x00
}; };
static const TestHeaderData test_header_tests[] = { static const TestHeaderData test_header_tests[] = {
{ "binder", GBINDER_DEFAULT_BINDER, "foo", { "aidl/ok", "aidl", GBINDER_DEFAULT_BINDER, "foo",
TEST_ARRAY_AND_SIZE(test_header_binder) }, TEST_ARRAY_AND_SIZE(test_header_aidl) },
{ "hwbinder", GBINDER_DEFAULT_HWBINDER, "foo", { "aidl/short", "aidl", GBINDER_DEFAULT_BINDER, NULL,
TEST_ARRAY_AND_SIZE(test_header_hwbinder) } 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 * device
*==========================================================================*/ *==========================================================================*/
@@ -82,12 +165,129 @@ void
test_device( test_device(
void) void)
{ {
g_assert(gbinder_rpc_protocol_for_device(NULL) == const GBinderRpcProtocol* p;
&gbinder_rpc_protocol_binder);
g_assert(gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER) == p = gbinder_rpc_protocol_for_device(NULL);
&gbinder_rpc_protocol_binder); g_assert(p);
g_assert(gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_HWBINDER) == g_assert_cmpstr(p->name, == ,"aidl");
&gbinder_rpc_protocol_hwbinder);
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 static
void void
test_no_header1( test_no_header1(
void) gconstpointer test_data)
{ {
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL, const TestData* test = test_data;
gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER), 0, 0); 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); gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION, NULL);
g_assert(!gbinder_remote_request_interface(req)); g_assert(!gbinder_remote_request_interface(req));
gbinder_remote_request_unref(req); gbinder_remote_request_unref(req);
test_config_cleanup(&config);
} }
/*==========================================================================* /*==========================================================================*
@@ -114,21 +321,35 @@ test_no_header1(
static static
void void
test_no_header2( test_no_header2(
void) gconstpointer test_data)
{ {
const GBinderRpcProtocol* p = &gbinder_rpc_protocol_binder; const TestData* test = test_data;
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, p); const GBinderRpcProtocol* p;
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL, p, 0, 0); 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_remote_request_set_data(req, GBINDER_DUMP_TRANSACTION,
gbinder_buffer_new(driver, gbinder_buffer_new(driver,
g_memdup(TEST_ARRAY_AND_SIZE(test_header_binder)), g_memdup(TEST_ARRAY_AND_SIZE(test_header_aidl)),
sizeof(test_header_binder), NULL)); sizeof(test_header_aidl), NULL));
g_assert(!gbinder_remote_request_interface(req)); g_assert(!gbinder_remote_request_interface(req));
gbinder_remote_request_unref(req); gbinder_remote_request_unref(req);
gbinder_driver_unref(driver); 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 * write_header
*==========================================================================*/ *==========================================================================*/
@@ -139,17 +360,24 @@ test_write_header(
gconstpointer test_data) gconstpointer test_data)
{ {
const TestHeaderData* test = test_data; const TestHeaderData* test = test_data;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(test->dev); const GBinderRpcProtocol* prot;
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL); GBinderLocalRequest* req;
GBinderOutputData* data; GBinderOutputData* data;
GBinderWriter writer; 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); gbinder_local_request_init_writer(req, &writer);
prot->write_rpc_header(&writer, test->iface); prot->write_rpc_header(&writer, test->iface);
data = gbinder_local_request_data(req); data = gbinder_local_request_data(req);
g_assert(data->bytes->len == test->header_size); g_assert(data->bytes->len == test->header_size);
g_assert(!memcmp(data->bytes->data, test->header, test->header_size)); g_assert(!memcmp(data->bytes->data, test->header, test->header_size));
gbinder_local_request_unref(req); gbinder_local_request_unref(req);
test_config_cleanup(&config);
} }
/*==========================================================================* /*==========================================================================*
@@ -162,16 +390,23 @@ test_read_header(
gconstpointer test_data) gconstpointer test_data)
{ {
const TestHeaderData* test = test_data; const TestHeaderData* test = test_data;
GBinderDriver* driver = gbinder_driver_new(test->dev, NULL); GBinderDriver* driver;
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL, GBinderRemoteRequest* req;
gbinder_rpc_protocol_for_device(test->dev), 0, 0); 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_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
gbinder_buffer_new(driver, g_memdup(test->header, test->header_size), gbinder_buffer_new(driver, g_memdup(test->header, test->header_size),
test->header_size, NULL)); 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_remote_request_unref(req);
gbinder_driver_unref(driver); 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_init(&argc, &argv, NULL);
g_test_add_func(TEST_("device"), test_device); g_test_add_func(TEST_("device"), test_device);
g_test_add_func(TEST_("no_header1"), test_no_header1); g_test_add_func(TEST_("config1"), test_config1);
g_test_add_func(TEST_("no_header2"), test_no_header2); 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++) { for (i = 0; i < G_N_ELEMENTS(test_header_tests); i++) {
const TestHeaderData* test = test_header_tests + i; const TestHeaderData* test = test_header_tests + i;
char* path; 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_test_add_data_func(path, test, test_read_header);
g_free(path); g_free(path);
path = g_strconcat(TEST_PREFIX, test->name, "/write_header", NULL); if (test->iface) {
g_test_add_data_func(path, test, test_write_header); path = g_strconcat(TEST_("write_header/"), test->name, NULL);
g_free(path); g_test_add_data_func(path, test, test_write_header);
g_free(path);
}
} }
test_init(&test_opt, argc, argv); test_init(&test_opt, argc, argv);

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2019 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -624,7 +624,7 @@ test_hidl_struct(
gconstpointer test_data) gconstpointer test_data)
{ {
const TestHidlStruct* test = 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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL); g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -828,7 +828,7 @@ test_hidl_vec(
gconstpointer test_data) gconstpointer test_data)
{ {
const TestHidlVec* test = 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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL); g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -934,7 +934,7 @@ test_hidl_string_err(
gconstpointer test_data) gconstpointer test_data)
{ {
const TestHidlStringErr* test = 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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL); g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -968,7 +968,7 @@ test_hidl_string_err_skip(
gconstpointer test_data) gconstpointer test_data)
{ {
const TestHidlStringErr* test = 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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL); g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -1013,7 +1013,7 @@ test_fd_ok(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0), TEST_INT32_BYTES(fd), TEST_INT32_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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL); g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -1053,7 +1053,7 @@ test_fd_shortbuf(
TEST_INT32_BYTES(BINDER_TYPE_FD), TEST_INT32_BYTES(BINDER_TYPE_FD),
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS) 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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL); g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -1087,7 +1087,7 @@ test_fd_badtype(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0), TEST_INT32_BYTES(fd), TEST_INT32_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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL); g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -1130,7 +1130,7 @@ test_dupfd_ok(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0), TEST_INT32_BYTES(fd), TEST_INT32_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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL); g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -1177,7 +1177,7 @@ test_dupfd_badtype(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0), TEST_INT32_BYTES(fd), TEST_INT32_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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL); g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -1220,7 +1220,7 @@ test_dupfd_badfd(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0), TEST_INT32_BYTES(fd), TEST_INT32_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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL); g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data; GBinderReaderData data;
@@ -1259,7 +1259,7 @@ test_hidl_string(
guint bufcount, guint bufcount,
const char* result) 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), GBinderBuffer* buf = gbinder_buffer_new(ipc->driver, g_memdup(input, size),
size, NULL); size, NULL);
GBinderRemoteObject* obj = 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),
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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL); g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderRemoteObject* obj = NULL; GBinderRemoteObject* obj = NULL;
@@ -1578,7 +1578,7 @@ test_object(
TEST_INT32_BYTES(BINDER_TYPE_HANDLE), TEST_INT32_BYTES(0), TEST_INT32_BYTES(BINDER_TYPE_HANDLE), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(1 /* handle*/), TEST_INT64_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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL); g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderRemoteObject* obj = NULL; GBinderRemoteObject* obj = NULL;
@@ -1636,7 +1636,7 @@ test_object_invalid(
TEST_INT32_BYTES(42 /* invalid type */), TEST_INT32_BYTES(0), TEST_INT32_BYTES(42 /* invalid type */), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(1 /* handle*/), TEST_INT64_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, GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL); g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderRemoteObject* obj = NULL; GBinderRemoteObject* obj = NULL;
@@ -1670,7 +1670,7 @@ test_vec(
void) void)
{ {
/* Using 64-bit I/O */ /* Using 64-bit I/O */
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderReaderData data; GBinderReaderData data;
GBinderReader reader; GBinderReader reader;
BinderObject64 obj; BinderObject64 obj;
@@ -1723,7 +1723,7 @@ test_hidl_string_vec(
gsize size, gsize size,
const char* const* result) 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), GBinderBuffer* buf = gbinder_buffer_new(ipc->driver, g_memdup(input, size),
size, NULL); size, NULL);
GBinderRemoteObject* obj = NULL; GBinderRemoteObject* obj = NULL;

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2019 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its * 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from * contributors may be used to endorse or promote products derived
* this software without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -68,7 +68,7 @@ void
test_basic( test_basic(
void) 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); GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj1 = gbinder_object_registry_get_remote(reg, 1); GBinderRemoteObject* obj1 = gbinder_object_registry_get_remote(reg, 1);
GBinderRemoteObject* obj2 = gbinder_object_registry_get_remote(reg, 2); GBinderRemoteObject* obj2 = gbinder_object_registry_get_remote(reg, 2);
@@ -112,7 +112,7 @@ test_dead(
{ {
const guint handle = 1; const guint handle = 1;
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL); GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const int fd = gbinder_driver_fd(ipc->driver); const int fd = gbinder_driver_fd(ipc->driver);
GBinderRemoteObject* obj = gbinder_ipc_get_remote_object GBinderRemoteObject* obj = gbinder_ipc_get_remote_object
(ipc, handle, FALSE); (ipc, handle, FALSE);

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2018-2019 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -34,6 +34,7 @@
#include "gbinder_driver.h" #include "gbinder_driver.h"
#include "gbinder_client_p.h" #include "gbinder_client_p.h"
#include "gbinder_config.h"
#include "gbinder_remote_object_p.h" #include "gbinder_remote_object_p.h"
#include "gbinder_ipc.h" #include "gbinder_ipc.h"
#include "gbinder_local_object_p.h" #include "gbinder_local_object_p.h"
@@ -47,6 +48,7 @@
#include <errno.h> #include <errno.h>
static TestOpt test_opt; static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-servicemanager-XXXXXX";
static static
void void
@@ -224,7 +226,7 @@ test_hwservicemanager_check_name(
{ {
TestHwServiceManager* self = TEST_HWSERVICEMANAGER(sm); TestHwServiceManager* self = TEST_HWSERVICEMANAGER(sm);
return (!name || self->reject_name) ? return (!name || self->reject_name) ?
GBINDER_SERVICEMANAGER_NAME_INVALID : GBINDER_SERVICEMANAGER_NAME_INVALID :
GBINDER_SERVICEMANAGER_NAME_NORMALIZE; GBINDER_SERVICEMANAGER_NAME_NORMALIZE;
} }
@@ -281,7 +283,6 @@ test_hwservicemanager_class_init(
{ {
klass->iface = TEST_HWSERVICEMANAGER_IFACE; klass->iface = TEST_HWSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER; klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;
klass->list = test_servicemanager_list; klass->list = test_servicemanager_list;
klass->get_service = test_servicemanager_get_service; klass->get_service = test_servicemanager_get_service;
klass->add_service = test_servicemanager_add_service; klass->add_service = test_servicemanager_add_service;
@@ -292,12 +293,10 @@ test_hwservicemanager_class_init(
G_OBJECT_CLASS(klass)->finalize = test_hwservicemanager_finalize; G_OBJECT_CLASS(klass)->finalize = test_hwservicemanager_finalize;
} }
GBinderServiceManager* GType
gbinder_hwservicemanager_new( gbinder_servicemanager_hidl_get_type()
const char* dev)
{ {
return gbinder_servicemanager_new_with_type(TEST_TYPE_HWSERVICEMANAGER, return TEST_TYPE_HWSERVICEMANAGER;
dev);
} }
/*==========================================================================* /*==========================================================================*
@@ -325,7 +324,7 @@ test_defservicemanager_check_name(
{ {
TestDefServiceManager* self = TEST_DEFSERVICEMANAGER(sm); TestDefServiceManager* self = TEST_DEFSERVICEMANAGER(sm);
return (!name || self->reject_name) ? return (!name || self->reject_name) ?
GBINDER_SERVICEMANAGER_NAME_INVALID : GBINDER_SERVICEMANAGER_NAME_INVALID :
GBINDER_SERVICEMANAGER_NAME_OK; GBINDER_SERVICEMANAGER_NAME_OK;
} }
@@ -365,7 +364,6 @@ test_defservicemanager_class_init(
{ {
klass->iface = TEST_DEFSERVICEMANAGER_IFACE; klass->iface = TEST_DEFSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_BINDER; klass->default_device = GBINDER_DEFAULT_BINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
klass->list = test_servicemanager_list; klass->list = test_servicemanager_list;
klass->get_service = test_servicemanager_get_service; klass->get_service = test_servicemanager_get_service;
klass->add_service = test_servicemanager_add_service; klass->add_service = test_servicemanager_add_service;
@@ -374,12 +372,17 @@ test_defservicemanager_class_init(
G_OBJECT_CLASS(klass)->finalize = test_defservicemanager_finalize; G_OBJECT_CLASS(klass)->finalize = test_defservicemanager_finalize;
} }
GBinderServiceManager* GType
gbinder_defaultservicemanager_new( gbinder_servicemanager_aidl_get_type()
const char* dev)
{ {
return gbinder_servicemanager_new_with_type(TEST_TYPE_DEFSERVICEMANAGER, return TEST_TYPE_DEFSERVICEMANAGER;
dev); }
GType
gbinder_servicemanager_aidl2_get_type()
{
/* Avoid pulling in gbinder_servicemanager_aidl2 object */
return TEST_TYPE_DEFSERVICEMANAGER;
} }
/*==========================================================================* /*==========================================================================*
@@ -391,6 +394,7 @@ void
test_null( test_null(
void) void)
{ {
g_assert(!gbinder_servicemanager_new(NULL));
g_assert(!gbinder_servicemanager_new_with_type(0, 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_new_local_object(NULL, NULL, NULL, NULL));
g_assert(!gbinder_servicemanager_ref(NULL)); g_assert(!gbinder_servicemanager_ref(NULL));
@@ -423,7 +427,7 @@ test_invalid(
{ {
int status = 0; int status = 0;
const char* dev = GBINDER_DEFAULT_HWBINDER; const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL); GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServiceManager* sm; GBinderServiceManager* sm;
gulong id = 0; gulong id = 0;
@@ -466,9 +470,9 @@ static
void void
test_basic( test_basic(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_HWBINDER; const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL); GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServiceManager* sm; GBinderServiceManager* sm;
GBinderLocalObject* obj; GBinderLocalObject* obj;
@@ -486,6 +490,122 @@ test_basic(
gbinder_ipc_unref(ipc); 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 * not_present
*==========================================================================*/ *==========================================================================*/
@@ -494,9 +614,9 @@ static
void void
test_not_present( test_not_present(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_HWBINDER; 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 int fd = gbinder_driver_fd(ipc->driver);
GBinderServiceManager* sm; GBinderServiceManager* sm;
@@ -519,9 +639,9 @@ static
void void
test_wait( test_wait(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_HWBINDER; 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 int fd = gbinder_driver_fd(ipc->driver);
const glong forever = (test_opt.flags & TEST_FLAG_DEBUG) ? const glong forever = (test_opt.flags & TEST_FLAG_DEBUG) ?
(TEST_TIMEOUT_SEC * 1000) : -1; (TEST_TIMEOUT_SEC * 1000) : -1;
@@ -569,9 +689,9 @@ static
void void
test_wait_long( test_wait_long(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_HWBINDER; 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 int fd = gbinder_driver_fd(ipc->driver);
GBinderServiceManager* sm; GBinderServiceManager* sm;
gulong id; gulong id;
@@ -614,9 +734,9 @@ static
void void
test_wait_async( test_wait_async(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_HWBINDER; 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 int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm; GBinderServiceManager* sm;
@@ -658,9 +778,9 @@ static
void void
test_death( test_death(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_HWBINDER; 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 int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm; GBinderServiceManager* sm;
@@ -728,7 +848,7 @@ test_reanimate(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_HWBINDER; 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 int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm; GBinderServiceManager* sm;
@@ -777,13 +897,13 @@ static
void void
test_reuse( test_reuse(
void) void)
{ {
const char* binder_dev = GBINDER_DEFAULT_BINDER; const char* binder_dev = GBINDER_DEFAULT_BINDER;
const char* vndbinder_dev = "/dev/vpnbinder"; const char* vndbinder_dev = "/dev/vpnbinder";
const char* hwbinder_dev = GBINDER_DEFAULT_HWBINDER; const char* hwbinder_dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* binder_ipc = gbinder_ipc_new(binder_dev, NULL); GBinderIpc* binder_ipc = gbinder_ipc_new(binder_dev);
GBinderIpc* vndbinder_ipc = gbinder_ipc_new(vndbinder_dev, NULL); GBinderIpc* vndbinder_ipc = gbinder_ipc_new(vndbinder_dev);
GBinderIpc* hwbinder_ipc = gbinder_ipc_new(hwbinder_dev, NULL); GBinderIpc* hwbinder_ipc = gbinder_ipc_new(hwbinder_dev);
GBinderServiceManager* m1; GBinderServiceManager* m1;
GBinderServiceManager* m2; GBinderServiceManager* m2;
GBinderServiceManager* vnd1; GBinderServiceManager* vnd1;
@@ -835,7 +955,7 @@ test_notify_type(
GType t, GType t,
const char* dev) const char* dev)
{ {
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL); GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServiceManager* sm; GBinderServiceManager* sm;
TestHwServiceManager* test; TestHwServiceManager* test;
const char* name = "foo"; const char* name = "foo";
@@ -902,7 +1022,7 @@ test_list(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_BINDER; 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); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm; GBinderServiceManager* sm;
TestHwServiceManager* test; TestHwServiceManager* test;
@@ -950,7 +1070,7 @@ test_get(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_BINDER; 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); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm; GBinderServiceManager* sm;
TestHwServiceManager* test; TestHwServiceManager* test;
@@ -1011,7 +1131,7 @@ test_add(
void) void)
{ {
const char* dev = GBINDER_DEFAULT_BINDER; 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); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm; GBinderServiceManager* sm;
TestHwServiceManager* test; 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_("null"), test_null);
g_test_add_func(TEST_("invalid"), test_invalid); g_test_add_func(TEST_("invalid"), test_invalid);
g_test_add_func(TEST_("basic"), test_basic); 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_("not_present"), test_not_present);
g_test_add_func(TEST_("wait"), test_wait); g_test_add_func(TEST_("wait"), test_wait);
g_test_add_func(TEST_("wait_long"), test_wait_long); 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-2020 Jolla Ltd.
* Copyright (C) 2019 Slava Monich <slava.monich@jolla.com> * Copyright (C) 2019-2020 Slava Monich <slava.monich@jolla.com>
* *
* You may use this file under the terms of BSD license as follows: * You may use this file under the terms of BSD license as follows:
* *
@@ -202,7 +202,6 @@ test_servicemanager_class_init(
{ {
klass->iface = TEST_SERVICEMANAGER_IFACE; klass->iface = TEST_SERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER; klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
klass->list = test_servicemanager_list; klass->list = test_servicemanager_list;
klass->get_service = test_servicemanager_get_service; klass->get_service = test_servicemanager_get_service;
klass->add_service = test_servicemanager_add_service; klass->add_service = test_servicemanager_add_service;
@@ -212,18 +211,24 @@ test_servicemanager_class_init(
G_OBJECT_CLASS(klass)->finalize = test_servicemanager_finalize; G_OBJECT_CLASS(klass)->finalize = test_servicemanager_finalize;
} }
GBinderServiceManager* /* Avoid pulling in the actual objects */
gbinder_defaultservicemanager_new(
const char* dev) GType
gbinder_servicemanager_aidl_get_type()
{ {
return gbinder_servicemanager_new_with_type(TEST_TYPE_SERVICEMANAGER, dev); return TEST_TYPE_SERVICEMANAGER;
} }
GBinderServiceManager* GType
gbinder_hwservicemanager_new( gbinder_servicemanager_aidl2_get_type()
const char* dev)
{ {
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) void)
{ {
const char* dev = GBINDER_DEFAULT_BINDER; const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL); GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderServiceManager* sm; GBinderServiceManager* sm;
test_setup_ping(ipc); test_setup_ping(ipc);
@@ -263,7 +268,7 @@ test_basic(
const char* obj_name = "test"; const char* obj_name = "test";
const char* dev = GBINDER_DEFAULT_BINDER; const char* dev = GBINDER_DEFAULT_BINDER;
const char* const ifaces[] = { "interface", NULL }; 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); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj; GBinderLocalObject* obj;
GBinderServiceManager* sm; GBinderServiceManager* sm;
@@ -306,7 +311,7 @@ test_present(
const char* obj_name = "test"; const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL }; const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER; 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); const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj; GBinderLocalObject* obj;
@@ -371,7 +376,7 @@ test_not_present(
const char* obj_name = "test"; const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL }; const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER; 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); const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj; GBinderLocalObject* obj;
@@ -421,7 +426,7 @@ test_cancel(
const char* obj_name = "test"; const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL }; const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER; 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); const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE); GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj; GBinderLocalObject* obj;

View File

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