Compare commits
	
		
			17 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					eaab366dcb | ||
| 
						 | 
					784f06c415 | ||
| 
						 | 
					4b07e80a8f | ||
| 
						 | 
					9f7fac407d | ||
| 
						 | 
					47b6668876 | ||
| 
						 | 
					951977961b | ||
| 
						 | 
					f069c3a595 | ||
| 
						 | 
					b84194e8c7 | ||
| 
						 | 
					e06e989aa5 | ||
| 
						 | 
					ab75505437 | ||
| 
						 | 
					e97663b58e | ||
| 
						 | 
					a92f57a30c | ||
| 
						 | 
					ebb9381e46 | ||
| 
						 | 
					5fb441fb81 | ||
| 
						 | 
					f3a00fe8a2 | ||
| 
						 | 
					573494570c | ||
| 
						 | 
					92392f5c9a | 
							
								
								
									
										12
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								Makefile
									
									
									
									
									
								
							@@ -15,8 +15,8 @@
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
VERSION_MAJOR = 1
 | 
			
		||||
VERSION_MINOR = 0
 | 
			
		||||
VERSION_RELEASE = 47
 | 
			
		||||
VERSION_MINOR = 1
 | 
			
		||||
VERSION_RELEASE = 1
 | 
			
		||||
 | 
			
		||||
# Version for pkg-config
 | 
			
		||||
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
 | 
			
		||||
@@ -78,6 +78,7 @@ SRC = \
 | 
			
		||||
  gbinder_buffer.c \
 | 
			
		||||
  gbinder_cleanup.c \
 | 
			
		||||
  gbinder_client.c \
 | 
			
		||||
  gbinder_config.c \
 | 
			
		||||
  gbinder_driver.c \
 | 
			
		||||
  gbinder_eventloop.c \
 | 
			
		||||
  gbinder_io_32.c \
 | 
			
		||||
@@ -97,9 +98,10 @@ SRC = \
 | 
			
		||||
  gbinder_writer.c
 | 
			
		||||
 | 
			
		||||
SRC += \
 | 
			
		||||
  gbinder_defaultservicemanager.c \
 | 
			
		||||
  gbinder_hwservicemanager.c \
 | 
			
		||||
  gbinder_servicemanager.c
 | 
			
		||||
  gbinder_servicemanager.c \
 | 
			
		||||
  gbinder_servicemanager_aidl.c \
 | 
			
		||||
  gbinder_servicemanager_aidl2.c \
 | 
			
		||||
  gbinder_servicemanager_hidl.c
 | 
			
		||||
 | 
			
		||||
SRC += \
 | 
			
		||||
  gbinder_system.c
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								README
									
									
									
									
									
								
							@@ -1,7 +1,44 @@
 | 
			
		||||
GLib-style interface to binder (Android IPC mechanism)
 | 
			
		||||
 | 
			
		||||
Provides:
 | 
			
		||||
Key features:
 | 
			
		||||
 | 
			
		||||
1. Integration with GLib event loop
 | 
			
		||||
2. Detection of 32 vs 64 bit kernel at runtime
 | 
			
		||||
3. Asynchronous transactions that don't block the event thread
 | 
			
		||||
4. Stable service manager and low-level transation APIs
 | 
			
		||||
 | 
			
		||||
Android keeps changing both low-level RPC and service manager
 | 
			
		||||
protocols from version to version. To counter that, libgbinder
 | 
			
		||||
implements configirable backends for different variants of those,
 | 
			
		||||
and yet keeping its own API unchanged.
 | 
			
		||||
 | 
			
		||||
Configuration is loaded from [Protocol] and [ServiceManager] sections
 | 
			
		||||
of /etc/gbinder.conf file. The keys are binder device names or the
 | 
			
		||||
special Default value, the value is the identifier of the protocol
 | 
			
		||||
or service manager variant, respectively.
 | 
			
		||||
 | 
			
		||||
In addition to reading /etc/gbinder.conf if it exists, /etc/gbinder.d
 | 
			
		||||
directory is scanned for .conf files, the file list is sorted, files are
 | 
			
		||||
loaded one by one, overwriting the entries loaded from /etc/gbinder.conf
 | 
			
		||||
or from the previously processed file.
 | 
			
		||||
 | 
			
		||||
Known protocol and service manager variants are aidl, aidl2 and hidl.
 | 
			
		||||
This list is expected to expand further in the future. The default
 | 
			
		||||
configuration is as follows:
 | 
			
		||||
 | 
			
		||||
  [Protocol]
 | 
			
		||||
  Default = aidl
 | 
			
		||||
  /dev/binder = aidl
 | 
			
		||||
  /dev/hwbinder = hidl
 | 
			
		||||
 | 
			
		||||
  [ServiceManager]
 | 
			
		||||
  Default = aidl
 | 
			
		||||
  /dev/binder = aidl
 | 
			
		||||
  /dev/hwbinder = hidl
 | 
			
		||||
 | 
			
		||||
Alternatively, one can specify the desired Android API level:
 | 
			
		||||
 | 
			
		||||
  [General]
 | 
			
		||||
  ApiLevel = 29
 | 
			
		||||
 | 
			
		||||
and let libgbinder pick the appropriate preset.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,23 @@
 | 
			
		||||
libgbinder (1.1.1) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * Handle corner cases for abandoned loopers
 | 
			
		||||
  * Pass 0x0f priority to aidl2 service list request.
 | 
			
		||||
  * Improved binder simulation for unit tests
 | 
			
		||||
  * Added servicemanager_aidl unit test
 | 
			
		||||
 | 
			
		||||
 -- Slava Monich <slava.monich@jolla.com>  Tue, 22 Dec 2020 15:15:10 +0200
 | 
			
		||||
 | 
			
		||||
libgbinder (1.1.0) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * Made RPC protocol configurable per binder device
 | 
			
		||||
  * Made service managers configurable per binder device
 | 
			
		||||
  * Added support for multiple config files
 | 
			
		||||
  * Added "aidl2" variant of service manager
 | 
			
		||||
  * Added "aidl2" variant of RPC protocol
 | 
			
		||||
  * Added support for API level presets
 | 
			
		||||
 | 
			
		||||
 -- Slava Monich <slava.monich@jolla.com>  Fri, 04 Dec 2020 13:47:26 +0200
 | 
			
		||||
 | 
			
		||||
libgbinder (1.0.47) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * Make library executable on RPM based systems
 | 
			
		||||
 
 | 
			
		||||
@@ -80,11 +80,13 @@ gbinder_servicemanager_new(
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_defaultservicemanager_new(
 | 
			
		||||
    const char* dev);
 | 
			
		||||
    const char* dev)
 | 
			
		||||
    G_DEPRECATED_FOR(gbinder_servicemanager_new);
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_hwservicemanager_new(
 | 
			
		||||
    const char* dev);
 | 
			
		||||
    const char* dev)
 | 
			
		||||
    G_DEPRECATED_FOR(gbinder_servicemanager_new);
 | 
			
		||||
 | 
			
		||||
GBinderLocalObject*
 | 
			
		||||
gbinder_servicemanager_new_local_object(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
Name: libgbinder
 | 
			
		||||
Version: 1.0.47
 | 
			
		||||
Version: 1.1.1
 | 
			
		||||
Release: 0
 | 
			
		||||
Summary: Binder client library
 | 
			
		||||
License: BSD
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										384
									
								
								src/gbinder_config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								src/gbinder_config.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										78
									
								
								src/gbinder_config.h
									
									
									
									
									
										Normal 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:
 | 
			
		||||
 */
 | 
			
		||||
@@ -953,7 +953,7 @@ gbinder_driver_read(
 | 
			
		||||
    if (ret >= 0) {
 | 
			
		||||
        /* Loop until we have handled all the incoming commands */
 | 
			
		||||
        gbinder_driver_handle_commands(self, reg, handler, &rb);
 | 
			
		||||
        while (rb.buf.consumed) {
 | 
			
		||||
        while (rb.buf.consumed && gbinder_handler_can_loop(handler)) {
 | 
			
		||||
            ret = gbinder_driver_write_read(self, NULL, &rb.buf);
 | 
			
		||||
            if (ret >= 0) {
 | 
			
		||||
                gbinder_driver_handle_commands(self, reg, handler, &rb);
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,7 @@
 | 
			
		||||
#include "gbinder_types_p.h"
 | 
			
		||||
 | 
			
		||||
typedef struct gbinder_handler_functions {
 | 
			
		||||
    gboolean (*can_loop)(GBinderHandler* handler);
 | 
			
		||||
    GBinderLocalReply* (*transact)(GBinderHandler* handler,
 | 
			
		||||
        GBinderLocalObject* obj, GBinderRemoteRequest* req, guint code,
 | 
			
		||||
        guint flags, int* status);
 | 
			
		||||
@@ -47,6 +48,14 @@ struct gbinder_handler {
 | 
			
		||||
 | 
			
		||||
/* Inline wrappers */
 | 
			
		||||
 | 
			
		||||
GBINDER_INLINE_FUNC
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_handler_can_loop(
 | 
			
		||||
    GBinderHandler* self)
 | 
			
		||||
{
 | 
			
		||||
    return self && self->f->can_loop && self->f->can_loop(self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBINDER_INLINE_FUNC
 | 
			
		||||
GBinderLocalReply*
 | 
			
		||||
gbinder_handler_transact(
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,7 @@
 | 
			
		||||
#include "gbinder_driver.h"
 | 
			
		||||
#include "gbinder_handler.h"
 | 
			
		||||
#include "gbinder_io.h"
 | 
			
		||||
#include "gbinder_rpc_protocol.h"
 | 
			
		||||
#include "gbinder_object_registry.h"
 | 
			
		||||
#include "gbinder_local_object_p.h"
 | 
			
		||||
#include "gbinder_local_reply.h"
 | 
			
		||||
@@ -605,6 +606,16 @@ gbinder_ipc_looper_count_primary(
 | 
			
		||||
    return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_ipc_looper_can_loop(
 | 
			
		||||
    GBinderHandler* handler)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpcLooper* looper = G_CAST(handler,GBinderIpcLooper,handler);
 | 
			
		||||
 | 
			
		||||
    return !g_atomic_int_get(&looper->exit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderLocalReply*
 | 
			
		||||
gbinder_ipc_looper_transact(
 | 
			
		||||
@@ -823,6 +834,7 @@ gbinder_ipc_looper_new(
 | 
			
		||||
    /* Note: this call can actually fail */
 | 
			
		||||
    if (!pipe(fd)) {
 | 
			
		||||
        static const GBinderHandlerFunctions handler_functions = {
 | 
			
		||||
            .can_loop = gbinder_ipc_looper_can_loop,
 | 
			
		||||
            .transact = gbinder_ipc_looper_transact
 | 
			
		||||
        };
 | 
			
		||||
        GError* error = NULL;
 | 
			
		||||
@@ -895,13 +907,15 @@ gbinder_ipc_looper_stop(
 | 
			
		||||
    GBinderIpcLooper* looper)
 | 
			
		||||
{
 | 
			
		||||
    /* Caller checks looper for NULL */
 | 
			
		||||
    if (looper->thread && looper->thread != g_thread_self()) {
 | 
			
		||||
        guint8 done = TX_DONE;
 | 
			
		||||
 | 
			
		||||
    if (looper->thread) {
 | 
			
		||||
        GDEBUG("Stopping looper %s", looper->name);
 | 
			
		||||
        g_atomic_int_set(&looper->exit, TRUE);
 | 
			
		||||
        if (write(looper->pipefd[1], &done, sizeof(done)) <= 0) {
 | 
			
		||||
            looper->thread = NULL;
 | 
			
		||||
        if (looper->thread != g_thread_self()) {
 | 
			
		||||
            guint8 done = TX_DONE;
 | 
			
		||||
 | 
			
		||||
            if (write(looper->pipefd[1], &done, sizeof(done)) <= 0) {
 | 
			
		||||
                looper->thread = NULL;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1420,7 +1434,8 @@ gbinder_ipc_tx_internal_exec(
 | 
			
		||||
    GBinderIpcTxPriv* priv)
 | 
			
		||||
{
 | 
			
		||||
    static const GBinderHandlerFunctions handler_fn = {
 | 
			
		||||
        gbinder_ipc_tx_handler_transact
 | 
			
		||||
        .can_loop = NULL,
 | 
			
		||||
        .transact = gbinder_ipc_tx_handler_transact
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpcTxInternal* tx = gbinder_ipc_tx_internal_cast(priv);
 | 
			
		||||
    GBinderIpcTx* pub = &priv->pub;
 | 
			
		||||
@@ -1570,12 +1585,14 @@ gbinder_ipc_tx_proc(
 | 
			
		||||
 | 
			
		||||
GBinderIpc*
 | 
			
		||||
gbinder_ipc_new(
 | 
			
		||||
    const char* dev,
 | 
			
		||||
    const GBinderRpcProtocol* protocol)
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* self = NULL;
 | 
			
		||||
    const GBinderRpcProtocol* protocol;
 | 
			
		||||
 | 
			
		||||
    if (!dev || !dev[0]) dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    protocol = gbinder_rpc_protocol_for_device(dev); /* Never returns NULL */
 | 
			
		||||
 | 
			
		||||
    /* Lock */
 | 
			
		||||
    pthread_mutex_lock(&gbinder_ipc_mutex);
 | 
			
		||||
    if (gbinder_ipc_table) {
 | 
			
		||||
@@ -1746,6 +1763,14 @@ gbinder_ipc_cancel(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_ipc_set_max_threads(
 | 
			
		||||
    GBinderIpc* self,
 | 
			
		||||
    gint max)
 | 
			
		||||
{
 | 
			
		||||
    return g_thread_pool_set_max_threads(self->priv->tx_pool, max, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * Internals
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 
 | 
			
		||||
@@ -69,8 +69,7 @@ void
 | 
			
		||||
 | 
			
		||||
GBinderIpc*
 | 
			
		||||
gbinder_ipc_new(
 | 
			
		||||
    const char* dev,
 | 
			
		||||
    const GBinderRpcProtocol* protocol)
 | 
			
		||||
    const char* dev)
 | 
			
		||||
    GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
GBinderIpc*
 | 
			
		||||
@@ -170,12 +169,19 @@ gbinder_ipc_remote_object_disposed(
 | 
			
		||||
    GBinderRemoteObject* obj)
 | 
			
		||||
    GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
/* Needed by unit tests */
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_ipc_set_max_threads(
 | 
			
		||||
    GBinderIpc* self,
 | 
			
		||||
    gint max_threads)
 | 
			
		||||
    GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
/* Declared for unit tests */
 | 
			
		||||
__attribute__((destructor))
 | 
			
		||||
void
 | 
			
		||||
gbinder_ipc_exit(
 | 
			
		||||
    void)
 | 
			
		||||
    GBINDER_INTERNAL;
 | 
			
		||||
    GBINDER_INTERNAL
 | 
			
		||||
    GBINDER_DESTRUCTOR;
 | 
			
		||||
 | 
			
		||||
#endif /* GBINDER_IPC_H */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -115,6 +115,7 @@ gbinder_remote_object_reanimate(
 | 
			
		||||
        if (gbinder_driver_ping(ipc->driver, reg, self->handle) == 0) {
 | 
			
		||||
            /* Wow, it's alive! */
 | 
			
		||||
            self->dead = FALSE;
 | 
			
		||||
            gbinder_ipc_looper_check(self->ipc); /* For death notifications */
 | 
			
		||||
            gbinder_driver_acquire(ipc->driver, self->handle);
 | 
			
		||||
            gbinder_driver_request_death_notification(ipc->driver, self);
 | 
			
		||||
        }
 | 
			
		||||
@@ -151,6 +152,7 @@ gbinder_remote_object_new(
 | 
			
		||||
        self->ipc = gbinder_ipc_ref(ipc);
 | 
			
		||||
        self->handle = handle;
 | 
			
		||||
        if (!(self->dead = dead)) {
 | 
			
		||||
            gbinder_ipc_looper_check(self->ipc); /* For death notifications */
 | 
			
		||||
            gbinder_driver_acquire(ipc->driver, handle);
 | 
			
		||||
            gbinder_driver_request_death_notification(ipc->driver, self);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -14,8 +14,8 @@
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived from
 | 
			
		||||
 *      this software without specific prior written permission.
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -33,6 +33,12 @@
 | 
			
		||||
#include "gbinder_rpc_protocol.h"
 | 
			
		||||
#include "gbinder_reader.h"
 | 
			
		||||
#include "gbinder_writer.h"
 | 
			
		||||
#include "gbinder_config.h"
 | 
			
		||||
#include "gbinder_log.h"
 | 
			
		||||
 | 
			
		||||
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
 | 
			
		||||
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
 | 
			
		||||
#define UNSET_WORK_SOURCE (-1)
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * GBinderIpcProtocol callbacks (see Parcel::writeInterfaceToken in Android)
 | 
			
		||||
@@ -40,19 +46,39 @@
 | 
			
		||||
 *
 | 
			
		||||
 *   platform/system/libhwbinder/Parcel.cpp
 | 
			
		||||
 *   platform/frameworks/native/libs/binder/Parcel.cpp
 | 
			
		||||
 *
 | 
			
		||||
 * which mutate from version to version. Specific device => protocol
 | 
			
		||||
 * mapping can be optionally configured in /etc/gbinder.conf file.
 | 
			
		||||
 * The default protocol configuration looks like this:
 | 
			
		||||
 *
 | 
			
		||||
 *   [Protocol]
 | 
			
		||||
 *   Default = aidl
 | 
			
		||||
 *   /dev/binder = aidl
 | 
			
		||||
 *   /dev/hwbinder = hidl
 | 
			
		||||
 *
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
#define CONF_GROUP GBINDER_CONFIG_GROUP_PROTOCOL
 | 
			
		||||
#define CONF_DEFAULT GBINDER_CONFIG_VALUE_DEFAULT
 | 
			
		||||
 | 
			
		||||
static GHashTable* gbinder_rpc_protocol_map = NULL;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Default protocol for those binder devices which which haven't been
 | 
			
		||||
 * explicitely mapped.
 | 
			
		||||
 */
 | 
			
		||||
#define DEFAULT_PROTOCOL gbinder_rpc_protocol_aidl
 | 
			
		||||
static const GBinderRpcProtocol DEFAULT_PROTOCOL;
 | 
			
		||||
static const GBinderRpcProtocol* gbinder_rpc_protocol_default =
 | 
			
		||||
    &DEFAULT_PROTOCOL;
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * /dev/binder
 | 
			
		||||
 * The original AIDL protocol.
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
/* No idea what that is... */
 | 
			
		||||
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
 | 
			
		||||
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_rpc_protocol_binder_write_ping(
 | 
			
		||||
gbinder_rpc_protocol_aidl_write_ping(
 | 
			
		||||
    GBinderWriter* writer)
 | 
			
		||||
{
 | 
			
		||||
    /* No payload */
 | 
			
		||||
@@ -60,7 +86,7 @@ gbinder_rpc_protocol_binder_write_ping(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_rpc_protocol_binder_write_rpc_header(
 | 
			
		||||
gbinder_rpc_protocol_aidl_write_rpc_header(
 | 
			
		||||
    GBinderWriter* writer,
 | 
			
		||||
    const char* iface)
 | 
			
		||||
{
 | 
			
		||||
@@ -75,7 +101,7 @@ gbinder_rpc_protocol_binder_write_rpc_header(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
const char*
 | 
			
		||||
gbinder_rpc_protocol_binder_read_rpc_header(
 | 
			
		||||
gbinder_rpc_protocol_aidl_read_rpc_header(
 | 
			
		||||
    GBinderReader* reader,
 | 
			
		||||
    guint32 txcode,
 | 
			
		||||
    char** iface)
 | 
			
		||||
@@ -91,13 +117,69 @@ gbinder_rpc_protocol_binder_read_rpc_header(
 | 
			
		||||
    return *iface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const GBinderRpcProtocol gbinder_rpc_protocol_aidl = {
 | 
			
		||||
    .name = "aidl",
 | 
			
		||||
    .ping_tx = GBINDER_PING_TRANSACTION,
 | 
			
		||||
    .write_ping = gbinder_rpc_protocol_aidl_write_ping,
 | 
			
		||||
    .write_rpc_header = gbinder_rpc_protocol_aidl_write_rpc_header,
 | 
			
		||||
    .read_rpc_header = gbinder_rpc_protocol_aidl_read_rpc_header
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * /dev/hwbinder
 | 
			
		||||
 * AIDL protocol appeared in Android 10 (API level 29)
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_rpc_protocol_hwbinder_write_rpc_header(
 | 
			
		||||
gbinder_rpc_protocol_aidl2_write_rpc_header(
 | 
			
		||||
    GBinderWriter* writer,
 | 
			
		||||
    const char* iface)
 | 
			
		||||
{
 | 
			
		||||
    /*
 | 
			
		||||
     * writeInt32(IPCThreadState::self()->getStrictModePolicy() |
 | 
			
		||||
     *               STRICT_MODE_PENALTY_GATHER);
 | 
			
		||||
     * writeInt32(IPCThreadState::kUnsetWorkSource);
 | 
			
		||||
     * writeString16(interface);
 | 
			
		||||
     */
 | 
			
		||||
    gbinder_writer_append_int32(writer, BINDER_RPC_FLAGS);
 | 
			
		||||
    gbinder_writer_append_int32(writer, UNSET_WORK_SOURCE);
 | 
			
		||||
    gbinder_writer_append_string16(writer, iface);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
const char*
 | 
			
		||||
gbinder_rpc_protocol_aidl2_read_rpc_header(
 | 
			
		||||
    GBinderReader* reader,
 | 
			
		||||
    guint32 txcode,
 | 
			
		||||
    char** iface)
 | 
			
		||||
{
 | 
			
		||||
    if (txcode > GBINDER_TRANSACTION(0,0,0)) {
 | 
			
		||||
        /* Internal transaction e.g. GBINDER_DUMP_TRANSACTION etc. */
 | 
			
		||||
        *iface = NULL;
 | 
			
		||||
    } else if (gbinder_reader_read_int32(reader, NULL) /* flags */ &&
 | 
			
		||||
        gbinder_reader_read_int32(reader, NULL) /* work source */) {
 | 
			
		||||
        *iface = gbinder_reader_read_string16(reader);
 | 
			
		||||
    } else {
 | 
			
		||||
        *iface = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return *iface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const GBinderRpcProtocol gbinder_rpc_protocol_aidl2 = {
 | 
			
		||||
    .name = "aidl2",
 | 
			
		||||
    .ping_tx = GBINDER_PING_TRANSACTION,
 | 
			
		||||
    .write_ping = gbinder_rpc_protocol_aidl_write_ping, /* no payload */
 | 
			
		||||
    .write_rpc_header = gbinder_rpc_protocol_aidl2_write_rpc_header,
 | 
			
		||||
    .read_rpc_header = gbinder_rpc_protocol_aidl2_read_rpc_header
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * The original /dev/hwbinder protocol.
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_rpc_protocol_hidl_write_rpc_header(
 | 
			
		||||
    GBinderWriter* writer,
 | 
			
		||||
    const char* iface)
 | 
			
		||||
{
 | 
			
		||||
@@ -109,16 +191,16 @@ gbinder_rpc_protocol_hwbinder_write_rpc_header(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_rpc_protocol_hwbinder_write_ping(
 | 
			
		||||
gbinder_rpc_protocol_hidl_write_ping(
 | 
			
		||||
    GBinderWriter* writer)
 | 
			
		||||
{
 | 
			
		||||
    gbinder_rpc_protocol_hwbinder_write_rpc_header(writer,
 | 
			
		||||
    gbinder_rpc_protocol_hidl_write_rpc_header(writer,
 | 
			
		||||
        "android.hidl.base@1.0::IBase");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
const char*
 | 
			
		||||
gbinder_rpc_protocol_hwbinder_read_rpc_header(
 | 
			
		||||
gbinder_rpc_protocol_hidl_read_rpc_header(
 | 
			
		||||
    GBinderReader* reader,
 | 
			
		||||
    guint32 txcode,
 | 
			
		||||
    char** iface)
 | 
			
		||||
@@ -127,30 +209,126 @@ gbinder_rpc_protocol_hwbinder_read_rpc_header(
 | 
			
		||||
    return gbinder_reader_read_string8(reader);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const GBinderRpcProtocol gbinder_rpc_protocol_hidl = {
 | 
			
		||||
    .name = "hidl",
 | 
			
		||||
    .ping_tx = HIDL_PING_TRANSACTION,
 | 
			
		||||
    .write_ping = gbinder_rpc_protocol_hidl_write_ping,
 | 
			
		||||
    .write_rpc_header = gbinder_rpc_protocol_hidl_write_rpc_header,
 | 
			
		||||
    .read_rpc_header = gbinder_rpc_protocol_hidl_read_rpc_header
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * Implementation
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
/* All known protocols */
 | 
			
		||||
static const GBinderRpcProtocol* gbinder_rpc_protocol_list[] = {
 | 
			
		||||
    &gbinder_rpc_protocol_aidl,
 | 
			
		||||
    &gbinder_rpc_protocol_aidl2,
 | 
			
		||||
    &gbinder_rpc_protocol_hidl
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
const GBinderRpcProtocol*
 | 
			
		||||
gbinder_rpc_protocol_find(
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    guint i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < G_N_ELEMENTS(gbinder_rpc_protocol_list); i++) {
 | 
			
		||||
        if (!g_ascii_strcasecmp(gbinder_rpc_protocol_list[i]->name, name)) {
 | 
			
		||||
            return gbinder_rpc_protocol_list[i];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_rpc_protocol_map_add_default(
 | 
			
		||||
    GHashTable* map,
 | 
			
		||||
    const char* dev,
 | 
			
		||||
    const GBinderRpcProtocol* protocol)
 | 
			
		||||
{
 | 
			
		||||
    if (!g_hash_table_contains(map, dev)) {
 | 
			
		||||
        g_hash_table_insert(map, g_strdup(dev), (gpointer) protocol);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gconstpointer
 | 
			
		||||
gbinder_rpc_protocol_value_map(
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_rpc_protocol_find(name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GHashTable*
 | 
			
		||||
gbinder_rpc_protocol_load_config()
 | 
			
		||||
{
 | 
			
		||||
    GHashTable* map = gbinder_config_load(CONF_GROUP,
 | 
			
		||||
        gbinder_rpc_protocol_value_map);
 | 
			
		||||
 | 
			
		||||
    /* Add default configuration if it's not overridden */
 | 
			
		||||
    gbinder_rpc_protocol_map_add_default(map,
 | 
			
		||||
        GBINDER_DEFAULT_BINDER, &gbinder_rpc_protocol_aidl);
 | 
			
		||||
    gbinder_rpc_protocol_map_add_default(map,
 | 
			
		||||
        GBINDER_DEFAULT_HWBINDER, &gbinder_rpc_protocol_hidl);
 | 
			
		||||
 | 
			
		||||
    return map;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Runs at exit */
 | 
			
		||||
void
 | 
			
		||||
gbinder_rpc_protocol_exit()
 | 
			
		||||
{
 | 
			
		||||
    if (gbinder_rpc_protocol_map) {
 | 
			
		||||
        g_hash_table_destroy(gbinder_rpc_protocol_map);
 | 
			
		||||
        gbinder_rpc_protocol_map = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    /* Reset the default too, mostly for unit testing */
 | 
			
		||||
    gbinder_rpc_protocol_default = &DEFAULT_PROTOCOL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * Interface
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
const GBinderRpcProtocol gbinder_rpc_protocol_binder = {
 | 
			
		||||
    .ping_tx = GBINDER_PING_TRANSACTION,
 | 
			
		||||
    .write_ping = gbinder_rpc_protocol_binder_write_ping,
 | 
			
		||||
    .write_rpc_header = gbinder_rpc_protocol_binder_write_rpc_header,
 | 
			
		||||
    .read_rpc_header = gbinder_rpc_protocol_binder_read_rpc_header
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const GBinderRpcProtocol gbinder_rpc_protocol_hwbinder = {
 | 
			
		||||
    .ping_tx = HIDL_PING_TRANSACTION,
 | 
			
		||||
    .write_ping = gbinder_rpc_protocol_hwbinder_write_ping,
 | 
			
		||||
    .write_rpc_header = gbinder_rpc_protocol_hwbinder_write_rpc_header,
 | 
			
		||||
    .read_rpc_header = gbinder_rpc_protocol_hwbinder_read_rpc_header
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const GBinderRpcProtocol*
 | 
			
		||||
gbinder_rpc_protocol_for_device(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    return (dev && !strcmp(dev, GBINDER_DEFAULT_HWBINDER)) ?
 | 
			
		||||
        &gbinder_rpc_protocol_hwbinder : &gbinder_rpc_protocol_binder;
 | 
			
		||||
    if (dev) {
 | 
			
		||||
        const GBinderRpcProtocol* protocol;
 | 
			
		||||
 | 
			
		||||
        if (!gbinder_rpc_protocol_map) {
 | 
			
		||||
            const GBinderRpcProtocol* p;
 | 
			
		||||
 | 
			
		||||
            /* One-time initialization */
 | 
			
		||||
            gbinder_rpc_protocol_map = gbinder_rpc_protocol_load_config();
 | 
			
		||||
 | 
			
		||||
            /* "Default" is a special value stored in a special variable */
 | 
			
		||||
            p = g_hash_table_lookup(gbinder_rpc_protocol_map, CONF_DEFAULT);
 | 
			
		||||
            if (p) {
 | 
			
		||||
                g_hash_table_remove(gbinder_rpc_protocol_map, CONF_DEFAULT);
 | 
			
		||||
                gbinder_rpc_protocol_default = p;
 | 
			
		||||
            } else {
 | 
			
		||||
                gbinder_rpc_protocol_default = &DEFAULT_PROTOCOL;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        protocol = g_hash_table_lookup(gbinder_rpc_protocol_map, dev);
 | 
			
		||||
        if (protocol) {
 | 
			
		||||
            GDEBUG("Using %s protocol for %s", protocol->name, dev);
 | 
			
		||||
            return protocol;
 | 
			
		||||
        }
 | 
			
		||||
        GDEBUG("Using default protocol %s for %s",
 | 
			
		||||
            gbinder_rpc_protocol_default->name, dev);
 | 
			
		||||
    } else {
 | 
			
		||||
        GDEBUG("Using default protocol %s",
 | 
			
		||||
            gbinder_rpc_protocol_default->name);
 | 
			
		||||
    }
 | 
			
		||||
    return gbinder_rpc_protocol_default;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,6 @@
 | 
			
		||||
 *   2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
@@ -37,11 +36,12 @@
 | 
			
		||||
#include "gbinder_types_p.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * For whatever reason services communicating via /dev/binder
 | 
			
		||||
 * and /dev/hwbinder use slightly different RPC headers.
 | 
			
		||||
 * There are several versions of binder RPC protocol with diffferent
 | 
			
		||||
 * transaction headers and transaction codes.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct gbinder_rpc_protocol {
 | 
			
		||||
    const char* name;
 | 
			
		||||
    guint32 ping_tx;
 | 
			
		||||
    void (*write_ping)(GBinderWriter* writer);
 | 
			
		||||
    void (*write_rpc_header)(GBinderWriter* writer, const char* iface);
 | 
			
		||||
@@ -49,15 +49,19 @@ struct gbinder_rpc_protocol {
 | 
			
		||||
        char** iface);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const GBinderRpcProtocol gbinder_rpc_protocol_binder GBINDER_INTERNAL;
 | 
			
		||||
extern const GBinderRpcProtocol gbinder_rpc_protocol_hwbinder GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
/* Returns one of the above based on the device name */
 | 
			
		||||
const GBinderRpcProtocol*
 | 
			
		||||
gbinder_rpc_protocol_for_device(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
    GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
/* Runs at exit, declared here strictly for unit tests */
 | 
			
		||||
void
 | 
			
		||||
gbinder_rpc_protocol_exit(
 | 
			
		||||
    void)
 | 
			
		||||
    GBINDER_DESTRUCTOR
 | 
			
		||||
    GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
#endif /* GBINDER_RPC_PROTOCOL_H */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@
 | 
			
		||||
 | 
			
		||||
#include "gbinder_servicemanager_p.h"
 | 
			
		||||
#include "gbinder_client_p.h"
 | 
			
		||||
#include "gbinder_config.h"
 | 
			
		||||
#include "gbinder_local_object_p.h"
 | 
			
		||||
#include "gbinder_remote_object_p.h"
 | 
			
		||||
#include "gbinder_eventloop_p.h"
 | 
			
		||||
@@ -47,6 +48,51 @@
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 *
 | 
			
		||||
 * Different versions of Android come with different flavors of service
 | 
			
		||||
 * managers. They are usually based on these two more or less independent
 | 
			
		||||
 * variants:
 | 
			
		||||
 *
 | 
			
		||||
 *   platform/frameworks/native/cmds/servicemanager/ServiceManager.cpp
 | 
			
		||||
 *   platform/system/hwservicemanager/ServiceManager.cpp
 | 
			
		||||
 *
 | 
			
		||||
 * They are talking slightly different protocols which slightly mutate
 | 
			
		||||
 * from version to version. If that's not complex enough, different
 | 
			
		||||
 * kinds of service managers can be running simultaneously, serving
 | 
			
		||||
 * different binder devices. Specific device => servicemanager mapping
 | 
			
		||||
 * can be optionally configured in /etc/gbinder.conf file. The default
 | 
			
		||||
 * service manager configuration looks like this:
 | 
			
		||||
 *
 | 
			
		||||
 *   [ServiceManager]
 | 
			
		||||
 *   Default = aidl
 | 
			
		||||
 *   /dev/binder = aidl
 | 
			
		||||
 *   /dev/hwbinder = hidl
 | 
			
		||||
 *
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
#define CONF_GROUP GBINDER_CONFIG_GROUP_SERVICEMANAGER
 | 
			
		||||
#define CONF_DEFAULT GBINDER_CONFIG_VALUE_DEFAULT
 | 
			
		||||
 | 
			
		||||
typedef struct gbinder_servicemanager_type {
 | 
			
		||||
    const char* name;
 | 
			
		||||
    GType (*get_type)(void);
 | 
			
		||||
} GBinderServiceManagerType;
 | 
			
		||||
 | 
			
		||||
static const GBinderServiceManagerType gbinder_servicemanager_types[] = {
 | 
			
		||||
    { "aidl", gbinder_servicemanager_aidl_get_type },
 | 
			
		||||
    { "aidl2", gbinder_servicemanager_aidl2_get_type },
 | 
			
		||||
    { "hidl", gbinder_servicemanager_hidl_get_type }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define SERVICEMANAGER_TYPE_AIDL (gbinder_servicemanager_types + 0)
 | 
			
		||||
#define SERVICEMANAGER_TYPE_HIDL (gbinder_servicemanager_types + 2)
 | 
			
		||||
#define SERVICEMANAGER_TYPE_DEFAULT SERVICEMANAGER_TYPE_AIDL
 | 
			
		||||
 | 
			
		||||
static GHashTable* gbinder_servicemanager_map = NULL;
 | 
			
		||||
static const GBinderServiceManagerType* gbinder_servicemanager_default =
 | 
			
		||||
    SERVICEMANAGER_TYPE_DEFAULT;
 | 
			
		||||
 | 
			
		||||
#define PRESENSE_WAIT_MS_MIN  (100)
 | 
			
		||||
#define PRESENSE_WAIT_MS_MAX  (1000)
 | 
			
		||||
#define PRESENSE_WAIT_MS_STEP (100)
 | 
			
		||||
@@ -75,9 +121,6 @@ G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
 | 
			
		||||
#define GBINDER_SERVICEMANAGER(obj) \
 | 
			
		||||
    G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER, \
 | 
			
		||||
    GBinderServiceManager)
 | 
			
		||||
#define GBINDER_SERVICEMANAGER_CLASS(klass) \
 | 
			
		||||
    G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
 | 
			
		||||
    GBinderServiceManagerClass)
 | 
			
		||||
#define GBINDER_SERVICEMANAGER_GET_CLASS(obj) \
 | 
			
		||||
    G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER, \
 | 
			
		||||
    GBinderServiceManagerClass)
 | 
			
		||||
@@ -408,6 +451,64 @@ gbinder_servicemanager_autorelease_cb(
 | 
			
		||||
    g_slist_free_full(list, g_object_unref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicemanager_map_add_default(
 | 
			
		||||
    GHashTable* map,
 | 
			
		||||
    const char* dev,
 | 
			
		||||
    const GBinderServiceManagerType* type)
 | 
			
		||||
{
 | 
			
		||||
    if (!g_hash_table_contains(map, dev)) {
 | 
			
		||||
        g_hash_table_insert(map, g_strdup(dev), (gpointer) type);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gconstpointer
 | 
			
		||||
gbinder_servicemanager_value_map(
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    guint i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < G_N_ELEMENTS(gbinder_servicemanager_types); i++) {
 | 
			
		||||
        const GBinderServiceManagerType* t = gbinder_servicemanager_types + i;
 | 
			
		||||
 | 
			
		||||
        if (!g_strcmp0(name, t->name)) {
 | 
			
		||||
            return t;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GHashTable*
 | 
			
		||||
gbinder_servicemanager_load_config()
 | 
			
		||||
{
 | 
			
		||||
    GHashTable* map = gbinder_config_load(CONF_GROUP,
 | 
			
		||||
        gbinder_servicemanager_value_map);
 | 
			
		||||
 | 
			
		||||
    /* Add default configuration if it's not overridden */
 | 
			
		||||
    gbinder_servicemanager_map_add_default(map,
 | 
			
		||||
        GBINDER_DEFAULT_BINDER, SERVICEMANAGER_TYPE_AIDL);
 | 
			
		||||
    gbinder_servicemanager_map_add_default(map,
 | 
			
		||||
        GBINDER_DEFAULT_HWBINDER, SERVICEMANAGER_TYPE_HIDL);
 | 
			
		||||
 | 
			
		||||
    return map;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Runs at exit */
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicemanager_exit(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    if (gbinder_servicemanager_map) {
 | 
			
		||||
        g_hash_table_destroy(gbinder_servicemanager_map);
 | 
			
		||||
        gbinder_servicemanager_map = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    /* Reset the default too, mostly for unit testing */
 | 
			
		||||
    gbinder_servicemanager_default = SERVICEMANAGER_TYPE_DEFAULT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * Internal interface
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
@@ -424,9 +525,9 @@ gbinder_servicemanager_new_with_type(
 | 
			
		||||
        GBinderIpc* ipc;
 | 
			
		||||
 | 
			
		||||
        if (!dev) dev = klass->default_device;
 | 
			
		||||
        ipc = gbinder_ipc_new(dev, klass->rpc_protocol);
 | 
			
		||||
        ipc = gbinder_ipc_new(dev);
 | 
			
		||||
        if (ipc) {
 | 
			
		||||
            /* Create a possible dead remote object */
 | 
			
		||||
            /* Create a possibly dead remote object */
 | 
			
		||||
            GBinderRemoteObject* object = gbinder_ipc_get_remote_object
 | 
			
		||||
                (ipc, GBINDER_SERVICEMANAGER_HANDLE, TRUE);
 | 
			
		||||
 | 
			
		||||
@@ -517,11 +618,35 @@ GBinderServiceManager*
 | 
			
		||||
gbinder_servicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    if (!g_strcmp0(dev, GBINDER_DEFAULT_HWBINDER)) {
 | 
			
		||||
        return gbinder_hwservicemanager_new(dev);
 | 
			
		||||
    } else {
 | 
			
		||||
        return gbinder_defaultservicemanager_new(dev);
 | 
			
		||||
    if (dev) {
 | 
			
		||||
        const GBinderServiceManagerType* type = NULL;
 | 
			
		||||
 | 
			
		||||
        if (!gbinder_servicemanager_map) {
 | 
			
		||||
            const GBinderServiceManagerType* t;
 | 
			
		||||
 | 
			
		||||
            /* One-time initialization */
 | 
			
		||||
            gbinder_servicemanager_map = gbinder_servicemanager_load_config();
 | 
			
		||||
 | 
			
		||||
            /* "Default" is a special value stored in a special variable */
 | 
			
		||||
            t = g_hash_table_lookup(gbinder_servicemanager_map, CONF_DEFAULT);
 | 
			
		||||
            if (t) {
 | 
			
		||||
                g_hash_table_remove(gbinder_servicemanager_map, CONF_DEFAULT);
 | 
			
		||||
                gbinder_servicemanager_default = t;
 | 
			
		||||
            } else {
 | 
			
		||||
                gbinder_servicemanager_default = SERVICEMANAGER_TYPE_DEFAULT;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        type = g_hash_table_lookup(gbinder_servicemanager_map, dev);
 | 
			
		||||
        if (type) {
 | 
			
		||||
            GDEBUG("Using %s service manager for %s", type->name, dev);
 | 
			
		||||
        } else {
 | 
			
		||||
            type = gbinder_servicemanager_default;
 | 
			
		||||
            GDEBUG("Using default service manager %s for %s", type->name, dev);
 | 
			
		||||
        }
 | 
			
		||||
        return gbinder_servicemanager_new_with_type(type->get_type(), dev);
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderLocalObject*
 | 
			
		||||
@@ -870,6 +995,28 @@ gbinder_servicemanager_remove_handlers(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These two exist mostly for backward compatibility. Normally,
 | 
			
		||||
 * gbinder_servicemanager_new() should be used, to allow the type of
 | 
			
		||||
 * service manager to be configurable per device via /etc/gbinder.conf
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_defaultservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type
 | 
			
		||||
        (gbinder_servicemanager_aidl_get_type(), dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_hwservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type
 | 
			
		||||
        (gbinder_servicemanager_hidl_get_type(), dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * Internals
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,9 @@
 | 
			
		||||
 * THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "gbinder_servicemanager_p.h"
 | 
			
		||||
#include "gbinder_rpc_protocol.h"
 | 
			
		||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
 | 
			
		||||
 | 
			
		||||
#include "gbinder_servicemanager_aidl.h"
 | 
			
		||||
#include "gbinder_servicepoll.h"
 | 
			
		||||
#include "gbinder_eventloop_p.h"
 | 
			
		||||
#include "gbinder_log.h"
 | 
			
		||||
@@ -40,61 +41,47 @@
 | 
			
		||||
#include <gbinder_local_request.h>
 | 
			
		||||
#include <gbinder_remote_reply.h>
 | 
			
		||||
 | 
			
		||||
#include <gutil_macros.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
typedef struct gbinder_defaultservicemanager_watch {
 | 
			
		||||
typedef struct gbinder_servicemanager_aidl_watch {
 | 
			
		||||
    GBinderServicePoll* poll;
 | 
			
		||||
    char* name;
 | 
			
		||||
    gulong handler_id;
 | 
			
		||||
    GBinderEventLoopTimeout* notify;
 | 
			
		||||
} GBinderDefaultServiceManagerWatch;
 | 
			
		||||
} GBinderServiceManagerAidlWatch;
 | 
			
		||||
 | 
			
		||||
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass;
 | 
			
		||||
typedef struct gbinder_defaultservicemanager {
 | 
			
		||||
    GBinderServiceManager manager;
 | 
			
		||||
struct gbinder_servicemanager_aidl_priv {
 | 
			
		||||
    GBinderServicePoll* poll;
 | 
			
		||||
    GHashTable* watch_table;
 | 
			
		||||
} GBinderDefaultServiceManager;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE(GBinderDefaultServiceManager,
 | 
			
		||||
    gbinder_defaultservicemanager,
 | 
			
		||||
G_DEFINE_TYPE(GBinderServiceManagerAidl,
 | 
			
		||||
    gbinder_servicemanager_aidl,
 | 
			
		||||
    GBINDER_TYPE_SERVICEMANAGER)
 | 
			
		||||
 | 
			
		||||
#define PARENT_CLASS gbinder_defaultservicemanager_parent_class
 | 
			
		||||
#define GBINDER_TYPE_DEFAULTSERVICEMANAGER \
 | 
			
		||||
    gbinder_defaultservicemanager_get_type()
 | 
			
		||||
#define GBINDER_DEFAULTSERVICEMANAGER(obj) \
 | 
			
		||||
    G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_DEFAULTSERVICEMANAGER, \
 | 
			
		||||
    GBinderDefaultServiceManager)
 | 
			
		||||
#define PARENT_CLASS gbinder_servicemanager_aidl_parent_class
 | 
			
		||||
#define GBINDER_SERVICEMANAGER_AIDL(obj) \
 | 
			
		||||
    G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
 | 
			
		||||
    GBinderServiceManagerAidl)
 | 
			
		||||
#define GBINDER_SERVICEMANAGER_AIDL_GET_CLASS(obj) \
 | 
			
		||||
    G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
 | 
			
		||||
    GBinderServiceManagerAidlClass)
 | 
			
		||||
 | 
			
		||||
enum gbinder_defaultservicemanager_calls {
 | 
			
		||||
enum gbinder_servicemanager_aidl_calls {
 | 
			
		||||
    GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
 | 
			
		||||
    CHECK_SERVICE_TRANSACTION,
 | 
			
		||||
    ADD_SERVICE_TRANSACTION,
 | 
			
		||||
    LIST_SERVICES_TRANSACTION
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define DEFAULTSERVICEMANAGER_IFACE  "android.os.IServiceManager"
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_defaultservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type
 | 
			
		||||
        (GBINDER_TYPE_DEFAULTSERVICEMANAGER, dev);
 | 
			
		||||
}
 | 
			
		||||
#define SERVICEMANAGER_AIDL_IFACE  "android.os.IServiceManager"
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_watch_proc(
 | 
			
		||||
gbinder_servicemanager_aidl_watch_proc(
 | 
			
		||||
    GBinderServicePoll* poll,
 | 
			
		||||
    const char* name_added,
 | 
			
		||||
    void* user_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch = user_data;
 | 
			
		||||
    GBinderServiceManagerAidlWatch* watch = user_data;
 | 
			
		||||
 | 
			
		||||
    if (!g_strcmp0(name_added, watch->name)) {
 | 
			
		||||
        GBinderServiceManager* manager =
 | 
			
		||||
@@ -110,10 +97,10 @@ gbinder_defaultservicemanager_watch_proc(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_defaultservicemanager_watch_notify(
 | 
			
		||||
gbinder_servicemanager_aidl_watch_notify(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch = user_data;
 | 
			
		||||
    GBinderServiceManagerAidlWatch* watch = user_data;
 | 
			
		||||
    GBinderServiceManager* manager = gbinder_servicepoll_manager(watch->poll);
 | 
			
		||||
    char* name = g_strdup(watch->name);
 | 
			
		||||
 | 
			
		||||
@@ -126,54 +113,75 @@ gbinder_defaultservicemanager_watch_notify(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_watch_free(
 | 
			
		||||
gbinder_servicemanager_aidl_watch_free(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch = user_data;
 | 
			
		||||
    GBinderServiceManagerAidlWatch* watch = user_data;
 | 
			
		||||
 | 
			
		||||
    gbinder_timeout_remove(watch->notify);
 | 
			
		||||
    gbinder_servicepoll_remove_handler(watch->poll, watch->handler_id);
 | 
			
		||||
    gbinder_servicepoll_unref(watch->poll);
 | 
			
		||||
    g_free(watch->name);
 | 
			
		||||
    g_slice_free(GBinderDefaultServiceManagerWatch, watch);
 | 
			
		||||
    g_slice_free(GBinderServiceManagerAidlWatch, watch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderDefaultServiceManagerWatch*
 | 
			
		||||
gbinder_defaultservicemanager_watch_new(
 | 
			
		||||
    GBinderDefaultServiceManager* manager,
 | 
			
		||||
GBinderServiceManagerAidlWatch*
 | 
			
		||||
gbinder_servicemanager_aidl_watch_new(
 | 
			
		||||
    GBinderServiceManagerAidl* self,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch =
 | 
			
		||||
        g_slice_new0(GBinderDefaultServiceManagerWatch);
 | 
			
		||||
    GBinderServiceManagerAidlPriv* priv = self->priv;
 | 
			
		||||
    GBinderServiceManagerAidlWatch* watch =
 | 
			
		||||
        g_slice_new0(GBinderServiceManagerAidlWatch);
 | 
			
		||||
 | 
			
		||||
    watch->name = g_strdup(name);
 | 
			
		||||
    watch->poll = gbinder_servicepoll_new(&manager->manager, &manager->poll);
 | 
			
		||||
    watch->handler_id = gbinder_servicepoll_add_handler(watch->poll,
 | 
			
		||||
        gbinder_defaultservicemanager_watch_proc, watch);
 | 
			
		||||
    watch->poll = gbinder_servicepoll_new(&self->manager, &priv->poll);
 | 
			
		||||
    watch->handler_id = gbinder_servicepoll_add_handler(priv->poll,
 | 
			
		||||
        gbinder_servicemanager_aidl_watch_proc, watch);
 | 
			
		||||
    return watch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderLocalRequest*
 | 
			
		||||
gbinder_servicemanager_list_services_req(
 | 
			
		||||
    GBinderServiceManager* self,
 | 
			
		||||
gbinder_servicemanager_aidl_list_services_req(
 | 
			
		||||
    GBinderClient* client,
 | 
			
		||||
    gint32 index)
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_local_request_append_int32
 | 
			
		||||
        (gbinder_client_new_request(self->client), index);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_client_new_request(client);
 | 
			
		||||
 | 
			
		||||
    gbinder_local_request_append_int32(req, index);
 | 
			
		||||
    return req;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderLocalRequest*
 | 
			
		||||
gbinder_servicemanager_aidl_add_service_req(
 | 
			
		||||
    GBinderClient* client,
 | 
			
		||||
    const char* name,
 | 
			
		||||
    GBinderLocalObject* obj)
 | 
			
		||||
{
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_client_new_request(client);
 | 
			
		||||
 | 
			
		||||
    gbinder_local_request_append_string16(req, name);
 | 
			
		||||
    gbinder_local_request_append_local_object(req, obj);
 | 
			
		||||
    gbinder_local_request_append_int32(req, 0);
 | 
			
		||||
    return req;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
char**
 | 
			
		||||
gbinder_defaultservicemanager_list(
 | 
			
		||||
    GBinderServiceManager* self)
 | 
			
		||||
gbinder_servicemanager_aidl_list(
 | 
			
		||||
    GBinderServiceManager* manager)
 | 
			
		||||
{
 | 
			
		||||
    GPtrArray* list = g_ptr_array_new();
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_servicemanager_list_services_req(self,0);
 | 
			
		||||
    GBinderClient* client = manager->client;
 | 
			
		||||
    GBinderServiceManagerAidlClass* klass =
 | 
			
		||||
        GBINDER_SERVICEMANAGER_AIDL_GET_CLASS(manager);
 | 
			
		||||
    GBinderLocalRequest* req = klass->list_services_req(client, 0);
 | 
			
		||||
    GBinderRemoteReply* reply;
 | 
			
		||||
 | 
			
		||||
    while ((reply = gbinder_client_transact_sync_reply(self->client,
 | 
			
		||||
    while ((reply = gbinder_client_transact_sync_reply(client,
 | 
			
		||||
        LIST_SERVICES_TRANSACTION, req, NULL)) != NULL) {
 | 
			
		||||
        char* service = gbinder_remote_reply_read_string16(reply);
 | 
			
		||||
 | 
			
		||||
@@ -181,7 +189,7 @@ gbinder_defaultservicemanager_list(
 | 
			
		||||
        if (service) {
 | 
			
		||||
            g_ptr_array_add(list, service);
 | 
			
		||||
            gbinder_local_request_unref(req);
 | 
			
		||||
            req = gbinder_servicemanager_list_services_req(self, list->len);
 | 
			
		||||
            req = klass->list_services_req(client, list->len);
 | 
			
		||||
        } else {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
@@ -194,7 +202,7 @@ gbinder_defaultservicemanager_list(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderRemoteObject*
 | 
			
		||||
gbinder_defaultservicemanager_get_service(
 | 
			
		||||
gbinder_servicemanager_aidl_get_service(
 | 
			
		||||
    GBinderServiceManager* self,
 | 
			
		||||
    const char* name,
 | 
			
		||||
    int* status)
 | 
			
		||||
@@ -215,20 +223,16 @@ gbinder_defaultservicemanager_get_service(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
int
 | 
			
		||||
gbinder_defaultservicemanager_add_service(
 | 
			
		||||
    GBinderServiceManager* self,
 | 
			
		||||
gbinder_servicemanager_aidl_add_service(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name,
 | 
			
		||||
    GBinderLocalObject* obj)
 | 
			
		||||
{
 | 
			
		||||
    int status;
 | 
			
		||||
    GBinderRemoteReply* reply;
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_client_new_request(self->client);
 | 
			
		||||
 | 
			
		||||
    gbinder_local_request_append_string16(req, name);
 | 
			
		||||
    gbinder_local_request_append_local_object(req, obj);
 | 
			
		||||
    gbinder_local_request_append_int32(req, 0);
 | 
			
		||||
 | 
			
		||||
    reply = gbinder_client_transact_sync_reply(self->client,
 | 
			
		||||
    GBinderClient* client = manager->client;
 | 
			
		||||
    GBinderLocalRequest* req = GBINDER_SERVICEMANAGER_AIDL_GET_CLASS
 | 
			
		||||
        (manager)->add_service_req(client, name, obj);
 | 
			
		||||
    GBinderRemoteReply* reply = gbinder_client_transact_sync_reply(client,
 | 
			
		||||
        ADD_SERVICE_TRANSACTION, req, &status);
 | 
			
		||||
 | 
			
		||||
    gbinder_remote_reply_unref(reply);
 | 
			
		||||
@@ -238,7 +242,7 @@ gbinder_defaultservicemanager_add_service(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBINDER_SERVICEMANAGER_NAME_CHECK
 | 
			
		||||
gbinder_defaultservicemanager_check_name(
 | 
			
		||||
gbinder_servicemanager_aidl_check_name(
 | 
			
		||||
    GBinderServiceManager* self,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
@@ -247,69 +251,84 @@ gbinder_defaultservicemanager_check_name(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_defaultservicemanager_watch(
 | 
			
		||||
gbinder_servicemanager_aidl_watch(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(manager);
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch =
 | 
			
		||||
        gbinder_defaultservicemanager_watch_new(self, name);
 | 
			
		||||
    GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
 | 
			
		||||
    GBinderServiceManagerAidlPriv* priv = self->priv;
 | 
			
		||||
    GBinderServiceManagerAidlWatch* watch =
 | 
			
		||||
        gbinder_servicemanager_aidl_watch_new(self, name);
 | 
			
		||||
 | 
			
		||||
    g_hash_table_replace(self->watch_table, watch->name, watch);
 | 
			
		||||
    g_hash_table_replace(priv->watch_table, watch->name, watch);
 | 
			
		||||
    if (gbinder_servicepoll_is_known_name(watch->poll, name)) {
 | 
			
		||||
        watch->notify = gbinder_idle_add
 | 
			
		||||
            (gbinder_defaultservicemanager_watch_notify, watch);
 | 
			
		||||
            (gbinder_servicemanager_aidl_watch_notify, watch);
 | 
			
		||||
    }
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_unwatch(
 | 
			
		||||
gbinder_servicemanager_aidl_unwatch(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    g_hash_table_remove(GBINDER_DEFAULTSERVICEMANAGER(manager)->watch_table,
 | 
			
		||||
        name);
 | 
			
		||||
    GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
 | 
			
		||||
    GBinderServiceManagerAidlPriv* priv = self->priv;
 | 
			
		||||
 | 
			
		||||
    g_hash_table_remove(priv->watch_table, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_init(
 | 
			
		||||
    GBinderDefaultServiceManager* self)
 | 
			
		||||
gbinder_servicemanager_aidl_init(
 | 
			
		||||
    GBinderServiceManagerAidl* self)
 | 
			
		||||
{
 | 
			
		||||
    self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
 | 
			
		||||
        NULL, gbinder_defaultservicemanager_watch_free);
 | 
			
		||||
    GBinderServiceManagerAidlPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
 | 
			
		||||
        GBINDER_TYPE_SERVICEMANAGER_AIDL, GBinderServiceManagerAidlPriv);
 | 
			
		||||
 | 
			
		||||
    self->priv = priv;
 | 
			
		||||
    priv->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
 | 
			
		||||
        NULL, gbinder_servicemanager_aidl_watch_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_finalize(
 | 
			
		||||
gbinder_servicemanager_aidl_finalize(
 | 
			
		||||
    GObject* object)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(object);
 | 
			
		||||
    GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(object);
 | 
			
		||||
    GBinderServiceManagerAidlPriv* priv = self->priv;
 | 
			
		||||
 | 
			
		||||
    g_hash_table_destroy(self->watch_table);
 | 
			
		||||
    g_hash_table_destroy(priv->watch_table);
 | 
			
		||||
    G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_class_init(
 | 
			
		||||
    GBinderDefaultServiceManagerClass* klass)
 | 
			
		||||
gbinder_servicemanager_aidl_class_init(
 | 
			
		||||
    GBinderServiceManagerAidlClass* klass)
 | 
			
		||||
{
 | 
			
		||||
    klass->iface = DEFAULTSERVICEMANAGER_IFACE;
 | 
			
		||||
    klass->default_device = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    klass->rpc_protocol = &gbinder_rpc_protocol_binder;
 | 
			
		||||
    GBinderServiceManagerClass* manager = GBINDER_SERVICEMANAGER_CLASS(klass);
 | 
			
		||||
    GObjectClass* object = G_OBJECT_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    klass->list = gbinder_defaultservicemanager_list;
 | 
			
		||||
    klass->get_service = gbinder_defaultservicemanager_get_service;
 | 
			
		||||
    klass->add_service = gbinder_defaultservicemanager_add_service;
 | 
			
		||||
    klass->check_name = gbinder_defaultservicemanager_check_name;
 | 
			
		||||
    g_type_class_add_private(klass, sizeof(GBinderServiceManagerAidlPriv));
 | 
			
		||||
    klass->list_services_req = gbinder_servicemanager_aidl_list_services_req;
 | 
			
		||||
    klass->add_service_req = gbinder_servicemanager_aidl_add_service_req;
 | 
			
		||||
 | 
			
		||||
    manager->iface = SERVICEMANAGER_AIDL_IFACE;
 | 
			
		||||
    manager->default_device = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
 | 
			
		||||
    manager->list = gbinder_servicemanager_aidl_list;
 | 
			
		||||
    manager->get_service = gbinder_servicemanager_aidl_get_service;
 | 
			
		||||
    manager->add_service = gbinder_servicemanager_aidl_add_service;
 | 
			
		||||
    manager->check_name = gbinder_servicemanager_aidl_check_name;
 | 
			
		||||
    /* normalize_name is not needed */
 | 
			
		||||
    klass->watch = gbinder_defaultservicemanager_watch;
 | 
			
		||||
    klass->unwatch = gbinder_defaultservicemanager_unwatch;
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = gbinder_defaultservicemanager_finalize;
 | 
			
		||||
    manager->watch = gbinder_servicemanager_aidl_watch;
 | 
			
		||||
    manager->unwatch = gbinder_servicemanager_aidl_unwatch;
 | 
			
		||||
 | 
			
		||||
    object->finalize = gbinder_servicemanager_aidl_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
							
								
								
									
										66
									
								
								src/gbinder_servicemanager_aidl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/gbinder_servicemanager_aidl.h
									
									
									
									
									
										Normal 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:
 | 
			
		||||
 */
 | 
			
		||||
							
								
								
									
										102
									
								
								src/gbinder_servicemanager_aidl2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/gbinder_servicemanager_aidl2.c
									
									
									
									
									
										Normal 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:
 | 
			
		||||
 */
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -14,8 +14,8 @@
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived from
 | 
			
		||||
 *      this software without specific prior written permission.
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -31,7 +31,6 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "gbinder_servicemanager_p.h"
 | 
			
		||||
#include "gbinder_rpc_protocol.h"
 | 
			
		||||
#include "gbinder_log.h"
 | 
			
		||||
 | 
			
		||||
#include <gbinder_client.h>
 | 
			
		||||
@@ -42,30 +41,30 @@
 | 
			
		||||
#include <gbinder_reader.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
typedef struct gbinder_hwservicemanager_watch {
 | 
			
		||||
typedef struct gbinder_servicemanager_hidl_watch {
 | 
			
		||||
    char* name;
 | 
			
		||||
    GBinderLocalObject* callback;
 | 
			
		||||
} GBinderHwServiceManagerWatch;
 | 
			
		||||
} GBinderServiceManagerHidlWatch;
 | 
			
		||||
 | 
			
		||||
typedef GBinderServiceManagerClass GBinderHwServiceManagerClass;
 | 
			
		||||
typedef struct gbinder_hwservicemanager {
 | 
			
		||||
typedef GBinderServiceManagerClass GBinderServiceManagerHidlClass;
 | 
			
		||||
typedef struct gbinder_servicemanager_hidl {
 | 
			
		||||
    GBinderServiceManager manager;
 | 
			
		||||
    GHashTable* watch_table;
 | 
			
		||||
} GBinderHwServiceManager;
 | 
			
		||||
} GBinderServiceManagerHidl;
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE(GBinderHwServiceManager,
 | 
			
		||||
    gbinder_hwservicemanager,
 | 
			
		||||
G_DEFINE_TYPE(GBinderServiceManagerHidl,
 | 
			
		||||
    gbinder_servicemanager_hidl,
 | 
			
		||||
    GBINDER_TYPE_SERVICEMANAGER)
 | 
			
		||||
 | 
			
		||||
#define PARENT_CLASS gbinder_hwservicemanager_parent_class
 | 
			
		||||
#define GBINDER_TYPE_HWSERVICEMANAGER (gbinder_hwservicemanager_get_type())
 | 
			
		||||
#define GBINDER_HWSERVICEMANAGER(obj) \
 | 
			
		||||
    G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_HWSERVICEMANAGER, \
 | 
			
		||||
    GBinderHwServiceManager)
 | 
			
		||||
#define PARENT_CLASS gbinder_servicemanager_hidl_parent_class
 | 
			
		||||
#define GBINDER_TYPE_SERVICEMANAGER_HIDL \
 | 
			
		||||
    gbinder_servicemanager_hidl_get_type()
 | 
			
		||||
#define GBINDER_SERVICEMANAGER_HIDL(obj) \
 | 
			
		||||
    G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER_HIDL, \
 | 
			
		||||
    GBinderServiceManagerHidl)
 | 
			
		||||
 | 
			
		||||
enum gbinder_hwservicemanager_calls {
 | 
			
		||||
enum gbinder_servicemanager_hidl_calls {
 | 
			
		||||
    GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
 | 
			
		||||
    ADD_TRANSACTION,
 | 
			
		||||
    GET_TRANSPORT_TRANSACTION,
 | 
			
		||||
@@ -76,18 +75,18 @@ enum gbinder_hwservicemanager_calls {
 | 
			
		||||
    REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum gbinder_hwservicemanager_notifications {
 | 
			
		||||
enum gbinder_servicemanager_hidl_notifications {
 | 
			
		||||
    ON_REGISTRATION_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define HWSERVICEMANAGER_IFACE  "android.hidl.manager@1.0::IServiceManager"
 | 
			
		||||
#define HWSERVICEMANAGER_NOTIFICATION_IFACE \
 | 
			
		||||
#define SERVICEMANAGER_HIDL_IFACE  "android.hidl.manager@1.0::IServiceManager"
 | 
			
		||||
#define SERVICEMANAGER_HIDL_NOTIFICATION_IFACE \
 | 
			
		||||
    "android.hidl.manager@1.0::IServiceNotification"
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_hwservicemanager_handle_registration(
 | 
			
		||||
    GBinderHwServiceManager* self,
 | 
			
		||||
gbinder_servicemanager_hidl_handle_registration(
 | 
			
		||||
    GBinderServiceManagerHidl* self,
 | 
			
		||||
    GBinderReader* reader)
 | 
			
		||||
{
 | 
			
		||||
    char* fqname = gbinder_reader_read_hidl_string(reader);
 | 
			
		||||
@@ -111,7 +110,7 @@ gbinder_hwservicemanager_handle_registration(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderLocalReply*
 | 
			
		||||
gbinder_hwservicemanager_notification(
 | 
			
		||||
gbinder_servicemanager_hidl_notification(
 | 
			
		||||
    GBinderLocalObject* obj,
 | 
			
		||||
    GBinderRemoteRequest* req,
 | 
			
		||||
    guint code,
 | 
			
		||||
@@ -119,22 +118,22 @@ gbinder_hwservicemanager_notification(
 | 
			
		||||
    int* status,
 | 
			
		||||
    void* user_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(user_data);
 | 
			
		||||
    GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(user_data);
 | 
			
		||||
    const char* iface = gbinder_remote_request_interface(req);
 | 
			
		||||
 | 
			
		||||
    if (!g_strcmp0(iface, HWSERVICEMANAGER_NOTIFICATION_IFACE)) {
 | 
			
		||||
    if (!g_strcmp0(iface, SERVICEMANAGER_HIDL_NOTIFICATION_IFACE)) {
 | 
			
		||||
        GBinderReader reader;
 | 
			
		||||
 | 
			
		||||
        gbinder_remote_request_init_reader(req, &reader);
 | 
			
		||||
        switch (code) {
 | 
			
		||||
        case ON_REGISTRATION_TRANSACTION:
 | 
			
		||||
            GDEBUG(HWSERVICEMANAGER_NOTIFICATION_IFACE " %u onRegistration",
 | 
			
		||||
            GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u onRegistration",
 | 
			
		||||
                code);
 | 
			
		||||
            gbinder_hwservicemanager_handle_registration(self, &reader);
 | 
			
		||||
            gbinder_servicemanager_hidl_handle_registration(self, &reader);
 | 
			
		||||
            *status = GBINDER_STATUS_OK;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            GDEBUG(HWSERVICEMANAGER_NOTIFICATION_IFACE " %u", code);
 | 
			
		||||
            GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u", code);
 | 
			
		||||
            *status = GBINDER_STATUS_FAILED;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
@@ -145,17 +144,9 @@ gbinder_hwservicemanager_notification(
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_hwservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type
 | 
			
		||||
        (gbinder_hwservicemanager_get_type(), dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
char**
 | 
			
		||||
gbinder_hwservicemanager_list(
 | 
			
		||||
gbinder_servicemanager_hidl_list(
 | 
			
		||||
    GBinderServiceManager* self)
 | 
			
		||||
{
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_client_new_request(self->client);
 | 
			
		||||
@@ -184,7 +175,7 @@ gbinder_hwservicemanager_list(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderRemoteObject*
 | 
			
		||||
gbinder_hwservicemanager_get_service(
 | 
			
		||||
gbinder_servicemanager_hidl_get_service(
 | 
			
		||||
    GBinderServiceManager* self,
 | 
			
		||||
    const char* fqinstance,
 | 
			
		||||
    int* status)
 | 
			
		||||
@@ -231,7 +222,7 @@ gbinder_hwservicemanager_get_service(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
int
 | 
			
		||||
gbinder_hwservicemanager_add_service(
 | 
			
		||||
gbinder_servicemanager_hidl_add_service(
 | 
			
		||||
    GBinderServiceManager* self,
 | 
			
		||||
    const char* name,
 | 
			
		||||
    GBinderLocalObject* obj)
 | 
			
		||||
@@ -254,10 +245,10 @@ gbinder_hwservicemanager_add_service(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_hwservicemanager_watch_free(
 | 
			
		||||
gbinder_servicemanager_hidl_watch_free(
 | 
			
		||||
    gpointer data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderHwServiceManagerWatch* watch = data;
 | 
			
		||||
    GBinderServiceManagerHidlWatch* watch = data;
 | 
			
		||||
 | 
			
		||||
    g_free(watch->name);
 | 
			
		||||
    gbinder_local_object_drop(watch->callback);
 | 
			
		||||
@@ -266,7 +257,7 @@ gbinder_hwservicemanager_watch_free(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBINDER_SERVICEMANAGER_NAME_CHECK
 | 
			
		||||
gbinder_hwservicemanager_check_name(
 | 
			
		||||
gbinder_servicemanager_hidl_check_name(
 | 
			
		||||
    GBinderServiceManager* self,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
@@ -287,32 +278,32 @@ gbinder_hwservicemanager_check_name(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
char*
 | 
			
		||||
gbinder_hwservicemanager_normalize_name(
 | 
			
		||||
gbinder_servicemanager_hidl_normalize_name(
 | 
			
		||||
    GBinderServiceManager* self,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    /* Slash must be there, see gbinder_hwservicemanager_check_name() above */
 | 
			
		||||
    /* Slash must be there, see gbinder_servicemanager_hidl_check_name() */
 | 
			
		||||
    return g_strndup(name, strchr(name, '/') - name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_hwservicemanager_watch(
 | 
			
		||||
gbinder_servicemanager_hidl_watch(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(manager);
 | 
			
		||||
    GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(manager);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_client_new_request(manager->client);
 | 
			
		||||
    GBinderRemoteReply* reply;
 | 
			
		||||
    GBinderHwServiceManagerWatch* watch =
 | 
			
		||||
        g_new0(GBinderHwServiceManagerWatch, 1);
 | 
			
		||||
    GBinderServiceManagerHidlWatch* watch =
 | 
			
		||||
        g_new0(GBinderServiceManagerHidlWatch, 1);
 | 
			
		||||
    gboolean success = FALSE;
 | 
			
		||||
    int status;
 | 
			
		||||
 | 
			
		||||
    watch->name = g_strdup(name);
 | 
			
		||||
    watch->callback = gbinder_servicemanager_new_local_object(manager,
 | 
			
		||||
        HWSERVICEMANAGER_NOTIFICATION_IFACE,
 | 
			
		||||
        gbinder_hwservicemanager_notification, self);
 | 
			
		||||
        SERVICEMANAGER_HIDL_NOTIFICATION_IFACE,
 | 
			
		||||
        gbinder_servicemanager_hidl_notification, self);
 | 
			
		||||
    g_hash_table_replace(self->watch_table, watch->name, watch);
 | 
			
		||||
 | 
			
		||||
    /* registerForNotifications(string fqName, string name,
 | 
			
		||||
@@ -344,28 +335,29 @@ gbinder_hwservicemanager_watch(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_hwservicemanager_unwatch(
 | 
			
		||||
gbinder_servicemanager_hidl_unwatch(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    g_hash_table_remove(GBINDER_HWSERVICEMANAGER(manager)->watch_table, name);
 | 
			
		||||
    g_hash_table_remove(GBINDER_SERVICEMANAGER_HIDL(manager)->
 | 
			
		||||
        watch_table, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_hwservicemanager_init(
 | 
			
		||||
    GBinderHwServiceManager* self)
 | 
			
		||||
gbinder_servicemanager_hidl_init(
 | 
			
		||||
    GBinderServiceManagerHidl* self)
 | 
			
		||||
{
 | 
			
		||||
    self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
 | 
			
		||||
        NULL, gbinder_hwservicemanager_watch_free);
 | 
			
		||||
        NULL, gbinder_servicemanager_hidl_watch_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_hwservicemanager_finalize(
 | 
			
		||||
gbinder_servicemanager_hidl_finalize(
 | 
			
		||||
    GObject* object)
 | 
			
		||||
{
 | 
			
		||||
    GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(object);
 | 
			
		||||
    GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(object);
 | 
			
		||||
 | 
			
		||||
    g_hash_table_destroy(self->watch_table);
 | 
			
		||||
    G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
 | 
			
		||||
@@ -373,21 +365,20 @@ gbinder_hwservicemanager_finalize(
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_hwservicemanager_class_init(
 | 
			
		||||
    GBinderHwServiceManagerClass* klass)
 | 
			
		||||
gbinder_servicemanager_hidl_class_init(
 | 
			
		||||
    GBinderServiceManagerHidlClass* klass)
 | 
			
		||||
{
 | 
			
		||||
    klass->iface = HWSERVICEMANAGER_IFACE;
 | 
			
		||||
    klass->iface = SERVICEMANAGER_HIDL_IFACE;
 | 
			
		||||
    klass->default_device = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;
 | 
			
		||||
 | 
			
		||||
    klass->list = gbinder_hwservicemanager_list;
 | 
			
		||||
    klass->get_service = gbinder_hwservicemanager_get_service;
 | 
			
		||||
    klass->add_service = gbinder_hwservicemanager_add_service;
 | 
			
		||||
    klass->check_name = gbinder_hwservicemanager_check_name;
 | 
			
		||||
    klass->normalize_name = gbinder_hwservicemanager_normalize_name;
 | 
			
		||||
    klass->watch = gbinder_hwservicemanager_watch;
 | 
			
		||||
    klass->unwatch = gbinder_hwservicemanager_unwatch;
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = gbinder_hwservicemanager_finalize;
 | 
			
		||||
    klass->list = gbinder_servicemanager_hidl_list;
 | 
			
		||||
    klass->get_service = gbinder_servicemanager_hidl_get_service;
 | 
			
		||||
    klass->add_service = gbinder_servicemanager_hidl_add_service;
 | 
			
		||||
    klass->check_name = gbinder_servicemanager_hidl_check_name;
 | 
			
		||||
    klass->normalize_name = gbinder_servicemanager_hidl_normalize_name;
 | 
			
		||||
    klass->watch = gbinder_servicemanager_hidl_watch;
 | 
			
		||||
    klass->unwatch = gbinder_servicemanager_hidl_unwatch;
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = gbinder_servicemanager_hidl_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -64,7 +64,6 @@ typedef struct gbinder_servicemanager_class {
 | 
			
		||||
 | 
			
		||||
    const char* iface;
 | 
			
		||||
    const char* default_device;
 | 
			
		||||
    const GBinderRpcProtocol* rpc_protocol;
 | 
			
		||||
 | 
			
		||||
    /* Methods (synchronous) */
 | 
			
		||||
    char** (*list)(GBinderServiceManager* self);
 | 
			
		||||
@@ -86,6 +85,9 @@ typedef struct gbinder_servicemanager_class {
 | 
			
		||||
 | 
			
		||||
GType gbinder_servicemanager_get_type(void) GBINDER_INTERNAL;
 | 
			
		||||
#define GBINDER_TYPE_SERVICEMANAGER (gbinder_servicemanager_get_type())
 | 
			
		||||
#define GBINDER_SERVICEMANAGER_CLASS(klass) \
 | 
			
		||||
    G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
 | 
			
		||||
    GBinderServiceManagerClass)
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_servicemanager_new_with_type(
 | 
			
		||||
@@ -99,6 +101,19 @@ gbinder_servicemanager_service_registered(
 | 
			
		||||
    const char* name)
 | 
			
		||||
    GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
/* Declared for unit tests */
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicemanager_exit(
 | 
			
		||||
    void)
 | 
			
		||||
    GBINDER_INTERNAL
 | 
			
		||||
    GBINDER_DESTRUCTOR;
 | 
			
		||||
 | 
			
		||||
/* Derived types */
 | 
			
		||||
 | 
			
		||||
GType gbinder_servicemanager_aidl_get_type(void) GBINDER_INTERNAL;
 | 
			
		||||
GType gbinder_servicemanager_aidl2_get_type(void) GBINDER_INTERNAL;
 | 
			
		||||
GType gbinder_servicemanager_hidl_get_type(void) GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
#endif /* GBINDER_SERVICEMANAGER_PRIVATE_H */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,7 @@ typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
 | 
			
		||||
 | 
			
		||||
#define GBINDER_INLINE_FUNC static inline
 | 
			
		||||
#define GBINDER_INTERNAL G_GNUC_INTERNAL
 | 
			
		||||
#define GBINDER_DESTRUCTOR __attribute__((destructor))
 | 
			
		||||
 | 
			
		||||
#define GBINDER_TRANSACTION(c2,c3,c4)     GBINDER_FOURCC('_',c2,c3,c4)
 | 
			
		||||
#define GBINDER_PING_TRANSACTION          GBINDER_TRANSACTION('P','N','G')
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ all:
 | 
			
		||||
	@$(MAKE) -C unit_buffer $*
 | 
			
		||||
	@$(MAKE) -C unit_cleanup $*
 | 
			
		||||
	@$(MAKE) -C unit_client $*
 | 
			
		||||
	@$(MAKE) -C unit_config $*
 | 
			
		||||
	@$(MAKE) -C unit_driver $*
 | 
			
		||||
	@$(MAKE) -C unit_eventloop $*
 | 
			
		||||
	@$(MAKE) -C unit_ipc $*
 | 
			
		||||
@@ -18,6 +19,7 @@ all:
 | 
			
		||||
	@$(MAKE) -C unit_remote_reply $*
 | 
			
		||||
	@$(MAKE) -C unit_remote_request $*
 | 
			
		||||
	@$(MAKE) -C unit_servicemanager $*
 | 
			
		||||
	@$(MAKE) -C unit_servicemanager_aidl $*
 | 
			
		||||
	@$(MAKE) -C unit_servicename $*
 | 
			
		||||
	@$(MAKE) -C unit_servicepoll $*
 | 
			
		||||
	@$(MAKE) -C unit_writer $*
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
 | 
			
		||||
 | 
			
		||||
CC ?= $(CROSS_COMPILE)gcc
 | 
			
		||||
LD = $(CC)
 | 
			
		||||
WARNINGS += -Wall
 | 
			
		||||
WARNINGS += -Wall -Wno-deprecated-declarations
 | 
			
		||||
INCLUDES += -I$(COMMON_DIR) -I$(LIB_DIR)/src -I$(LIB_DIR)/include
 | 
			
		||||
BASE_FLAGS = -fPIC
 | 
			
		||||
BASE_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -14,8 +14,8 @@
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived from
 | 
			
		||||
 *      this software without specific prior written permission.
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -30,6 +30,8 @@
 | 
			
		||||
 * THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "test_binder.h"
 | 
			
		||||
#include "gbinder_local_object.h"
 | 
			
		||||
#include "gbinder_system.h"
 | 
			
		||||
 | 
			
		||||
#define GLOG_MODULE_NAME test_binder_log
 | 
			
		||||
@@ -47,19 +49,26 @@ static GHashTable* test_fd_map = NULL;
 | 
			
		||||
static GHashTable* test_node_map = NULL;
 | 
			
		||||
static GPrivate test_looper;
 | 
			
		||||
 | 
			
		||||
#define public_fd  fd[0]
 | 
			
		||||
#define private_fd fd[1]
 | 
			
		||||
G_LOCK_DEFINE_STATIC(test_binder);
 | 
			
		||||
 | 
			
		||||
#define PUBLIC (0)
 | 
			
		||||
#define PRIVATE (1)
 | 
			
		||||
#define public_fd  node[PUBLIC].fd
 | 
			
		||||
#define private_fd node[PRIVATE].fd
 | 
			
		||||
 | 
			
		||||
#define BINDER_VERSION _IOWR('b', 9, gint32)
 | 
			
		||||
#define BINDER_SET_MAX_THREADS _IOW('b', 5, guint32)
 | 
			
		||||
 | 
			
		||||
#define B_TYPE_LARGE 0x85
 | 
			
		||||
#define BINDER_TYPE_BINDER  GBINDER_FOURCC('s', 'b', '*', B_TYPE_LARGE)
 | 
			
		||||
#define BINDER_TYPE_HANDLE  GBINDER_FOURCC('s', 'h', '*', B_TYPE_LARGE)
 | 
			
		||||
 | 
			
		||||
#define TF_ONE_WAY     0x01
 | 
			
		||||
#define TF_ROOT_OBJECT 0x04
 | 
			
		||||
#define TF_STATUS_CODE 0x08
 | 
			
		||||
#define TF_ACCEPT_FDS  0x10
 | 
			
		||||
 | 
			
		||||
typedef struct test_binder_io TestBinderIo;
 | 
			
		||||
typedef struct test_binder TestBinder;
 | 
			
		||||
 | 
			
		||||
typedef
 | 
			
		||||
void
 | 
			
		||||
@@ -77,23 +86,33 @@ typedef struct test_binder_submit_thread {
 | 
			
		||||
} TestBinderSubmitThread;
 | 
			
		||||
 | 
			
		||||
typedef struct test_binder_node {
 | 
			
		||||
    int fd;
 | 
			
		||||
    char* path;
 | 
			
		||||
    int refcount;
 | 
			
		||||
    const TestBinderIo* io;
 | 
			
		||||
    GHashTable* destroy_map;
 | 
			
		||||
    TestBinder* binder;
 | 
			
		||||
    gboolean looper_enabled;
 | 
			
		||||
} TestBinderNode;
 | 
			
		||||
 | 
			
		||||
typedef struct test_binder {
 | 
			
		||||
typedef struct test_binder_fd {
 | 
			
		||||
    int fd;
 | 
			
		||||
    GHashTable* destroy_map;
 | 
			
		||||
    TestBinderNode* node;
 | 
			
		||||
} TestBinderFd;
 | 
			
		||||
 | 
			
		||||
typedef struct test_binder {
 | 
			
		||||
    gint refcount;
 | 
			
		||||
    const TestBinderIo* io;
 | 
			
		||||
    GHashTable* object_map; /* GBinderLocalObject* => handle */
 | 
			
		||||
    GHashTable* handle_map; /* handle => GBinderLocalObject* */
 | 
			
		||||
    TestBinderSubmitThread* submit_thread;
 | 
			
		||||
    gboolean looper_enabled;
 | 
			
		||||
    int fd[2];
 | 
			
		||||
    GMutex mutex;
 | 
			
		||||
    gboolean passthrough;
 | 
			
		||||
    TestBinderNode node[2];
 | 
			
		||||
} TestBinder;
 | 
			
		||||
 | 
			
		||||
struct test_binder_io {
 | 
			
		||||
    int version;
 | 
			
		||||
    int write_read_request;
 | 
			
		||||
    int (*handle_write_read)(TestBinder* binder, void* data);
 | 
			
		||||
    int (*handle_write_read)(TestBinderFd* fd, void* data);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct binder_write_read_64 {
 | 
			
		||||
@@ -128,6 +147,13 @@ typedef struct binder_handle_cookie_64 {
 | 
			
		||||
  guint64 cookie;
 | 
			
		||||
} __attribute__((packed)) BinderHandleCookie64;
 | 
			
		||||
 | 
			
		||||
typedef struct binder_object_64 {
 | 
			
		||||
  guint32 type;
 | 
			
		||||
  guint32 flags;
 | 
			
		||||
  guint64 object;
 | 
			
		||||
  guint64 cookie;
 | 
			
		||||
} BinderObject64;
 | 
			
		||||
 | 
			
		||||
#define BC_TRANSACTION_64       _IOW('c', 0, BinderTransactionData64)
 | 
			
		||||
#define BC_REPLY_64             _IOW('c', 1, BinderTransactionData64)
 | 
			
		||||
#define BC_FREE_BUFFER_64       _IOW('c', 3, guint64)
 | 
			
		||||
@@ -259,74 +285,202 @@ test_binder_submit_later(
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_io_free_buffer(
 | 
			
		||||
    TestBinder* binder,
 | 
			
		||||
    TestBinderFd* fd,
 | 
			
		||||
    void* ptr)
 | 
			
		||||
{
 | 
			
		||||
    if (ptr) {
 | 
			
		||||
        TestBinderNode* node = binder->node;
 | 
			
		||||
        GDestroyNotify destroy = g_hash_table_lookup(node->destroy_map, ptr);
 | 
			
		||||
        GDestroyNotify destroy;
 | 
			
		||||
 | 
			
		||||
        G_LOCK(test_binder);
 | 
			
		||||
        destroy = g_hash_table_lookup(fd->destroy_map, ptr);
 | 
			
		||||
        if (destroy) {
 | 
			
		||||
            g_hash_table_remove(node->destroy_map, ptr);
 | 
			
		||||
            g_hash_table_remove(fd->destroy_map, ptr);
 | 
			
		||||
            destroy(ptr);
 | 
			
		||||
        } else {
 | 
			
		||||
            g_free(ptr);
 | 
			
		||||
        }
 | 
			
		||||
        G_UNLOCK(test_binder);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
test_binder_exit_wait(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    struct timespec wait;
 | 
			
		||||
 | 
			
		||||
    wait.tv_nsec = 100 * 1000000; /* 100 ms */
 | 
			
		||||
    wait.tv_sec = 0;
 | 
			
		||||
    G_LOCK(test_binder);
 | 
			
		||||
    while (test_node_map) {
 | 
			
		||||
        GDEBUG("Waiting for loopers to exit...");
 | 
			
		||||
        G_UNLOCK(test_binder);
 | 
			
		||||
        nanosleep(&wait, &wait);
 | 
			
		||||
        G_LOCK(test_binder);
 | 
			
		||||
    }
 | 
			
		||||
    G_UNLOCK(test_binder);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
guint64
 | 
			
		||||
test_io_passthough_fix_handle(
 | 
			
		||||
    TestBinder* binder,
 | 
			
		||||
    guint64 handle)
 | 
			
		||||
{
 | 
			
		||||
    gpointer key = GSIZE_TO_POINTER(handle);
 | 
			
		||||
 | 
			
		||||
    /* Invoked under lock */
 | 
			
		||||
    if (g_hash_table_contains(binder->object_map, key)) {
 | 
			
		||||
        gpointer value = g_hash_table_lookup(binder->object_map, key);
 | 
			
		||||
 | 
			
		||||
        handle = GPOINTER_TO_SIZE(value);
 | 
			
		||||
        GDEBUG("Object %p => handle %u", key, (guint) handle);
 | 
			
		||||
    } else if (g_hash_table_contains(binder->handle_map, key)) {
 | 
			
		||||
        gpointer obj = g_hash_table_lookup(binder->handle_map, key);
 | 
			
		||||
 | 
			
		||||
        GDEBUG("Handle %u => object %p", (guint) handle, obj);
 | 
			
		||||
        handle = GPOINTER_TO_SIZE(obj);
 | 
			
		||||
    }
 | 
			
		||||
    return handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gssize
 | 
			
		||||
test_io_passthough_write_64(
 | 
			
		||||
    TestBinderFd* fd,
 | 
			
		||||
    const void* bytes,
 | 
			
		||||
    gsize bytes_to_write)
 | 
			
		||||
{
 | 
			
		||||
    const guint code = *(guint32*)bytes;
 | 
			
		||||
    TestBinderNode* node = fd->node;
 | 
			
		||||
    TestBinder* binder = node->binder;
 | 
			
		||||
    BinderTransactionData64* tx = NULL;
 | 
			
		||||
    gssize bytes_written;
 | 
			
		||||
    guint extra;
 | 
			
		||||
    guint32* cmd;
 | 
			
		||||
    void* data;
 | 
			
		||||
 | 
			
		||||
    /* Just ignore some codes for now */
 | 
			
		||||
    switch (code) {
 | 
			
		||||
    case BC_ACQUIRE:
 | 
			
		||||
    case BC_RELEASE:
 | 
			
		||||
    case BC_REQUEST_DEATH_NOTIFICATION_64:
 | 
			
		||||
    case BC_CLEAR_DEATH_NOTIFICATION_64:
 | 
			
		||||
        return bytes_to_write;
 | 
			
		||||
    default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cmd = g_memdup(bytes, bytes_to_write);
 | 
			
		||||
    data = cmd + 1;
 | 
			
		||||
    switch (*cmd) {
 | 
			
		||||
    case BR_TRANSACTION_64:
 | 
			
		||||
        *cmd = BC_TRANSACTION_64;
 | 
			
		||||
        tx = data;
 | 
			
		||||
        break;
 | 
			
		||||
    case BC_TRANSACTION_64:
 | 
			
		||||
        *cmd = BR_TRANSACTION_64;
 | 
			
		||||
         tx = data;
 | 
			
		||||
       break;
 | 
			
		||||
    case BR_REPLY_64:
 | 
			
		||||
        *cmd = BC_REPLY_64;
 | 
			
		||||
        tx = data;
 | 
			
		||||
        break;
 | 
			
		||||
    case BC_REPLY_64:
 | 
			
		||||
        extra = BR_TRANSACTION_COMPLETE;
 | 
			
		||||
        write(fd->fd, &extra, sizeof(extra));
 | 
			
		||||
        *cmd = BR_REPLY_64;
 | 
			
		||||
        tx = data;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    if (tx) {
 | 
			
		||||
        guint32* data_buffer = g_memdup(GSIZE_TO_POINTER(tx->data_buffer),
 | 
			
		||||
            tx->data_size);
 | 
			
		||||
        void* data_offsets = g_memdup(GSIZE_TO_POINTER(tx->data_offsets),
 | 
			
		||||
            tx->offsets_size);
 | 
			
		||||
 | 
			
		||||
        G_LOCK(test_binder);
 | 
			
		||||
        tx->handle = test_io_passthough_fix_handle(binder, tx->handle);
 | 
			
		||||
        if (data_buffer && tx->data_size > sizeof(BinderObject64)) {
 | 
			
		||||
            /* Replace BINDER_TYPE_BINDER with BINDER_TYPE_HANDLE */
 | 
			
		||||
            guint32* data_ptr = data_buffer;
 | 
			
		||||
            const guint32* data_end = data_buffer + (tx->data_size -
 | 
			
		||||
                sizeof(BinderObject64))/sizeof(guint32);
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             * Objects are supposed to be aligned at 32-bit boundary, so we
 | 
			
		||||
             * can scanning the data buffer with 4-byte step.
 | 
			
		||||
             */
 | 
			
		||||
            for (data_ptr = data_buffer; data_ptr < data_end; data_ptr++) {
 | 
			
		||||
                if (*data_ptr == BINDER_TYPE_BINDER) {
 | 
			
		||||
                    BinderObject64* object = (BinderObject64*) data_ptr;
 | 
			
		||||
 | 
			
		||||
                    object->type = BINDER_TYPE_HANDLE;
 | 
			
		||||
                    object->object = test_io_passthough_fix_handle(binder,
 | 
			
		||||
                        object->object);
 | 
			
		||||
                    data_ptr += sizeof(object)/sizeof(guint32) - 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        g_hash_table_replace(fd->destroy_map, data_offsets, NULL);
 | 
			
		||||
        G_UNLOCK(test_binder);
 | 
			
		||||
        tx->data_buffer = GPOINTER_TO_SIZE(data_buffer);
 | 
			
		||||
        tx->data_offsets = GPOINTER_TO_SIZE(data_offsets);
 | 
			
		||||
    }
 | 
			
		||||
    bytes_written = write(fd->fd, cmd, bytes_to_write);
 | 
			
		||||
    g_free(cmd);
 | 
			
		||||
    return bytes_written;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
int
 | 
			
		||||
test_io_handle_write_read_64(
 | 
			
		||||
    TestBinder* binder,
 | 
			
		||||
    TestBinderFd* fd,
 | 
			
		||||
    void* data)
 | 
			
		||||
{
 | 
			
		||||
    TestBinderNode* node = fd->node;
 | 
			
		||||
    TestBinder* binder = node->binder;
 | 
			
		||||
    BinderWriteRead64* wr = data;
 | 
			
		||||
    gssize bytes_left = wr->write_size - wr->write_consumed;
 | 
			
		||||
    const guint8* write_ptr = (void*)(gsize)
 | 
			
		||||
        (wr->write_buffer + wr->write_consumed);
 | 
			
		||||
    const guint8* write_ptr = (void*)(gsize)(wr->write_buffer +
 | 
			
		||||
        wr->write_consumed);
 | 
			
		||||
    gboolean is_looper;
 | 
			
		||||
 | 
			
		||||
    while (bytes_left >= sizeof(guint32)) {
 | 
			
		||||
        const guint cmd = *(guint32*)write_ptr;
 | 
			
		||||
        const guint cmdsize = _IOC_SIZE(cmd);
 | 
			
		||||
        const void* cmddata = write_ptr + sizeof(guint32);
 | 
			
		||||
        const gsize bytes_to_write = sizeof(guint32) + cmdsize;
 | 
			
		||||
 | 
			
		||||
        GASSERT(bytes_left >= (sizeof(guint32) + cmdsize));
 | 
			
		||||
        if (bytes_left >= (sizeof(guint32) + cmdsize)) {
 | 
			
		||||
            wr->write_consumed += sizeof(guint32);
 | 
			
		||||
            write_ptr += sizeof(guint32);
 | 
			
		||||
            bytes_left -= sizeof(guint32);
 | 
			
		||||
        GASSERT(bytes_left >= bytes_to_write);
 | 
			
		||||
        if (bytes_left >= bytes_to_write) {
 | 
			
		||||
            gssize bytes_written = bytes_to_write;
 | 
			
		||||
 | 
			
		||||
            switch (cmd) {
 | 
			
		||||
            case BC_TRANSACTION_64:
 | 
			
		||||
            case BC_REPLY_64:
 | 
			
		||||
                /* Is there anything special about transactions and replies? */
 | 
			
		||||
                break;
 | 
			
		||||
            case BC_FREE_BUFFER_64:
 | 
			
		||||
                test_io_free_buffer(binder,
 | 
			
		||||
                    GSIZE_TO_POINTER(*(guint64*)write_ptr));
 | 
			
		||||
                test_io_free_buffer(fd, GSIZE_TO_POINTER(*(guint64*)cmddata));
 | 
			
		||||
                break;
 | 
			
		||||
            case BC_ENTER_LOOPER:
 | 
			
		||||
                 g_private_set(&test_looper, GINT_TO_POINTER(TRUE));
 | 
			
		||||
                 break;
 | 
			
		||||
                g_private_set(&test_looper, GINT_TO_POINTER(TRUE));
 | 
			
		||||
                break;
 | 
			
		||||
            case BC_EXIT_LOOPER:
 | 
			
		||||
                 g_private_set(&test_looper, NULL);
 | 
			
		||||
                 break;
 | 
			
		||||
            case BC_REQUEST_DEATH_NOTIFICATION_64:
 | 
			
		||||
            case BC_CLEAR_DEATH_NOTIFICATION_64:
 | 
			
		||||
            case BC_INCREFS:
 | 
			
		||||
            case BC_ACQUIRE:
 | 
			
		||||
            case BC_RELEASE:
 | 
			
		||||
            case BC_DECREFS:
 | 
			
		||||
                g_private_set(&test_looper, NULL);
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
#pragma message("TODO: implement more BINDER_WRITE_READ commands")
 | 
			
		||||
                GDEBUG("Unhandled command 0x%08x", cmd);
 | 
			
		||||
                if (binder->passthrough) {
 | 
			
		||||
                    bytes_written = test_io_passthough_write_64(fd,
 | 
			
		||||
                        write_ptr, bytes_to_write);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            wr->write_consumed += cmdsize;
 | 
			
		||||
            write_ptr += cmdsize;
 | 
			
		||||
            bytes_left -= cmdsize;
 | 
			
		||||
            if (bytes_written >= 0) {
 | 
			
		||||
                wr->write_consumed += bytes_written;
 | 
			
		||||
                write_ptr += bytes_written;
 | 
			
		||||
                bytes_left -= bytes_written;
 | 
			
		||||
            } else {
 | 
			
		||||
                GDEBUG("Write failed, %s", strerror(errno));
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Partial command in the buffer */
 | 
			
		||||
            errno = EINVAL;
 | 
			
		||||
@@ -335,17 +489,17 @@ test_io_handle_write_read_64(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    is_looper = g_private_get(&test_looper) ? TRUE : FALSE;
 | 
			
		||||
    if (binder->looper_enabled || !is_looper) {
 | 
			
		||||
    if (node->looper_enabled || !is_looper) {
 | 
			
		||||
        /* Now read the data from the socket */
 | 
			
		||||
        int bytes_available = 0;
 | 
			
		||||
        int err = ioctl(binder->public_fd, FIONREAD, &bytes_available);
 | 
			
		||||
        int err = ioctl(fd->fd, FIONREAD, &bytes_available);
 | 
			
		||||
 | 
			
		||||
        if (err >= 0) {
 | 
			
		||||
            int bytes_read = 0;
 | 
			
		||||
 | 
			
		||||
            if (bytes_available >= 4) {
 | 
			
		||||
                bytes_read = read(binder->public_fd,
 | 
			
		||||
                    (void*)(gsize)(wr->read_buffer + wr->read_consumed),
 | 
			
		||||
                bytes_read = read(fd->fd, (void*)(gsize)
 | 
			
		||||
                   (wr->read_buffer + wr->read_consumed),
 | 
			
		||||
                    wr->read_size - wr->read_consumed);
 | 
			
		||||
            } else {
 | 
			
		||||
                struct timespec wait;
 | 
			
		||||
@@ -387,26 +541,26 @@ test_binder_ioctl_version(
 | 
			
		||||
    TestBinder* binder,
 | 
			
		||||
    int* version)
 | 
			
		||||
{
 | 
			
		||||
    *version = binder->node->io->version;
 | 
			
		||||
    *version = binder->io->version;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_binder_node_unref(
 | 
			
		||||
    TestBinderNode* node)
 | 
			
		||||
TestBinderFd*
 | 
			
		||||
test_binder_fd_from_fd(
 | 
			
		||||
    int fd)
 | 
			
		||||
{
 | 
			
		||||
    node->refcount--;
 | 
			
		||||
    if (!node->refcount) {
 | 
			
		||||
        g_hash_table_remove(test_node_map, node->path);
 | 
			
		||||
        g_hash_table_destroy(node->destroy_map);
 | 
			
		||||
        g_free(node->path);
 | 
			
		||||
        g_free(node);
 | 
			
		||||
    }
 | 
			
		||||
    if (!g_hash_table_size(test_node_map)) {
 | 
			
		||||
        g_hash_table_unref(test_node_map);
 | 
			
		||||
        test_node_map = NULL;
 | 
			
		||||
    TestBinderFd* binder_fd = NULL;
 | 
			
		||||
 | 
			
		||||
    G_LOCK(test_binder);
 | 
			
		||||
    GASSERT(test_fd_map);
 | 
			
		||||
    if (test_fd_map) {
 | 
			
		||||
        binder_fd = g_hash_table_lookup(test_fd_map, GINT_TO_POINTER(fd));
 | 
			
		||||
        GASSERT(binder_fd);
 | 
			
		||||
    }
 | 
			
		||||
    G_UNLOCK(test_binder);
 | 
			
		||||
 | 
			
		||||
    return binder_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
@@ -414,13 +568,9 @@ TestBinder*
 | 
			
		||||
test_binder_from_fd(
 | 
			
		||||
    int fd)
 | 
			
		||||
{
 | 
			
		||||
    TestBinder* binder = NULL;
 | 
			
		||||
    GASSERT(test_fd_map);
 | 
			
		||||
    if (test_fd_map) {
 | 
			
		||||
        binder = g_hash_table_lookup(test_fd_map, GINT_TO_POINTER(fd));
 | 
			
		||||
        GASSERT(binder);
 | 
			
		||||
    }
 | 
			
		||||
    return binder;
 | 
			
		||||
    TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
 | 
			
		||||
 | 
			
		||||
    return binder_fd ? binder_fd->node->binder : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
@@ -435,11 +585,22 @@ void
 | 
			
		||||
test_binder_set_looper_enabled(
 | 
			
		||||
    int fd,
 | 
			
		||||
    gboolean enabled)
 | 
			
		||||
{
 | 
			
		||||
    TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
 | 
			
		||||
 | 
			
		||||
    g_assert(binder_fd);
 | 
			
		||||
    binder_fd->node->looper_enabled = enabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
test_binder_set_passthrough(
 | 
			
		||||
    int fd,
 | 
			
		||||
    gboolean passthrough)
 | 
			
		||||
{
 | 
			
		||||
    TestBinder* binder = test_binder_from_fd(fd);
 | 
			
		||||
 | 
			
		||||
    g_assert(binder);
 | 
			
		||||
    binder->looper_enabled = enabled;
 | 
			
		||||
    binder->passthrough = passthrough;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -448,13 +609,13 @@ test_binder_set_destroy(
 | 
			
		||||
    gpointer ptr,
 | 
			
		||||
    GDestroyNotify destroy)
 | 
			
		||||
{
 | 
			
		||||
    TestBinder* binder = test_binder_from_fd(fd);
 | 
			
		||||
    TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
 | 
			
		||||
 | 
			
		||||
    if (binder) {
 | 
			
		||||
        TestBinderNode* node = binder->node;
 | 
			
		||||
 | 
			
		||||
        g_hash_table_replace(node->destroy_map, ptr,
 | 
			
		||||
    if (binder_fd) {
 | 
			
		||||
        G_LOCK(test_binder);
 | 
			
		||||
        g_hash_table_replace(binder_fd->destroy_map, ptr,
 | 
			
		||||
            destroy ? destroy : test_io_destroy_none);
 | 
			
		||||
        G_UNLOCK(test_binder);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -704,44 +865,219 @@ test_binder_br_reply_status_later(
 | 
			
		||||
    test_binder_br_reply_status1(fd, status, test_binder_push_data_later);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_binder_node_clear(
 | 
			
		||||
    TestBinderNode* node)
 | 
			
		||||
{
 | 
			
		||||
    GDEBUG("Done with %s", node->path);
 | 
			
		||||
    g_hash_table_remove(test_node_map, node->path);
 | 
			
		||||
    if (!g_hash_table_size(test_node_map)) {
 | 
			
		||||
        g_hash_table_unref(test_node_map);
 | 
			
		||||
        test_node_map = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    close(node->fd);
 | 
			
		||||
    g_free(node->path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
TestBinder*
 | 
			
		||||
test_binder_ref(
 | 
			
		||||
    TestBinder* binder)
 | 
			
		||||
{
 | 
			
		||||
    if (binder) {
 | 
			
		||||
        g_atomic_int_inc(&binder->refcount);
 | 
			
		||||
    }
 | 
			
		||||
    return binder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_binder_unregister_objects_internal(
 | 
			
		||||
    TestBinder* binder,
 | 
			
		||||
    gboolean need_lock)
 | 
			
		||||
{
 | 
			
		||||
    GSList* objects = NULL;
 | 
			
		||||
    GHashTableIter it;
 | 
			
		||||
    gpointer value;
 | 
			
		||||
 | 
			
		||||
    if (need_lock) {
 | 
			
		||||
        G_LOCK(test_binder);
 | 
			
		||||
    }
 | 
			
		||||
    g_assert(binder);
 | 
			
		||||
    g_hash_table_iter_init(&it, binder->handle_map);
 | 
			
		||||
    while (g_hash_table_iter_next(&it, NULL, &value)) {
 | 
			
		||||
        objects = g_slist_append(objects, value);
 | 
			
		||||
    }
 | 
			
		||||
    g_hash_table_remove_all(binder->object_map);
 | 
			
		||||
    g_hash_table_remove_all(binder->handle_map);
 | 
			
		||||
    if (need_lock) {
 | 
			
		||||
        G_UNLOCK(test_binder);
 | 
			
		||||
    }
 | 
			
		||||
    /* Unref GBinderLocalObjects outside the lock */
 | 
			
		||||
    g_slist_free_full(objects, (GDestroyNotify) gbinder_local_object_unref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_binder_unref_internal(
 | 
			
		||||
    TestBinder* binder,
 | 
			
		||||
    gboolean need_lock)
 | 
			
		||||
{
 | 
			
		||||
    if (binder && g_atomic_int_dec_and_test(&binder->refcount)) {
 | 
			
		||||
        if (need_lock) {
 | 
			
		||||
            G_LOCK(test_binder);
 | 
			
		||||
        }
 | 
			
		||||
        test_binder_node_clear(binder->node + 0);
 | 
			
		||||
        test_binder_node_clear(binder->node + 1);
 | 
			
		||||
        if (need_lock) {
 | 
			
		||||
            G_UNLOCK(test_binder);
 | 
			
		||||
        }
 | 
			
		||||
        test_binder_submit_thread_free(binder->submit_thread);
 | 
			
		||||
        test_binder_unregister_objects_internal(binder, need_lock);
 | 
			
		||||
        g_hash_table_destroy(binder->object_map);
 | 
			
		||||
        g_hash_table_destroy(binder->handle_map);
 | 
			
		||||
        g_mutex_clear(&binder->mutex);
 | 
			
		||||
        g_free(binder);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
guint
 | 
			
		||||
test_binder_register_object(
 | 
			
		||||
    int fd,
 | 
			
		||||
    GBinderLocalObject* obj,
 | 
			
		||||
    guint h)
 | 
			
		||||
{
 | 
			
		||||
    TestBinder* binder = test_binder_from_fd(fd);
 | 
			
		||||
 | 
			
		||||
    g_assert(binder);
 | 
			
		||||
    g_assert(obj);
 | 
			
		||||
 | 
			
		||||
    G_LOCK(test_binder);
 | 
			
		||||
    g_assert(!g_hash_table_contains(binder->object_map, obj));
 | 
			
		||||
    g_assert(!g_hash_table_contains(binder->handle_map, GINT_TO_POINTER(h)));
 | 
			
		||||
    if (h == AUTO_HANDLE) {
 | 
			
		||||
        h = 1;
 | 
			
		||||
        while (g_hash_table_contains(binder->handle_map, GINT_TO_POINTER(h)) ||
 | 
			
		||||
            g_hash_table_contains(binder->object_map, GINT_TO_POINTER(h))) {
 | 
			
		||||
            h++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    GDEBUG("Object %p <=> handle %u", obj, h);
 | 
			
		||||
    g_hash_table_insert(binder->handle_map, GINT_TO_POINTER(h), obj);
 | 
			
		||||
    g_hash_table_insert(binder->object_map, obj, GINT_TO_POINTER(h));
 | 
			
		||||
    G_UNLOCK(test_binder);
 | 
			
		||||
 | 
			
		||||
    gbinder_local_object_ref(obj);
 | 
			
		||||
    return h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
test_binder_unregister_objects(
 | 
			
		||||
    int fd)
 | 
			
		||||
{
 | 
			
		||||
    test_binder_unregister_objects_internal(test_binder_from_fd(fd), TRUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_fd_map_free(
 | 
			
		||||
    gpointer entry)
 | 
			
		||||
{
 | 
			
		||||
    TestBinderFd* binder_fd = entry;
 | 
			
		||||
    GHashTableIter it;
 | 
			
		||||
    gpointer key, value;
 | 
			
		||||
 | 
			
		||||
    g_hash_table_iter_init(&it, binder_fd->destroy_map);
 | 
			
		||||
    while (g_hash_table_iter_next(&it, &key, &value)) {
 | 
			
		||||
        if (value) {
 | 
			
		||||
            ((GDestroyNotify)value)(key);
 | 
			
		||||
        } else {
 | 
			
		||||
            g_free(key);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    g_hash_table_destroy(binder_fd->destroy_map);
 | 
			
		||||
    test_binder_unref_internal(binder_fd->node->binder, FALSE);
 | 
			
		||||
    close(binder_fd->fd);
 | 
			
		||||
    g_free(binder_fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
TestBinderFd*
 | 
			
		||||
test_binder_fd_new(
 | 
			
		||||
    TestBinderNode* node)
 | 
			
		||||
{
 | 
			
		||||
    TestBinderFd* binder_fd = g_new0(TestBinderFd, 1);
 | 
			
		||||
 | 
			
		||||
    test_binder_ref(node->binder);
 | 
			
		||||
    binder_fd->node = node;
 | 
			
		||||
    binder_fd->fd = dup(node->fd);
 | 
			
		||||
    binder_fd->destroy_map = g_hash_table_new(g_direct_hash, g_direct_equal);
 | 
			
		||||
    return binder_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
gbinder_system_open(
 | 
			
		||||
    const char* path,
 | 
			
		||||
    int flags)
 | 
			
		||||
{
 | 
			
		||||
    if (path && g_str_has_prefix(path, "/dev") &&
 | 
			
		||||
        g_str_has_suffix(path, "binder")) {
 | 
			
		||||
        TestBinderNode* node = NULL;
 | 
			
		||||
        TestBinder* binder = NULL;
 | 
			
		||||
        int fd;
 | 
			
		||||
    static const char binder_suffix[] = "binder";
 | 
			
		||||
    static const char binder_private_suffix[] = "binder-private";
 | 
			
		||||
    static const char private_suffix[] = "-private";
 | 
			
		||||
 | 
			
		||||
    if (path && g_str_has_prefix(path, "/dev/") &&
 | 
			
		||||
        (g_str_has_suffix(path, binder_suffix) ||
 | 
			
		||||
         g_str_has_suffix(path, binder_private_suffix))) {
 | 
			
		||||
        TestBinderFd* fd;
 | 
			
		||||
        TestBinderNode* node;
 | 
			
		||||
 | 
			
		||||
        G_LOCK(test_binder);
 | 
			
		||||
        node = test_node_map ? g_hash_table_lookup(test_node_map, path) : NULL;
 | 
			
		||||
        if (!node) {
 | 
			
		||||
            int i, fds[2];
 | 
			
		||||
            TestBinder* binder = g_new0(TestBinder, 1);
 | 
			
		||||
 | 
			
		||||
            binder->io = &test_io_64;
 | 
			
		||||
            g_mutex_init(&binder->mutex);
 | 
			
		||||
            g_assert(!socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
 | 
			
		||||
 | 
			
		||||
            if (g_str_has_suffix(path, binder_suffix)) {
 | 
			
		||||
                node = binder->node + PUBLIC;
 | 
			
		||||
                node->path = g_strdup(path);
 | 
			
		||||
                binder->node[PRIVATE].path = g_strconcat(path,
 | 
			
		||||
                    private_suffix, NULL);
 | 
			
		||||
            } else {
 | 
			
		||||
                node = binder->node + PRIVATE;
 | 
			
		||||
                node->path = g_strdup(path);
 | 
			
		||||
                binder->node[PUBLIC].path = g_strndup(path,
 | 
			
		||||
                    strlen(path) - strlen(private_suffix) - 1);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        if (test_node_map) {
 | 
			
		||||
            node = g_hash_table_lookup(test_node_map, path);
 | 
			
		||||
        }
 | 
			
		||||
        if (node) {
 | 
			
		||||
            node->refcount++;
 | 
			
		||||
        } else {
 | 
			
		||||
            node = g_new0(TestBinderNode, 1);
 | 
			
		||||
            node->path = g_strdup(path);
 | 
			
		||||
            node->refcount = 1;
 | 
			
		||||
            node->io = &test_io_64;
 | 
			
		||||
            node->destroy_map = g_hash_table_new(g_direct_hash, g_direct_equal);
 | 
			
		||||
            if (!test_node_map) {
 | 
			
		||||
                test_node_map = g_hash_table_new(g_str_hash, g_str_equal);
 | 
			
		||||
            }
 | 
			
		||||
            g_hash_table_replace(test_node_map, node->path, node);
 | 
			
		||||
            for (i = 0; i < 2; i++) {
 | 
			
		||||
                binder->node[i].binder = binder;
 | 
			
		||||
                binder->node[i].fd = fds[i];
 | 
			
		||||
                g_hash_table_replace(test_node_map, binder->node[i].path,
 | 
			
		||||
                    binder->node + i);
 | 
			
		||||
            }
 | 
			
		||||
            binder->object_map = g_hash_table_new
 | 
			
		||||
                (g_direct_hash, g_direct_equal);
 | 
			
		||||
            binder->handle_map = g_hash_table_new
 | 
			
		||||
                (g_direct_hash, g_direct_equal);
 | 
			
		||||
            GDEBUG("Created %s <=> %s binder", binder->node[0].path,
 | 
			
		||||
                binder->node[1].path);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        binder = g_new0(TestBinder, 1);
 | 
			
		||||
        binder->node = node;
 | 
			
		||||
        socketpair(AF_UNIX, SOCK_STREAM, 0, binder->fd);
 | 
			
		||||
        fd = binder->public_fd;
 | 
			
		||||
 | 
			
		||||
        fd = test_binder_fd_new(node);
 | 
			
		||||
        if (!test_fd_map) {
 | 
			
		||||
            test_fd_map = g_hash_table_new(g_direct_hash, g_direct_equal);
 | 
			
		||||
            test_fd_map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
 | 
			
		||||
                NULL, test_fd_map_free);
 | 
			
		||||
        }
 | 
			
		||||
        g_hash_table_replace(test_fd_map, GINT_TO_POINTER(fd), binder);
 | 
			
		||||
        return fd;
 | 
			
		||||
        g_hash_table_replace(test_fd_map, GINT_TO_POINTER(fd->fd), fd);
 | 
			
		||||
        G_UNLOCK(test_binder);
 | 
			
		||||
 | 
			
		||||
        return fd->fd;
 | 
			
		||||
    } else {
 | 
			
		||||
        errno = ENOENT;
 | 
			
		||||
        return -1;
 | 
			
		||||
@@ -752,23 +1088,22 @@ int
 | 
			
		||||
gbinder_system_close(
 | 
			
		||||
    int fd)
 | 
			
		||||
{
 | 
			
		||||
    TestBinder* binder = test_binder_from_fd(fd);
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (binder) {
 | 
			
		||||
        g_hash_table_remove(test_fd_map, GINT_TO_POINTER(fd));
 | 
			
		||||
    G_LOCK(test_binder);
 | 
			
		||||
    if (g_hash_table_remove(test_fd_map, GINT_TO_POINTER(fd))) {
 | 
			
		||||
        if (!g_hash_table_size(test_fd_map)) {
 | 
			
		||||
            g_hash_table_unref(test_fd_map);
 | 
			
		||||
            test_fd_map = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        test_binder_submit_thread_free(binder->submit_thread);
 | 
			
		||||
        test_binder_node_unref(binder->node);
 | 
			
		||||
        close(binder->public_fd);
 | 
			
		||||
        close(binder->private_fd);
 | 
			
		||||
        g_free(binder);
 | 
			
		||||
        return 0;
 | 
			
		||||
        ret = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        errno = EBADF;
 | 
			
		||||
        ret = -1;
 | 
			
		||||
    }
 | 
			
		||||
    errno = EBADF;
 | 
			
		||||
    return -1;
 | 
			
		||||
    G_UNLOCK(test_binder);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
@@ -777,9 +1112,11 @@ gbinder_system_ioctl(
 | 
			
		||||
    int request,
 | 
			
		||||
    void* data)
 | 
			
		||||
{
 | 
			
		||||
    TestBinder* binder = test_binder_from_fd(fd);
 | 
			
		||||
    if (binder) {
 | 
			
		||||
        const TestBinderIo* io = binder->node->io;
 | 
			
		||||
    TestBinderFd* binder_fd = test_binder_fd_from_fd(fd);
 | 
			
		||||
 | 
			
		||||
    if (binder_fd) {
 | 
			
		||||
        TestBinder* binder = binder_fd->node->binder;
 | 
			
		||||
        const TestBinderIo* io = binder->io;
 | 
			
		||||
 | 
			
		||||
        switch (request) {
 | 
			
		||||
        case BINDER_VERSION:
 | 
			
		||||
@@ -788,7 +1125,7 @@ gbinder_system_ioctl(
 | 
			
		||||
            return 0;
 | 
			
		||||
        default:
 | 
			
		||||
            if (request == io->write_read_request) {
 | 
			
		||||
                return io->handle_write_read(binder, data);
 | 
			
		||||
                return io->handle_write_read(binder_fd, data);
 | 
			
		||||
            } else {
 | 
			
		||||
                errno = EINVAL;
 | 
			
		||||
                return -1;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -14,8 +14,8 @@
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived from
 | 
			
		||||
 *      this software without specific prior written permission.
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -35,6 +35,8 @@
 | 
			
		||||
 | 
			
		||||
#include "test_common.h"
 | 
			
		||||
 | 
			
		||||
typedef struct test_binder TestBinder;
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
test_binder_br_noop(
 | 
			
		||||
    int fd);
 | 
			
		||||
@@ -116,12 +118,33 @@ test_binder_set_looper_enabled(
 | 
			
		||||
    int fd,
 | 
			
		||||
    gboolean enabled);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
test_binder_set_passthrough(
 | 
			
		||||
    int fd,
 | 
			
		||||
    gboolean passthrough);
 | 
			
		||||
 | 
			
		||||
guint
 | 
			
		||||
test_binder_register_object(
 | 
			
		||||
    int fd,
 | 
			
		||||
    GBinderLocalObject* obj,
 | 
			
		||||
    guint handle);
 | 
			
		||||
 | 
			
		||||
#define AUTO_HANDLE ((guint)-1)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
test_binder_unregister_objects(
 | 
			
		||||
    int fd);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
test_binder_set_destroy(
 | 
			
		||||
    int fd,
 | 
			
		||||
    gpointer ptr,
 | 
			
		||||
    GDestroyNotify destroy);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
test_binder_exit_wait(
 | 
			
		||||
    void);
 | 
			
		||||
 | 
			
		||||
#endif /* TEST_BINDER_H */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 Jolla Ltd.
 | 
			
		||||
 * Contact: Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -13,9 +13,9 @@
 | 
			
		||||
 *   2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the name of Jolla Ltd nor the names of its contributors may
 | 
			
		||||
 *      be used to endorse or promote products derived from this software
 | 
			
		||||
 *      without specific prior written permission.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -58,6 +58,12 @@ void
 | 
			
		||||
test_quit_later(
 | 
			
		||||
    GMainLoop* loop);
 | 
			
		||||
 | 
			
		||||
/* Quits the event loop after n iterations */
 | 
			
		||||
void
 | 
			
		||||
test_quit_later_n(
 | 
			
		||||
    GMainLoop* loop,
 | 
			
		||||
    guint n);
 | 
			
		||||
 | 
			
		||||
#define TEST_TIMEOUT_SEC (20)
 | 
			
		||||
 | 
			
		||||
/* Helper macros */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 Jolla Ltd.
 | 
			
		||||
 * Contact: Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -13,9 +13,9 @@
 | 
			
		||||
 *   2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the name of Jolla Ltd nor the names of its contributors may
 | 
			
		||||
 *      be used to endorse or promote products derived from this software
 | 
			
		||||
 *      without specific prior written permission.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -34,6 +34,11 @@
 | 
			
		||||
 | 
			
		||||
#include <gutil_log.h>
 | 
			
		||||
 | 
			
		||||
typedef struct test_quit_later_data{
 | 
			
		||||
    GMainLoop* loop;
 | 
			
		||||
    guint n;
 | 
			
		||||
} TestQuitLaterData;
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
test_timeout_expired(
 | 
			
		||||
@@ -43,6 +48,46 @@ test_timeout_expired(
 | 
			
		||||
    return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_quit_later_n_free(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    TestQuitLaterData* data = user_data;
 | 
			
		||||
 | 
			
		||||
    g_main_loop_unref(data->loop);
 | 
			
		||||
    g_free(data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
test_quit_later_n_func(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    TestQuitLaterData* data = user_data;
 | 
			
		||||
 | 
			
		||||
    if (data->n > 0) {
 | 
			
		||||
        data->n--;
 | 
			
		||||
        return G_SOURCE_CONTINUE;
 | 
			
		||||
    } else {
 | 
			
		||||
        g_main_loop_quit(data->loop);
 | 
			
		||||
        return G_SOURCE_REMOVE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
test_quit_later_n(
 | 
			
		||||
    GMainLoop* loop,
 | 
			
		||||
    guint n)
 | 
			
		||||
{
 | 
			
		||||
    TestQuitLaterData* data = g_new0(TestQuitLaterData, 1);
 | 
			
		||||
 | 
			
		||||
    data->loop = g_main_loop_ref(loop);
 | 
			
		||||
    data->n = n;
 | 
			
		||||
    g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, test_quit_later_n_func, data,
 | 
			
		||||
        test_quit_later_n_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
test_quit_later_cb(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
#
 | 
			
		||||
# This script requires lcov, dirname
 | 
			
		||||
@@ -7,6 +8,7 @@ TESTS="\
 | 
			
		||||
unit_buffer \
 | 
			
		||||
unit_cleanup \
 | 
			
		||||
unit_client \
 | 
			
		||||
unit_config \
 | 
			
		||||
unit_driver \
 | 
			
		||||
unit_eventloop \
 | 
			
		||||
unit_ipc \
 | 
			
		||||
@@ -20,6 +22,7 @@ unit_remote_object \
 | 
			
		||||
unit_remote_reply \
 | 
			
		||||
unit_remote_request \
 | 
			
		||||
unit_servicemanager \
 | 
			
		||||
unit_servicemanager_aidl \
 | 
			
		||||
unit_servicename \
 | 
			
		||||
unit_servicepoll \
 | 
			
		||||
unit_writer"
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ test_client_new(
 | 
			
		||||
    guint handle,
 | 
			
		||||
    const char* iface)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, handle);
 | 
			
		||||
    GBinderClient* client = gbinder_client_new(obj, iface);
 | 
			
		||||
@@ -97,7 +97,7 @@ void
 | 
			
		||||
test_basic(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0);
 | 
			
		||||
    const char* iface = "foo";
 | 
			
		||||
@@ -123,7 +123,7 @@ void
 | 
			
		||||
test_interfaces(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0);
 | 
			
		||||
    static const GBinderClientIfaceInfo ifaces[] = {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								unit/unit_config/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								unit/unit_config/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
# -*- Mode: makefile-gmake -*-
 | 
			
		||||
 | 
			
		||||
EXE = unit_config
 | 
			
		||||
 | 
			
		||||
include ../common/Makefile
 | 
			
		||||
							
								
								
									
										505
									
								
								unit/unit_config/unit_config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										505
									
								
								unit/unit_config/unit_config.c
									
									
									
									
									
										Normal 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:
 | 
			
		||||
 */
 | 
			
		||||
@@ -109,8 +109,8 @@ void
 | 
			
		||||
test_basic(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
 | 
			
		||||
    g_assert(ipc);
 | 
			
		||||
    g_assert(ipc2);
 | 
			
		||||
@@ -119,16 +119,17 @@ test_basic(
 | 
			
		||||
    gbinder_ipc_unref(ipc2);
 | 
			
		||||
 | 
			
		||||
    /* Second gbinder_ipc_new returns the same (default) object */
 | 
			
		||||
    g_assert(gbinder_ipc_new(NULL, NULL) == ipc);
 | 
			
		||||
    g_assert(gbinder_ipc_new("", NULL) == ipc);
 | 
			
		||||
    g_assert(gbinder_ipc_new(NULL) == ipc);
 | 
			
		||||
    g_assert(gbinder_ipc_new("") == ipc);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
 | 
			
		||||
    /* Invalid path */
 | 
			
		||||
    g_assert(!gbinder_ipc_new("invalid path", NULL));
 | 
			
		||||
    g_assert(!gbinder_ipc_new("invalid path"));
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -153,7 +154,7 @@ void
 | 
			
		||||
test_async_oneway(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
 | 
			
		||||
@@ -180,7 +181,7 @@ void
 | 
			
		||||
test_sync_oneway(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
 | 
			
		||||
@@ -191,6 +192,7 @@ test_sync_oneway(
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -202,7 +204,7 @@ void
 | 
			
		||||
test_sync_reply_ok_status(
 | 
			
		||||
    int* status)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
 | 
			
		||||
@@ -235,6 +237,7 @@ test_sync_reply_ok_status(
 | 
			
		||||
    gbinder_local_reply_unref(reply);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
@@ -258,7 +261,7 @@ void
 | 
			
		||||
test_sync_reply_error(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
 | 
			
		||||
@@ -278,6 +281,7 @@ test_sync_reply_error(
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -316,7 +320,7 @@ void
 | 
			
		||||
test_transact_ok(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
 | 
			
		||||
@@ -348,6 +352,7 @@ test_transact_ok(
 | 
			
		||||
    gbinder_local_reply_unref(reply);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -374,7 +379,7 @@ void
 | 
			
		||||
test_transact_dead(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
 | 
			
		||||
@@ -395,6 +400,7 @@ test_transact_dead(
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -421,7 +427,7 @@ void
 | 
			
		||||
test_transact_failed(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
 | 
			
		||||
@@ -442,6 +448,7 @@ test_transact_failed(
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -470,7 +477,7 @@ void
 | 
			
		||||
test_transact_status(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
 | 
			
		||||
@@ -491,6 +498,7 @@ test_transact_status(
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -512,7 +520,7 @@ void
 | 
			
		||||
test_transact_custom(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    gulong id = gbinder_ipc_transact_custom(ipc, NULL,
 | 
			
		||||
        test_transact_custom_done, NULL, loop);
 | 
			
		||||
@@ -523,6 +531,7 @@ test_transact_custom(
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -543,7 +552,7 @@ void
 | 
			
		||||
test_transact_custom2(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    gulong id = gbinder_ipc_transact_custom(ipc, NULL, NULL,
 | 
			
		||||
        test_transact_custom_destroy, loop);
 | 
			
		||||
@@ -554,6 +563,7 @@ test_transact_custom2(
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -575,7 +585,7 @@ void
 | 
			
		||||
test_transact_custom3(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    /* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
 | 
			
		||||
    gulong id = gbinder_ipc_transact_custom(ipc, test_transact_custom3_exec,
 | 
			
		||||
@@ -586,6 +596,7 @@ test_transact_custom3(
 | 
			
		||||
 | 
			
		||||
    /* Reference to GBinderIpc is released by test_transact_custom3_exec */
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -624,7 +635,7 @@ void
 | 
			
		||||
test_transact_cancel(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel_exec,
 | 
			
		||||
        test_transact_cancel_done, test_transact_cancel_destroy, loop);
 | 
			
		||||
@@ -635,6 +646,7 @@ test_transact_cancel(
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -669,7 +681,7 @@ void
 | 
			
		||||
test_transact_cancel2(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    /* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
 | 
			
		||||
    gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel2_exec,
 | 
			
		||||
@@ -680,6 +692,7 @@ test_transact_cancel2(
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -718,7 +731,7 @@ void
 | 
			
		||||
test_transact_2way(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    const char* dev = gbinder_driver_dev(ipc->driver);
 | 
			
		||||
@@ -769,6 +782,7 @@ test_transact_2way(
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -803,7 +817,7 @@ void
 | 
			
		||||
test_transact_incoming(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    const char* dev = gbinder_driver_dev(ipc->driver);
 | 
			
		||||
@@ -840,6 +854,7 @@ test_transact_incoming(
 | 
			
		||||
    test_run(&test_opt, loop);
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -873,7 +888,7 @@ void
 | 
			
		||||
test_transact_status_reply(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    const char* dev = gbinder_driver_dev(ipc->driver);
 | 
			
		||||
@@ -904,6 +919,7 @@ test_transact_status_reply(
 | 
			
		||||
    test_run(&test_opt, loop);
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -980,7 +996,7 @@ void
 | 
			
		||||
test_transact_async(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    const char* dev = gbinder_driver_dev(ipc->driver);
 | 
			
		||||
@@ -1011,6 +1027,7 @@ test_transact_async(
 | 
			
		||||
    test_run(&test_opt, loop);
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1053,7 +1070,7 @@ void
 | 
			
		||||
test_transact_async_sync(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    const char* dev = gbinder_driver_dev(ipc->driver);
 | 
			
		||||
@@ -1084,6 +1101,7 @@ test_transact_async_sync(
 | 
			
		||||
    test_run(&test_opt, loop);
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1107,7 +1125,7 @@ void
 | 
			
		||||
test_drop_remote_refs(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new
 | 
			
		||||
        (ipc, NULL, NULL, NULL);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
@@ -1126,6 +1144,7 @@ test_drop_remote_refs(
 | 
			
		||||
    /* gbinder_ipc_exit will drop the remote reference */
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1149,7 +1168,7 @@ void
 | 
			
		||||
test_cancel_on_exit(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const GBinderIo* io = gbinder_driver_io(ipc->driver);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
@@ -1163,6 +1182,7 @@ test_cancel_on_exit(
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -14,8 +14,8 @@
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived from
 | 
			
		||||
 *      this software without specific prior written permission.
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -152,7 +152,7 @@ test_basic(
 | 
			
		||||
{
 | 
			
		||||
    const char* const ifaces_foo[] = { "foo", NULL };
 | 
			
		||||
    const char* const ifaces_bar[] = { "bar", NULL };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderLocalObject* foo;
 | 
			
		||||
    GBinderLocalObject* bar;
 | 
			
		||||
@@ -201,7 +201,7 @@ test_ping(
 | 
			
		||||
    int status = INT_MAX;
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
 | 
			
		||||
@@ -247,7 +247,7 @@ test_interface(
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
 | 
			
		||||
    const char* const ifaces[] = { "x", NULL };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
 | 
			
		||||
@@ -296,7 +296,7 @@ test_hidl_ping(
 | 
			
		||||
    int status = INT_MAX;
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
 | 
			
		||||
@@ -346,7 +346,7 @@ test_get_descriptor(
 | 
			
		||||
    int status = INT_MAX;
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
 | 
			
		||||
@@ -402,7 +402,7 @@ test_descriptor_chain(
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
 | 
			
		||||
    const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
 | 
			
		||||
@@ -476,7 +476,7 @@ test_custom_iface(
 | 
			
		||||
    int count = 0, status = INT_MAX;
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
 | 
			
		||||
@@ -583,7 +583,7 @@ test_reply_status(
 | 
			
		||||
    int count = 0, status = 0;
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
 | 
			
		||||
@@ -624,7 +624,7 @@ void
 | 
			
		||||
test_increfs(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new
 | 
			
		||||
        (ipc, NULL, NULL, NULL);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
@@ -666,7 +666,7 @@ void
 | 
			
		||||
test_decrefs(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new
 | 
			
		||||
        (ipc, NULL, NULL, NULL);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
@@ -708,7 +708,7 @@ void
 | 
			
		||||
test_acquire(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new
 | 
			
		||||
        (ipc, NULL, NULL, NULL);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
@@ -750,7 +750,7 @@ void
 | 
			
		||||
test_release(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
 
 | 
			
		||||
@@ -399,7 +399,7 @@ test_local_object(
 | 
			
		||||
    GBinderLocalReply* reply;
 | 
			
		||||
    GBinderOutputData* data;
 | 
			
		||||
    GUtilIntArray* offsets;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(NULL, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(NULL);
 | 
			
		||||
    const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
 | 
			
		||||
    GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -14,8 +14,8 @@
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived from
 | 
			
		||||
 *      this software without specific prior written permission.
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -33,6 +33,7 @@
 | 
			
		||||
#include "test_common.h"
 | 
			
		||||
 | 
			
		||||
#include "gbinder_buffer_p.h"
 | 
			
		||||
#include "gbinder_config.h"
 | 
			
		||||
#include "gbinder_driver.h"
 | 
			
		||||
#include "gbinder_io.h"
 | 
			
		||||
#include "gbinder_local_request_p.h"
 | 
			
		||||
@@ -43,36 +44,118 @@
 | 
			
		||||
#include "gbinder_writer.h"
 | 
			
		||||
 | 
			
		||||
static TestOpt test_opt;
 | 
			
		||||
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-protocol-XXXXXX";
 | 
			
		||||
 | 
			
		||||
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
 | 
			
		||||
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
 | 
			
		||||
#define UNSET_WORK_SOURCE (-1)
 | 
			
		||||
 | 
			
		||||
typedef struct test_data {
 | 
			
		||||
    const char* name;
 | 
			
		||||
    const char* prot;
 | 
			
		||||
    const char* dev;
 | 
			
		||||
} TestData;
 | 
			
		||||
 | 
			
		||||
typedef struct test_header_data {
 | 
			
		||||
    const char* name;
 | 
			
		||||
    const char* prot;
 | 
			
		||||
    const char* dev;
 | 
			
		||||
    const char* iface;
 | 
			
		||||
    const guint8* header;
 | 
			
		||||
    guint header_size;
 | 
			
		||||
} TestHeaderData;
 | 
			
		||||
 | 
			
		||||
static const guint8 test_header_binder [] = {
 | 
			
		||||
static const guint8 test_header_aidl [] = {
 | 
			
		||||
    TEST_INT32_BYTES(BINDER_RPC_FLAGS),
 | 
			
		||||
    TEST_INT32_BYTES(3),
 | 
			
		||||
    TEST_INT16_BYTES('f'), TEST_INT16_BYTES('o'),
 | 
			
		||||
    TEST_INT16_BYTES('o'), 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const guint8 test_header_hwbinder [] = {
 | 
			
		||||
static const guint8 test_header_aidl2 [] = {
 | 
			
		||||
    TEST_INT32_BYTES(BINDER_RPC_FLAGS),
 | 
			
		||||
    TEST_INT32_BYTES(UNSET_WORK_SOURCE),
 | 
			
		||||
    TEST_INT32_BYTES(3),
 | 
			
		||||
    TEST_INT16_BYTES('f'), TEST_INT16_BYTES('o'),
 | 
			
		||||
    TEST_INT16_BYTES('o'), 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const guint8 test_header_hidl [] = {
 | 
			
		||||
    'f', 'o', 'o', 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const TestHeaderData test_header_tests[] = {
 | 
			
		||||
    { "binder", GBINDER_DEFAULT_BINDER, "foo",
 | 
			
		||||
      TEST_ARRAY_AND_SIZE(test_header_binder) },
 | 
			
		||||
    { "hwbinder", GBINDER_DEFAULT_HWBINDER, "foo",
 | 
			
		||||
      TEST_ARRAY_AND_SIZE(test_header_hwbinder) }
 | 
			
		||||
    { "aidl/ok", "aidl", GBINDER_DEFAULT_BINDER, "foo",
 | 
			
		||||
      TEST_ARRAY_AND_SIZE(test_header_aidl) },
 | 
			
		||||
    { "aidl/short", "aidl", GBINDER_DEFAULT_BINDER, NULL,
 | 
			
		||||
      test_header_aidl, 8 }, /* Short packet */
 | 
			
		||||
    { "aidl2/ok", "aidl2", GBINDER_DEFAULT_BINDER, "foo",
 | 
			
		||||
      TEST_ARRAY_AND_SIZE(test_header_aidl2) },
 | 
			
		||||
    { "aidl2/short/1", "aidl2", GBINDER_DEFAULT_BINDER, NULL,
 | 
			
		||||
      test_header_aidl2, 1 }, /* Short packet */
 | 
			
		||||
    { "aidl2/short/2", "aidl2", GBINDER_DEFAULT_BINDER, NULL,
 | 
			
		||||
      test_header_aidl2, 5 }, /* Short packet */
 | 
			
		||||
    { "aidl2/short/3", "adl2", GBINDER_DEFAULT_BINDER, NULL,
 | 
			
		||||
      test_header_aidl2, 9 }, /* Short packet */
 | 
			
		||||
    { "hidl/ok", "hidl", GBINDER_DEFAULT_HWBINDER, "foo",
 | 
			
		||||
      TEST_ARRAY_AND_SIZE(test_header_hidl) },
 | 
			
		||||
    { "hidl/short", "hidl", GBINDER_DEFAULT_HWBINDER, NULL,
 | 
			
		||||
      test_header_hidl, 1 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct test_config {
 | 
			
		||||
    char* dir;
 | 
			
		||||
    char* file;
 | 
			
		||||
} TestConfig;
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_config_init(
 | 
			
		||||
    TestConfig* test,
 | 
			
		||||
    const char* config)
 | 
			
		||||
{
 | 
			
		||||
    test->dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
 | 
			
		||||
    test->file = g_build_filename(test->dir, "test.conf", NULL);
 | 
			
		||||
 | 
			
		||||
    /* Reset the state */
 | 
			
		||||
    gbinder_rpc_protocol_exit();
 | 
			
		||||
    gbinder_config_exit();
 | 
			
		||||
 | 
			
		||||
    /* Write the config */
 | 
			
		||||
    g_assert(g_file_set_contents(test->file, config, -1, NULL));
 | 
			
		||||
    gbinder_config_file = test->file;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_config_init2(
 | 
			
		||||
    TestConfig* test,
 | 
			
		||||
    const char* dev,
 | 
			
		||||
    const char* prot)
 | 
			
		||||
{
 | 
			
		||||
    char* config = g_strconcat("[Protocol]\n", dev, " = ", prot, "\n", NULL);
 | 
			
		||||
 | 
			
		||||
    test_config_init(test, config);
 | 
			
		||||
    g_free(config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_config_cleanup(
 | 
			
		||||
    TestConfig* test)
 | 
			
		||||
{
 | 
			
		||||
    /* Undo the damage */
 | 
			
		||||
    gbinder_rpc_protocol_exit();
 | 
			
		||||
    gbinder_config_exit();
 | 
			
		||||
    gbinder_config_file = NULL;
 | 
			
		||||
 | 
			
		||||
    remove(test->file);
 | 
			
		||||
    g_free(test->file);
 | 
			
		||||
 | 
			
		||||
    remove(test->dir);
 | 
			
		||||
    g_free(test->dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * device
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
@@ -82,12 +165,129 @@ void
 | 
			
		||||
test_device(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    g_assert(gbinder_rpc_protocol_for_device(NULL) ==
 | 
			
		||||
        &gbinder_rpc_protocol_binder);
 | 
			
		||||
    g_assert(gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER) ==
 | 
			
		||||
        &gbinder_rpc_protocol_binder);
 | 
			
		||||
    g_assert(gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_HWBINDER) ==
 | 
			
		||||
        &gbinder_rpc_protocol_hwbinder);
 | 
			
		||||
    const GBinderRpcProtocol* p;
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device(NULL);
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"aidl");
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"aidl");
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"hidl");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * config1
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_config1(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const GBinderRpcProtocol* p;
 | 
			
		||||
    TestConfig config;
 | 
			
		||||
 | 
			
		||||
    test_config_init(&config,
 | 
			
		||||
        "[Protocol]\n"
 | 
			
		||||
        "/dev/binder = hidl\n" /* Redefined name for /dev/binder */
 | 
			
		||||
        "/dev/hwbinder = foo\n"); /* Invalid protocol name */
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device(NULL);
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"aidl");
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device("/dev/hwbinder");
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"hidl");
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device("/dev/binder");
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"hidl"); /* Redefined by config */
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device("/dev/someotherbinder");
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"aidl");
 | 
			
		||||
 | 
			
		||||
    test_config_cleanup(&config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * config2
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_config2(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const GBinderRpcProtocol* p;
 | 
			
		||||
    TestConfig config;
 | 
			
		||||
 | 
			
		||||
    test_config_init(&config,
 | 
			
		||||
        "[Protocol]\n"
 | 
			
		||||
        "Default = hidl\n"
 | 
			
		||||
        "/dev/vndbinder = hidl\n"
 | 
			
		||||
        "/dev/hwbinder = foo\n"); /* Invalid protocol name */
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device(NULL);
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"aidl");
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device("/dev/vndbinder");
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"hidl");
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device("/dev/hwbinder");
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"hidl");
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device("/dev/binder");
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"aidl");
 | 
			
		||||
 | 
			
		||||
    /* The default is redefined */
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device("/dev/someotherbinder");
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"hidl");
 | 
			
		||||
 | 
			
		||||
    test_config_cleanup(&config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * config3
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_config3(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const GBinderRpcProtocol* p;
 | 
			
		||||
    TestConfig config;
 | 
			
		||||
 | 
			
		||||
    test_config_init(&config,
 | 
			
		||||
        "[Whatever]\n"
 | 
			
		||||
        "/dev/hwbinder = aidl\n"); /* Ignored, wrong section */
 | 
			
		||||
 | 
			
		||||
    /* Just the default config */
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device(NULL);
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"aidl");
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device("/dev/hwbinder");
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"hidl");
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device("/dev/binder");
 | 
			
		||||
    g_assert(p);
 | 
			
		||||
    g_assert_cmpstr(p->name, == ,"aidl");
 | 
			
		||||
 | 
			
		||||
    test_config_cleanup(&config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -97,14 +297,21 @@ test_device(
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_no_header1(
 | 
			
		||||
    void)
 | 
			
		||||
    gconstpointer test_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
 | 
			
		||||
        gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER), 0, 0);
 | 
			
		||||
    const TestData* test = test_data;
 | 
			
		||||
    GBinderRemoteRequest* req;
 | 
			
		||||
    TestConfig config;
 | 
			
		||||
 | 
			
		||||
    test_config_init2(&config, test->dev, test->prot);
 | 
			
		||||
 | 
			
		||||
    req = gbinder_remote_request_new(NULL, gbinder_rpc_protocol_for_device
 | 
			
		||||
        (GBINDER_DEFAULT_BINDER), 0, 0);
 | 
			
		||||
    gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION, NULL);
 | 
			
		||||
    g_assert(!gbinder_remote_request_interface(req));
 | 
			
		||||
    gbinder_remote_request_unref(req);
 | 
			
		||||
 | 
			
		||||
    test_config_cleanup(&config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -114,21 +321,35 @@ test_no_header1(
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_no_header2(
 | 
			
		||||
    void)
 | 
			
		||||
    gconstpointer test_data)
 | 
			
		||||
{
 | 
			
		||||
    const GBinderRpcProtocol* p = &gbinder_rpc_protocol_binder;
 | 
			
		||||
    GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, p);
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(NULL, p, 0, 0);
 | 
			
		||||
    const TestData* test = test_data;
 | 
			
		||||
    const GBinderRpcProtocol* p;
 | 
			
		||||
    GBinderDriver* driver;
 | 
			
		||||
    GBinderRemoteRequest* req;
 | 
			
		||||
    TestConfig config;
 | 
			
		||||
 | 
			
		||||
    test_config_init2(&config, test->dev, test->prot);
 | 
			
		||||
 | 
			
		||||
    p = gbinder_rpc_protocol_for_device(test->dev);
 | 
			
		||||
    driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, p);
 | 
			
		||||
    req = gbinder_remote_request_new(NULL, p, 0, 0);
 | 
			
		||||
 | 
			
		||||
    gbinder_remote_request_set_data(req, GBINDER_DUMP_TRANSACTION,
 | 
			
		||||
        gbinder_buffer_new(driver,
 | 
			
		||||
        g_memdup(TEST_ARRAY_AND_SIZE(test_header_binder)),
 | 
			
		||||
        sizeof(test_header_binder), NULL));
 | 
			
		||||
        g_memdup(TEST_ARRAY_AND_SIZE(test_header_aidl)),
 | 
			
		||||
        sizeof(test_header_aidl), NULL));
 | 
			
		||||
    g_assert(!gbinder_remote_request_interface(req));
 | 
			
		||||
    gbinder_remote_request_unref(req);
 | 
			
		||||
    gbinder_driver_unref(driver);
 | 
			
		||||
    test_config_cleanup(&config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const TestData test_no_header_data[] = {
 | 
			
		||||
    { "aidl", "aidl", GBINDER_DEFAULT_BINDER },
 | 
			
		||||
    { "aidl2", "aidl2", GBINDER_DEFAULT_BINDER },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * write_header
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
@@ -139,17 +360,24 @@ test_write_header(
 | 
			
		||||
    gconstpointer test_data)
 | 
			
		||||
{
 | 
			
		||||
    const TestHeaderData* test = test_data;
 | 
			
		||||
    const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(test->dev);
 | 
			
		||||
    GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
 | 
			
		||||
    const GBinderRpcProtocol* prot;
 | 
			
		||||
    GBinderLocalRequest* req;
 | 
			
		||||
    GBinderOutputData* data;
 | 
			
		||||
    GBinderWriter writer;
 | 
			
		||||
    TestConfig config;
 | 
			
		||||
 | 
			
		||||
    test_config_init2(&config, test->dev, test->prot);
 | 
			
		||||
 | 
			
		||||
    prot = gbinder_rpc_protocol_for_device(test->dev);
 | 
			
		||||
    req = gbinder_local_request_new(&gbinder_io_32, NULL);
 | 
			
		||||
    gbinder_local_request_init_writer(req, &writer);
 | 
			
		||||
    prot->write_rpc_header(&writer, test->iface);
 | 
			
		||||
    data = gbinder_local_request_data(req);
 | 
			
		||||
    g_assert(data->bytes->len == test->header_size);
 | 
			
		||||
    g_assert(!memcmp(data->bytes->data, test->header, test->header_size));
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
 | 
			
		||||
    test_config_cleanup(&config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -162,16 +390,23 @@ test_read_header(
 | 
			
		||||
    gconstpointer test_data)
 | 
			
		||||
{
 | 
			
		||||
    const TestHeaderData* test = test_data;
 | 
			
		||||
    GBinderDriver* driver = gbinder_driver_new(test->dev, NULL);
 | 
			
		||||
    GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
 | 
			
		||||
        gbinder_rpc_protocol_for_device(test->dev), 0, 0);
 | 
			
		||||
    GBinderDriver* driver;
 | 
			
		||||
    GBinderRemoteRequest* req;
 | 
			
		||||
    TestConfig config;
 | 
			
		||||
 | 
			
		||||
    test_config_init2(&config, test->dev, test->prot);
 | 
			
		||||
 | 
			
		||||
    driver = gbinder_driver_new(test->dev, NULL);
 | 
			
		||||
    req = gbinder_remote_request_new(NULL, gbinder_rpc_protocol_for_device
 | 
			
		||||
        (test->dev), 0, 0);
 | 
			
		||||
    gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
 | 
			
		||||
        gbinder_buffer_new(driver, g_memdup(test->header, test->header_size),
 | 
			
		||||
        test->header_size, NULL));
 | 
			
		||||
    g_assert(!g_strcmp0(gbinder_remote_request_interface(req), test->iface));
 | 
			
		||||
    g_assert_cmpstr(gbinder_remote_request_interface(req), == ,test->iface);
 | 
			
		||||
    gbinder_remote_request_unref(req);
 | 
			
		||||
    gbinder_driver_unref(driver);
 | 
			
		||||
 | 
			
		||||
    test_config_cleanup(&config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -187,20 +422,36 @@ int main(int argc, char* argv[])
 | 
			
		||||
 | 
			
		||||
    g_test_init(&argc, &argv, NULL);
 | 
			
		||||
    g_test_add_func(TEST_("device"), test_device);
 | 
			
		||||
    g_test_add_func(TEST_("no_header1"), test_no_header1);
 | 
			
		||||
    g_test_add_func(TEST_("no_header2"), test_no_header2);
 | 
			
		||||
    g_test_add_func(TEST_("config1"), test_config1);
 | 
			
		||||
    g_test_add_func(TEST_("config2"), test_config2);
 | 
			
		||||
    g_test_add_func(TEST_("config3"), test_config3);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < G_N_ELEMENTS(test_no_header_data); i++) {
 | 
			
		||||
        const TestData* test = test_no_header_data + i;
 | 
			
		||||
        char* path;
 | 
			
		||||
 | 
			
		||||
        path = g_strconcat(TEST_("no_header1/"), test->name, NULL);
 | 
			
		||||
        g_test_add_data_func(path, test, test_no_header1);
 | 
			
		||||
        g_free(path);
 | 
			
		||||
 | 
			
		||||
        path = g_strconcat(TEST_("no_header2/"), test->name, NULL);
 | 
			
		||||
        g_test_add_data_func(path, test, test_no_header2);
 | 
			
		||||
        g_free(path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < G_N_ELEMENTS(test_header_tests); i++) {
 | 
			
		||||
        const TestHeaderData* test = test_header_tests + i;
 | 
			
		||||
        char* path;
 | 
			
		||||
 | 
			
		||||
        path = g_strconcat(TEST_PREFIX, test->name, "/read_header", NULL);
 | 
			
		||||
        path = g_strconcat(TEST_("read_header/"), test->name, NULL);
 | 
			
		||||
        g_test_add_data_func(path, test, test_read_header);
 | 
			
		||||
        g_free(path);
 | 
			
		||||
 | 
			
		||||
        path = g_strconcat(TEST_PREFIX, test->name, "/write_header", NULL);
 | 
			
		||||
        g_test_add_data_func(path, test, test_write_header);
 | 
			
		||||
        g_free(path);
 | 
			
		||||
        if (test->iface) {
 | 
			
		||||
            path = g_strconcat(TEST_("write_header/"), test->name, NULL);
 | 
			
		||||
            g_test_add_data_func(path, test, test_write_header);
 | 
			
		||||
            g_free(path);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    test_init(&test_opt, argc, argv);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -14,8 +14,8 @@
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived from
 | 
			
		||||
 *      this software without specific prior written permission.
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -624,7 +624,7 @@ test_hidl_struct(
 | 
			
		||||
    gconstpointer test_data)
 | 
			
		||||
{
 | 
			
		||||
    const TestHidlStruct* test = test_data;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(test->in, test->in_size), test->in_size, NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -828,7 +828,7 @@ test_hidl_vec(
 | 
			
		||||
    gconstpointer test_data)
 | 
			
		||||
{
 | 
			
		||||
    const TestHidlVec* test = test_data;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(test->in, test->in_size), test->in_size, NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -934,7 +934,7 @@ test_hidl_string_err(
 | 
			
		||||
    gconstpointer test_data)
 | 
			
		||||
{
 | 
			
		||||
    const TestHidlStringErr* test = test_data;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(test->in, test->in_size), test->in_size, NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -968,7 +968,7 @@ test_hidl_string_err_skip(
 | 
			
		||||
    gconstpointer test_data)
 | 
			
		||||
{
 | 
			
		||||
    const TestHidlStringErr* test = test_data;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(test->in, test->in_size), test->in_size, NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -1013,7 +1013,7 @@ test_fd_ok(
 | 
			
		||||
        TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
 | 
			
		||||
        TEST_INT64_BYTES(0)
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(input, sizeof(input)), sizeof(input), NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -1053,7 +1053,7 @@ test_fd_shortbuf(
 | 
			
		||||
        TEST_INT32_BYTES(BINDER_TYPE_FD),
 | 
			
		||||
        TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS)
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(input, sizeof(input)), sizeof(input), NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -1087,7 +1087,7 @@ test_fd_badtype(
 | 
			
		||||
        TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
 | 
			
		||||
        TEST_INT64_BYTES(0)
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(input, sizeof(input)), sizeof(input), NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -1130,7 +1130,7 @@ test_dupfd_ok(
 | 
			
		||||
        TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
 | 
			
		||||
        TEST_INT64_BYTES(0)
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(input, sizeof(input)), sizeof(input), NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -1177,7 +1177,7 @@ test_dupfd_badtype(
 | 
			
		||||
        TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
 | 
			
		||||
        TEST_INT64_BYTES(0)
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(input, sizeof(input)), sizeof(input), NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -1220,7 +1220,7 @@ test_dupfd_badfd(
 | 
			
		||||
        TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
 | 
			
		||||
        TEST_INT64_BYTES(0)
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(input, sizeof(input)), sizeof(input), NULL);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
@@ -1259,7 +1259,7 @@ test_hidl_string(
 | 
			
		||||
    guint bufcount,
 | 
			
		||||
    const char* result)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver, g_memdup(input, size),
 | 
			
		||||
        size, NULL);
 | 
			
		||||
    GBinderRemoteObject* obj = NULL;
 | 
			
		||||
@@ -1530,7 +1530,7 @@ test_buffer(
 | 
			
		||||
        TEST_INT64_BYTES(0), TEST_INT64_BYTES(0),
 | 
			
		||||
        TEST_INT64_BYTES(0), TEST_INT64_BYTES(0)
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(input, sizeof(input)), sizeof(input), NULL);
 | 
			
		||||
    GBinderRemoteObject* obj = NULL;
 | 
			
		||||
@@ -1578,7 +1578,7 @@ test_object(
 | 
			
		||||
        TEST_INT32_BYTES(BINDER_TYPE_HANDLE), TEST_INT32_BYTES(0),
 | 
			
		||||
        TEST_INT64_BYTES(1 /* handle*/), TEST_INT64_BYTES(0)
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(input, sizeof(input)), sizeof(input), NULL);
 | 
			
		||||
    GBinderRemoteObject* obj = NULL;
 | 
			
		||||
@@ -1636,7 +1636,7 @@ test_object_invalid(
 | 
			
		||||
        TEST_INT32_BYTES(42 /* invalid type */), TEST_INT32_BYTES(0),
 | 
			
		||||
        TEST_INT64_BYTES(1 /* handle*/), TEST_INT64_BYTES(0)
 | 
			
		||||
    };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
 | 
			
		||||
        g_memdup(input, sizeof(input)), sizeof(input), NULL);
 | 
			
		||||
    GBinderRemoteObject* obj = NULL;
 | 
			
		||||
@@ -1670,7 +1670,7 @@ test_vec(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    /* Using 64-bit I/O */
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderReaderData data;
 | 
			
		||||
    GBinderReader reader;
 | 
			
		||||
    BinderObject64 obj;
 | 
			
		||||
@@ -1723,7 +1723,7 @@ test_hidl_string_vec(
 | 
			
		||||
    gsize size,
 | 
			
		||||
    const char* const* result)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    GBinderBuffer* buf = gbinder_buffer_new(ipc->driver, g_memdup(input, size),
 | 
			
		||||
        size, NULL);
 | 
			
		||||
    GBinderRemoteObject* obj = NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -14,8 +14,8 @@
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived from
 | 
			
		||||
 *      this software without specific prior written permission.
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
@@ -68,7 +68,7 @@ void
 | 
			
		||||
test_basic(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
 | 
			
		||||
    GBinderRemoteObject* obj1 = gbinder_object_registry_get_remote(reg, 1);
 | 
			
		||||
    GBinderRemoteObject* obj2 = gbinder_object_registry_get_remote(reg, 2);
 | 
			
		||||
@@ -112,7 +112,7 @@ test_dead(
 | 
			
		||||
{
 | 
			
		||||
    const guint handle = 1;
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderRemoteObject* obj = gbinder_ipc_get_remote_object
 | 
			
		||||
        (ipc, handle, FALSE);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -34,6 +34,7 @@
 | 
			
		||||
 | 
			
		||||
#include "gbinder_driver.h"
 | 
			
		||||
#include "gbinder_client_p.h"
 | 
			
		||||
#include "gbinder_config.h"
 | 
			
		||||
#include "gbinder_remote_object_p.h"
 | 
			
		||||
#include "gbinder_ipc.h"
 | 
			
		||||
#include "gbinder_local_object_p.h"
 | 
			
		||||
@@ -47,6 +48,7 @@
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
static TestOpt test_opt;
 | 
			
		||||
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-servicemanager-XXXXXX";
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
@@ -224,7 +226,7 @@ test_hwservicemanager_check_name(
 | 
			
		||||
{
 | 
			
		||||
    TestHwServiceManager* self = TEST_HWSERVICEMANAGER(sm);
 | 
			
		||||
 | 
			
		||||
    return (!name || self->reject_name) ? 
 | 
			
		||||
    return (!name || self->reject_name) ?
 | 
			
		||||
        GBINDER_SERVICEMANAGER_NAME_INVALID :
 | 
			
		||||
        GBINDER_SERVICEMANAGER_NAME_NORMALIZE;
 | 
			
		||||
}
 | 
			
		||||
@@ -281,7 +283,6 @@ test_hwservicemanager_class_init(
 | 
			
		||||
{
 | 
			
		||||
    klass->iface = TEST_HWSERVICEMANAGER_IFACE;
 | 
			
		||||
    klass->default_device = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;
 | 
			
		||||
    klass->list = test_servicemanager_list;
 | 
			
		||||
    klass->get_service = test_servicemanager_get_service;
 | 
			
		||||
    klass->add_service = test_servicemanager_add_service;
 | 
			
		||||
@@ -292,12 +293,10 @@ test_hwservicemanager_class_init(
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = test_hwservicemanager_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_hwservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
GType
 | 
			
		||||
gbinder_servicemanager_hidl_get_type()
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type(TEST_TYPE_HWSERVICEMANAGER,
 | 
			
		||||
        dev);
 | 
			
		||||
    return TEST_TYPE_HWSERVICEMANAGER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -325,7 +324,7 @@ test_defservicemanager_check_name(
 | 
			
		||||
{
 | 
			
		||||
    TestDefServiceManager* self = TEST_DEFSERVICEMANAGER(sm);
 | 
			
		||||
 | 
			
		||||
    return (!name || self->reject_name) ? 
 | 
			
		||||
    return (!name || self->reject_name) ?
 | 
			
		||||
        GBINDER_SERVICEMANAGER_NAME_INVALID :
 | 
			
		||||
        GBINDER_SERVICEMANAGER_NAME_OK;
 | 
			
		||||
}
 | 
			
		||||
@@ -365,7 +364,6 @@ test_defservicemanager_class_init(
 | 
			
		||||
{
 | 
			
		||||
    klass->iface = TEST_DEFSERVICEMANAGER_IFACE;
 | 
			
		||||
    klass->default_device = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    klass->rpc_protocol = &gbinder_rpc_protocol_binder;
 | 
			
		||||
    klass->list = test_servicemanager_list;
 | 
			
		||||
    klass->get_service = test_servicemanager_get_service;
 | 
			
		||||
    klass->add_service = test_servicemanager_add_service;
 | 
			
		||||
@@ -374,12 +372,17 @@ test_defservicemanager_class_init(
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = test_defservicemanager_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_defaultservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
GType
 | 
			
		||||
gbinder_servicemanager_aidl_get_type()
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type(TEST_TYPE_DEFSERVICEMANAGER,
 | 
			
		||||
        dev);
 | 
			
		||||
    return TEST_TYPE_DEFSERVICEMANAGER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GType
 | 
			
		||||
gbinder_servicemanager_aidl2_get_type()
 | 
			
		||||
{
 | 
			
		||||
    /* Avoid pulling in gbinder_servicemanager_aidl2 object */
 | 
			
		||||
    return TEST_TYPE_DEFSERVICEMANAGER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -391,6 +394,7 @@ void
 | 
			
		||||
test_null(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    g_assert(!gbinder_servicemanager_new(NULL));
 | 
			
		||||
    g_assert(!gbinder_servicemanager_new_with_type(0, NULL));
 | 
			
		||||
    g_assert(!gbinder_servicemanager_new_local_object(NULL, NULL, NULL, NULL));
 | 
			
		||||
    g_assert(!gbinder_servicemanager_ref(NULL));
 | 
			
		||||
@@ -423,7 +427,7 @@ test_invalid(
 | 
			
		||||
{
 | 
			
		||||
    int status = 0;
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
    gulong id = 0;
 | 
			
		||||
 | 
			
		||||
@@ -466,9 +470,9 @@ static
 | 
			
		||||
void
 | 
			
		||||
test_basic(
 | 
			
		||||
    void)
 | 
			
		||||
{ 
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
    GBinderLocalObject* obj;
 | 
			
		||||
 | 
			
		||||
@@ -486,6 +490,122 @@ test_basic(
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * legacy
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_legacy(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* otherdev = "/dev/otherbinder";
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
 | 
			
		||||
    /* Reset the state */
 | 
			
		||||
    gbinder_servicemanager_exit();
 | 
			
		||||
    gbinder_config_exit();
 | 
			
		||||
    gbinder_config_file = NULL;
 | 
			
		||||
 | 
			
		||||
    test_setup_ping(ipc);
 | 
			
		||||
    sm = gbinder_hwservicemanager_new(dev);
 | 
			
		||||
    g_assert(TEST_IS_HWSERVICEMANAGER(sm));
 | 
			
		||||
    gbinder_servicemanager_unref(sm);
 | 
			
		||||
 | 
			
		||||
    test_setup_ping(ipc);
 | 
			
		||||
    sm = gbinder_defaultservicemanager_new(dev);
 | 
			
		||||
    g_assert(TEST_IS_DEFSERVICEMANAGER(sm));
 | 
			
		||||
    gbinder_servicemanager_unref(sm);
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
 | 
			
		||||
    /* Legacy default */
 | 
			
		||||
    ipc = gbinder_ipc_new(otherdev);
 | 
			
		||||
    test_setup_ping(ipc);
 | 
			
		||||
    sm = gbinder_servicemanager_new(otherdev);
 | 
			
		||||
    g_assert(TEST_IS_DEFSERVICEMANAGER(sm));
 | 
			
		||||
    gbinder_servicemanager_unref(sm);
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_servicemanager_exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * config
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_config(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc;
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
    const char* strange_name = "/dev/notbinder";
 | 
			
		||||
    const char* legacy_name = "/dev/legacybinder";
 | 
			
		||||
    char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
 | 
			
		||||
    char* file = g_build_filename(dir, "test.conf", NULL);
 | 
			
		||||
 | 
			
		||||
    static const char config[] =
 | 
			
		||||
        "[ServiceManager]\n"
 | 
			
		||||
        "Default = hidl\n"
 | 
			
		||||
        "/dev/binder = hidl\n" /* Redefined name for /dev/binder */
 | 
			
		||||
        "/dev/hwbinder = foo\n" /* Invalid name */
 | 
			
		||||
        "/dev/legacybinder = aidl\n";
 | 
			
		||||
 | 
			
		||||
    /* Reset the state */
 | 
			
		||||
    gbinder_servicemanager_exit();
 | 
			
		||||
    gbinder_config_exit();
 | 
			
		||||
 | 
			
		||||
    /* Write the config file */
 | 
			
		||||
    g_assert(g_file_set_contents(file, config, -1, NULL));
 | 
			
		||||
    gbinder_config_file = file;
 | 
			
		||||
 | 
			
		||||
    /* Unknown device instantiates the default */
 | 
			
		||||
    ipc = gbinder_ipc_new(strange_name);
 | 
			
		||||
    test_setup_ping(ipc);
 | 
			
		||||
    sm = gbinder_servicemanager_new(strange_name);
 | 
			
		||||
    g_assert(TEST_IS_HWSERVICEMANAGER(sm));
 | 
			
		||||
    gbinder_servicemanager_unref(sm);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
 | 
			
		||||
    /* This one was redefined */
 | 
			
		||||
    ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    test_setup_ping(ipc);
 | 
			
		||||
    sm = gbinder_servicemanager_new(GBINDER_DEFAULT_BINDER);
 | 
			
		||||
    g_assert(TEST_IS_HWSERVICEMANAGER(sm));
 | 
			
		||||
    gbinder_servicemanager_unref(sm);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
 | 
			
		||||
    /* This one was not (since name was invalid) */
 | 
			
		||||
    ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    test_setup_ping(ipc);
 | 
			
		||||
    sm = gbinder_servicemanager_new(GBINDER_DEFAULT_HWBINDER);
 | 
			
		||||
    g_assert(TEST_IS_HWSERVICEMANAGER(sm));
 | 
			
		||||
    gbinder_servicemanager_unref(sm);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
 | 
			
		||||
    /* This one points to legacy manager */
 | 
			
		||||
    ipc = gbinder_ipc_new(legacy_name);
 | 
			
		||||
    test_setup_ping(ipc);
 | 
			
		||||
    sm = gbinder_servicemanager_new(legacy_name);
 | 
			
		||||
    g_assert(TEST_IS_DEFSERVICEMANAGER(sm));
 | 
			
		||||
    gbinder_servicemanager_unref(sm);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
 | 
			
		||||
    /* Clear the state */
 | 
			
		||||
    gbinder_servicemanager_exit();
 | 
			
		||||
    gbinder_config_exit();
 | 
			
		||||
    gbinder_config_file = NULL;
 | 
			
		||||
 | 
			
		||||
    remove(file);
 | 
			
		||||
    remove(dir);
 | 
			
		||||
    g_free(file);
 | 
			
		||||
    g_free(dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * not_present
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
@@ -494,9 +614,9 @@ static
 | 
			
		||||
void
 | 
			
		||||
test_not_present(
 | 
			
		||||
    void)
 | 
			
		||||
{ 
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
 | 
			
		||||
@@ -519,9 +639,9 @@ static
 | 
			
		||||
void
 | 
			
		||||
test_wait(
 | 
			
		||||
    void)
 | 
			
		||||
{ 
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    const glong forever = (test_opt.flags & TEST_FLAG_DEBUG) ?
 | 
			
		||||
        (TEST_TIMEOUT_SEC * 1000) : -1;
 | 
			
		||||
@@ -569,9 +689,9 @@ static
 | 
			
		||||
void
 | 
			
		||||
test_wait_long(
 | 
			
		||||
    void)
 | 
			
		||||
{ 
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
    gulong id;
 | 
			
		||||
@@ -614,9 +734,9 @@ static
 | 
			
		||||
void
 | 
			
		||||
test_wait_async(
 | 
			
		||||
    void)
 | 
			
		||||
{ 
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
@@ -658,9 +778,9 @@ static
 | 
			
		||||
void
 | 
			
		||||
test_death(
 | 
			
		||||
    void)
 | 
			
		||||
{ 
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
@@ -728,7 +848,7 @@ test_reanimate(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
@@ -777,13 +897,13 @@ static
 | 
			
		||||
void
 | 
			
		||||
test_reuse(
 | 
			
		||||
    void)
 | 
			
		||||
{ 
 | 
			
		||||
{
 | 
			
		||||
    const char* binder_dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    const char* vndbinder_dev = "/dev/vpnbinder";
 | 
			
		||||
    const char* hwbinder_dev = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    GBinderIpc* binder_ipc = gbinder_ipc_new(binder_dev, NULL);
 | 
			
		||||
    GBinderIpc* vndbinder_ipc = gbinder_ipc_new(vndbinder_dev, NULL);
 | 
			
		||||
    GBinderIpc* hwbinder_ipc = gbinder_ipc_new(hwbinder_dev, NULL);
 | 
			
		||||
    GBinderIpc* binder_ipc = gbinder_ipc_new(binder_dev);
 | 
			
		||||
    GBinderIpc* vndbinder_ipc = gbinder_ipc_new(vndbinder_dev);
 | 
			
		||||
    GBinderIpc* hwbinder_ipc = gbinder_ipc_new(hwbinder_dev);
 | 
			
		||||
    GBinderServiceManager* m1;
 | 
			
		||||
    GBinderServiceManager* m2;
 | 
			
		||||
    GBinderServiceManager* vnd1;
 | 
			
		||||
@@ -835,7 +955,7 @@ test_notify_type(
 | 
			
		||||
    GType t,
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
    TestHwServiceManager* test;
 | 
			
		||||
    const char* name = "foo";
 | 
			
		||||
@@ -902,7 +1022,7 @@ test_list(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
    TestHwServiceManager* test;
 | 
			
		||||
@@ -950,7 +1070,7 @@ test_get(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
    TestHwServiceManager* test;
 | 
			
		||||
@@ -1011,7 +1131,7 @@ test_add(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
    TestHwServiceManager* test;
 | 
			
		||||
@@ -1048,6 +1168,8 @@ int main(int argc, char* argv[])
 | 
			
		||||
    g_test_add_func(TEST_("null"), test_null);
 | 
			
		||||
    g_test_add_func(TEST_("invalid"), test_invalid);
 | 
			
		||||
    g_test_add_func(TEST_("basic"), test_basic);
 | 
			
		||||
    g_test_add_func(TEST_("legacy"), test_legacy);
 | 
			
		||||
    g_test_add_func(TEST_("config"), test_config);
 | 
			
		||||
    g_test_add_func(TEST_("not_present"), test_not_present);
 | 
			
		||||
    g_test_add_func(TEST_("wait"), test_wait);
 | 
			
		||||
    g_test_add_func(TEST_("wait_long"), test_wait_long);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								unit/unit_servicemanager_aidl/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								unit/unit_servicemanager_aidl/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
# -*- Mode: makefile-gmake -*-
 | 
			
		||||
 | 
			
		||||
EXE = unit_servicemanager_aidl
 | 
			
		||||
 | 
			
		||||
include ../common/Makefile
 | 
			
		||||
							
								
								
									
										444
									
								
								unit/unit_servicemanager_aidl/unit_servicemanager_aidl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								unit/unit_servicemanager_aidl/unit_servicemanager_aidl.c
									
									
									
									
									
										Normal 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:
 | 
			
		||||
 */
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2019-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2019-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -202,7 +202,6 @@ test_servicemanager_class_init(
 | 
			
		||||
{
 | 
			
		||||
    klass->iface = TEST_SERVICEMANAGER_IFACE;
 | 
			
		||||
    klass->default_device = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    klass->rpc_protocol = &gbinder_rpc_protocol_binder;
 | 
			
		||||
    klass->list = test_servicemanager_list;
 | 
			
		||||
    klass->get_service = test_servicemanager_get_service;
 | 
			
		||||
    klass->add_service = test_servicemanager_add_service;
 | 
			
		||||
@@ -212,18 +211,24 @@ test_servicemanager_class_init(
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = test_servicemanager_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_defaultservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
/* Avoid pulling in the actual objects */
 | 
			
		||||
 | 
			
		||||
GType
 | 
			
		||||
gbinder_servicemanager_aidl_get_type()
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type(TEST_TYPE_SERVICEMANAGER, dev);
 | 
			
		||||
    return TEST_TYPE_SERVICEMANAGER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_hwservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
GType
 | 
			
		||||
gbinder_servicemanager_aidl2_get_type()
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new(dev);
 | 
			
		||||
    return TEST_TYPE_SERVICEMANAGER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GType
 | 
			
		||||
gbinder_servicemanager_hidl_get_type()
 | 
			
		||||
{
 | 
			
		||||
    return TEST_TYPE_SERVICEMANAGER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -236,7 +241,7 @@ test_null(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
 | 
			
		||||
    test_setup_ping(ipc);
 | 
			
		||||
@@ -263,7 +268,7 @@ test_basic(
 | 
			
		||||
    const char* obj_name = "test";
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    const char* const ifaces[] = { "interface", NULL };
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderLocalObject* obj;
 | 
			
		||||
    GBinderServiceManager* sm;
 | 
			
		||||
@@ -306,7 +311,7 @@ test_present(
 | 
			
		||||
    const char* obj_name = "test";
 | 
			
		||||
    const char* const ifaces[] = { "interface", NULL };
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderLocalObject* obj;
 | 
			
		||||
@@ -371,7 +376,7 @@ test_not_present(
 | 
			
		||||
    const char* obj_name = "test";
 | 
			
		||||
    const char* const ifaces[] = { "interface", NULL };
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderLocalObject* obj;
 | 
			
		||||
@@ -421,7 +426,7 @@ test_cancel(
 | 
			
		||||
    const char* obj_name = "test";
 | 
			
		||||
    const char* const ifaces[] = { "interface", NULL };
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    const int fd = gbinder_driver_fd(ipc->driver);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderLocalObject* obj;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2019 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2020 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -174,7 +174,6 @@ test_servicemanager_class_init(
 | 
			
		||||
{
 | 
			
		||||
    klass->iface = TEST_SERVICEMANAGER_IFACE;
 | 
			
		||||
    klass->default_device = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    klass->rpc_protocol = &gbinder_rpc_protocol_binder;
 | 
			
		||||
    klass->list = test_servicemanager_list;
 | 
			
		||||
    klass->get_service = test_servicemanager_get_service;
 | 
			
		||||
    klass->add_service = test_servicemanager_add_service;
 | 
			
		||||
@@ -184,18 +183,24 @@ test_servicemanager_class_init(
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = test_servicemanager_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_defaultservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
/* Avoid pulling in the actual objects */
 | 
			
		||||
 | 
			
		||||
GType
 | 
			
		||||
gbinder_servicemanager_aidl_get_type()
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type(TEST_TYPE_SERVICEMANAGER, dev);
 | 
			
		||||
    return TEST_TYPE_SERVICEMANAGER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_hwservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
GType
 | 
			
		||||
gbinder_servicemanager_aidl2_get_type()
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new(dev);
 | 
			
		||||
    return TEST_TYPE_SERVICEMANAGER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GType
 | 
			
		||||
gbinder_servicemanager_hidl_get_type()
 | 
			
		||||
{
 | 
			
		||||
    return TEST_TYPE_SERVICEMANAGER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -225,7 +230,7 @@ test_basic(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GBinderServicePoll* weakptr = NULL;
 | 
			
		||||
    GBinderServiceManager* manager;
 | 
			
		||||
    GBinderServicePoll* poll;
 | 
			
		||||
@@ -301,7 +306,7 @@ test_notify1(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServicePoll* weakptr = NULL;
 | 
			
		||||
    GBinderServiceManager* manager;
 | 
			
		||||
@@ -375,7 +380,7 @@ test_notify2(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServicePoll* weakptr = NULL;
 | 
			
		||||
    GBinderServiceManager* manager;
 | 
			
		||||
@@ -434,7 +439,7 @@ test_already_there(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    const char* dev = GBINDER_DEFAULT_BINDER;
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
 | 
			
		||||
    GBinderIpc* ipc = gbinder_ipc_new(dev);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServicePoll* weakptr = NULL;
 | 
			
		||||
    GBinderServiceManager* manager;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user