Compare commits

...

48 Commits

Author SHA1 Message Date
Slava Monich
b84194e8c7 Version 1.1.0 2020-12-04 13:50:42 +02:00
Slava Monich
e06e989aa5 [gbinder] Updated README 2020-12-04 13:44:41 +02:00
Slava Monich
ab75505437 Merge pull request #56 from monich/config
Make protocol and service managers configurable per binder device
2020-12-04 13:33:10 +02:00
Slava Monich
e97663b58e [gbinder] Added support for API level presets. JB#51844
API level can be configured via libgbinder config file like this:

  [General]
  ApiLevel = 28

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

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

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

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

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

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

  [Protocol]
  Default = aidl
  /dev/binder = aidl
  /dev/hwbinder = hidl
2020-12-03 20:15:33 +02:00
Slava Monich
8a634a0d95 Version 1.0.47 2020-09-19 20:17:50 +03:00
Slava Monich
23c5d48b5d Merge pull request #55 from rinigus/permissions
Install library as executable
2020-09-19 20:12:01 +03:00
Rinigus
f000b344dd [packaging] Install library as executable. JB#51013
Installs the library with exe permissions, as expected on RPM systems.

Signed-off-by: Rinigus <rinigus.git@gmail.com>
2020-09-19 20:05:37 +03:00
Slava Monich
42177e1ff2 Version 1.0.46 2020-07-31 02:06:28 +03:00
Slava Monich
091ca483e7 Merge pull request #52 from monich/wakeup_err
WARNING! Failed to wake up the looper
2020-07-31 02:01:13 +03:00
Slava Monich
42ce4f8821 Merge pull request #54 from monich/tools
Package binder-list and binder-ping utilities
2020-07-31 01:59:42 +03:00
Slava Monich
9a1781765b [packaging] Package binder-list and binder-ping tools. JB#42956
Package those as a separate package which won't be getting installed
by default, but will be easy enough to pull in, if needed. They are
quite useful as development tools.
2020-07-31 01:28:51 +03:00
Slava Monich
544b8181e5 [binder-list] Use /dev/hwbinder by default. JB#42956
It's become far more common use case recently.
2020-07-31 00:42:35 +03:00
Slava Monich
82ea37ead9 Version 1.0.45 2020-07-27 23:20:41 +03:00
Slava Monich
882ef93084 Merge pull request #53 from monich/null_vec
Fix long-standing issue with NULL vectors
2020-07-27 22:45:40 +03:00
Slava Monich
881469ab7f [gbinder] Always provide data buffer for hidl vector. JB#42956
Every vector, even the one without data, requires two buffer objects.
That's what generated stubs expect.
2020-07-27 20:53:01 +03:00
Slava Monich
d7834650ae [gbinder] Make sure we drop fds that are going to be closed. JB#50224
Even if for whatever reason the transaction thread doesn't get woken up
by the transaction handler, it (the transaction thread) still needs to
drop the transaction pipe fds unless all other references have already
been dropped. Otherwise those fds are going to be closed by whoever
drops the last reference to GBinderIpcLooperTx and become invalid.
2020-07-16 17:45:17 +03:00
Slava Monich
20bf183a10 [gbinder] Better diagnostics for polling failures. JB#50224
Something fishy is going on sometimes, which results in transaction
pipe descriptors being closed and yet still being used. Let's see
if this sheds any light on it.
2020-07-09 01:40:16 +03:00
Slava Monich
c990ac66da Version 1.0.44 2020-06-29 17:07:25 +03:00
Slava Monich
0964163a35 Merge pull request #51 from monich/jb49615
Never drop valid incoming transactions
2020-06-29 17:01:08 +03:00
Slava Monich
fc980b1bc9 [unit] Added GBinderIpc tests. JB#49615
Simulate simultaneous two-way transactions.
2020-06-26 16:10:22 +03:00
Slava Monich
e76c8a3ba7 [gbinder] Never drop valid incoming transactions. Fixes JB#49615
Incoming transactions were being rejected if they were received
while we were waiting for completion of our own transaction.
That wasn't right.
2020-06-26 16:09:17 +03:00
Slava Monich
5805290369 Version 1.0.43 2020-06-03 15:16:40 +03:00
Slava Monich
7dd9623929 Merge pull request #48 from krnlyng/jb49520
Allow strip command to be replaced through external environment variable STRIP
2020-06-03 15:07:57 +03:00
Slava Monich
95ac07e4de Merge pull request #49 from monich/lib64
Respect arch specific lib dir
2020-06-03 15:04:36 +03:00
Slava Monich
92cd463b34 [gbinder] Respect arch specific lib dir. JB#49681 2020-06-03 01:47:58 +03:00
Slava Monich
6832546dca [gbinder] Hide internal symbols. JB#42956 2020-06-03 01:33:23 +03:00
Franz-Josef Haider
049042b134 libgbinder: allow strip command to be replaced through external environment variable STRIP.
[libgbinder] allow strip command to be replaced through external environment variable STRIP. JB#49520
2020-05-29 12:22:40 +00:00
Slava Monich
6d2f2efe31 Version 1.0.42 2020-05-05 20:01:45 +03:00
Slava Monich
bcce4831e3 Merge pull request #47 from monich/multi-client
Support for multiple versions of hwbinder interfaces
2020-05-05 19:55:06 +03:00
Slava Monich
7fb3053135 [unit] Added test for the GBinderClient API. JB#49360 2020-05-05 19:45:36 +03:00
Slava Monich
00359a0fc8 [gbinder] Allow GBinderClient to use more than one interface. JB#49360
Or more likely, multiple versions of the same interface. For example,
first N transaction codes may be associated with version 1.0 of the
interface, the next M codes with version 1.1 and so on.

The following new functions have been introduced:

  gbinder_client_new2
  gbinder_client_interface2
  gbinder_client_new_request2

Note that a similar functionality could be achieved by allocating
a separate client for each version of the interface. This is just
a more convenient way of doing pretty much the same thing.

The old API still works, just assumes the same interface for all
transaction codes.
2020-05-05 19:44:14 +03:00
Slava Monich
ccf3e1237c Version 1.0.41 2020-04-14 12:40:05 +03:00
Slava Monich
e02f00fd41 Merge pull request #45 from monich/idle-pool
Stop using GUtilIdlePool
2020-04-14 12:34:42 +03:00
Slava Monich
e45e640f3c [gbinder] Stop using GUtilIdlePool. JB#49512
It won't work with a non-glib event loop. And one of those objects
turned out to actually be unused.
2020-04-11 02:26:46 +03:00
Slava Monich
75e8015c43 [gbinder] Added internal event loop utilities. JB#49512
gbinder_idle_callback_schedule_new = gbinder_idle_callback_new +
and gbinder_idle_callback_schedule

gbinder_idle_callback_destroy = gbinder_idle_callback_cancel +
gbinder_idle_callback_unref
2020-04-11 02:22:22 +03:00
Slava Monich
2c52fcc156 Version 1.0.40 2020-04-09 17:24:06 +03:00
Slava Monich
dc5b51a41f Merge pull request #44 from monich/event-loop
Pluggable event loop integration
2020-04-09 17:18:29 +03:00
Slava Monich
d12cee4690 [unit] Added eventloop test. JB#49512 2020-04-06 17:22:55 +03:00
Slava Monich
a74c4ac148 [gbinder] Virtualize event loop. JB#49512
This makes it possible to make libgbinder work with e.g. Qt event loop
based on QEventDispatcherUNIX (rather than QEventDispatcherGlib).
2020-04-04 20:26:06 +03:00
Slava Monich
53e50a8107 Version 1.0.39 2020-04-02 18:08:05 +03:00
Slava Monich
e896ba94cc Merge pull request #43 from mer-hybris/side-by-side-linking
Fix linking for side-by-side builds
2020-04-02 18:04:56 +03:00
Matti Lehtimäki
87ff990c73 [build] Fix linking for side-by-side builds. JB#49231 2020-04-02 14:48:16 +00:00
79 changed files with 4684 additions and 1110 deletions

14
.gitignore vendored
View File

@@ -1,13 +1,13 @@
*~
debian/files
debian/libgbinder-dev.debhelper.log
debian/libgbinder-dev.substvars
debian/libgbinder-dev
debian/libgbinder.debhelper.log
debian/libgbinder.postinst.debhelper
debian/libgbinder.postrm.debhelper
debian/libgbinder.substvars
debian/libgbinder
debian/libgbinder-dev
debian/libgbinder-tools
debian/*.debhelper.log
debian/*.debhelper
debian/*.substvars
debian/libgbinder.install
debian/libgbinder-dev.install
debian/tmp
documentation.list
installroot

View File

@@ -15,8 +15,8 @@
#
VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_RELEASE = 38
VERSION_MINOR = 1
VERSION_RELEASE = 0
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
@@ -78,7 +78,9 @@ SRC = \
gbinder_buffer.c \
gbinder_cleanup.c \
gbinder_client.c \
gbinder_config.c \
gbinder_driver.c \
gbinder_eventloop.c \
gbinder_io_32.c \
gbinder_io_64.c \
gbinder_ipc.c \
@@ -96,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
@@ -119,6 +122,7 @@ COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
#
CC ?= $(CROSS_COMPILE)gcc
STRIP ?= strip
LD = $(CC)
WARNINGS = -Wall -Wstrict-aliasing -Wunused-result
INCLUDES += -I$(INCLUDE_DIR)
@@ -131,10 +135,7 @@ DEBUG_FLAGS = -g
RELEASE_FLAGS =
COVERAGE_FLAGS = -g
ifndef KEEP_SYMBOLS
KEEP_SYMBOLS = 0
endif
KEEP_SYMBOLS ?= 0
ifneq ($(KEEP_SYMBOLS),0)
RELEASE_FLAGS += -g
endif
@@ -178,13 +179,15 @@ DEBUG_SO = $(DEBUG_BUILD_DIR)/$(LIB_SO)
RELEASE_SO = $(RELEASE_BUILD_DIR)/$(LIB_SO)
DEBUG_LINK = $(DEBUG_BUILD_DIR)/$(LIB_SYMLINK1)
RELEASE_LINK = $(RELEASE_BUILD_DIR)/$(LIB_SYMLINK1)
DEBUG_DEV_LINK = $(DEBUG_BUILD_DIR)/$(LIB_DEV_SYMLINK)
RELEASE_DEV_LINK = $(RELEASE_BUILD_DIR)/$(LIB_DEV_SYMLINK)
DEBUG_LIB = $(DEBUG_BUILD_DIR)/$(LIB)
RELEASE_LIB = $(RELEASE_BUILD_DIR)/$(LIB)
COVERAGE_LIB = $(COVERAGE_BUILD_DIR)/$(LIB)
debug: $(DEBUG_SO)
debug: $(DEBUG_SO) $(DEBUG_LINK) $(DEBUG_DEV_LINK)
release: $(RELEASE_SO)
release: $(RELEASE_SO) $(RELEASE_LINK) $(RELEASE_DEV_LINK)
debug_lib: $(DEBUG_LIB)
@@ -230,6 +233,7 @@ clean:
rm -fr debian/tmp debian/libgbinder debian/libgbinder-dev
rm -f documentation.list debian/files debian/*.substvars
rm -f debian/*.debhelper.log debian/*.debhelper debian/*~
rm -f debian/libgbinder.install debian/libgbinder-dev.install
test:
make -C unit test
@@ -257,13 +261,11 @@ $(COVERAGE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(DEBUG_SO): $(DEBUG_OBJS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) -o $@
ln -sf $(LIB_SO) $(DEBUG_LINK)
$(RELEASE_SO): $(RELEASE_OBJS)
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) -o $@
ln -sf $(LIB_SO) $(RELEASE_LINK)
ifeq ($(KEEP_SYMBOLS),0)
strip $@
$(STRIP) $@
endif
$(DEBUG_LIB): $(DEBUG_OBJS)
@@ -274,12 +276,35 @@ $(RELEASE_LIB): $(RELEASE_OBJS)
$(AR) rc $@ $?
ranlib $@
$(DEBUG_LINK):
ln -sf $(LIB_SO) $@
$(RELEASE_LINK):
ln -sf $(LIB_SO) $@
$(DEBUG_DEV_LINK):
ln -sf $(LIB_SYMLINK1) $@
$(RELEASE_DEV_LINK):
ln -sf $(LIB_SYMLINK1) $@
$(COVERAGE_LIB): $(COVERAGE_OBJS)
$(AR) rc $@ $?
ranlib $@
#
# LIBDIR usually gets substituted with arch specific dir.
# It's relative in deb build and can be whatever in rpm build.
#
LIBDIR ?= usr/lib
ABS_LIBDIR := $(shell echo /$(LIBDIR) | sed -r 's|/+|/|g')
$(PKGCONFIG): $(LIB_NAME).pc.in Makefile
sed -e 's/\[version\]/'$(PCVERSION)/g $< > $@
sed -e 's|@version@|$(PCVERSION)|g' -e 's|@libdir@|$(ABS_LIBDIR)|g' $< > $@
debian/%.install: debian/%.install.in
sed 's|@LIBDIR@|$(LIBDIR)|g' $< > $@
#
# Install
@@ -291,12 +316,12 @@ INSTALL = install
INSTALL_DIRS = $(INSTALL) -d
INSTALL_FILES = $(INSTALL) -m $(INSTALL_PERM)
INSTALL_LIB_DIR = $(DESTDIR)/usr/lib
INSTALL_LIB_DIR = $(DESTDIR)$(ABS_LIBDIR)
INSTALL_INCLUDE_DIR = $(DESTDIR)/usr/include/$(NAME)
INSTALL_PKGCONFIG_DIR = $(DESTDIR)/usr/lib/pkgconfig
INSTALL_PKGCONFIG_DIR = $(DESTDIR)$(ABS_LIBDIR)/pkgconfig
install: $(INSTALL_LIB_DIR)
$(INSTALL_FILES) $(RELEASE_SO) $(INSTALL_LIB_DIR)
$(INSTALL) -m 755 $(RELEASE_SO) $(INSTALL_LIB_DIR)
ln -sf $(LIB_SO) $(INSTALL_LIB_DIR)/$(LIB_SYMLINK2)
ln -sf $(LIB_SYMLINK2) $(INSTALL_LIB_DIR)/$(LIB_SYMLINK1)

39
README
View File

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

69
debian/changelog vendored
View File

@@ -1,3 +1,72 @@
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
-- Slava Monich <slava.monich@jolla.com> Sat, 19 Sep 2020 20:14:20 +0300
libgbinder (1.0.46) unstable; urgency=low
* Make sure we drop fds that are going to be closed
* Better diagnostics for polling failures
* Package binder-list and binder-ping utilities
-- Slava Monich <slava.monich@jolla.com> Fri, 31 Jul 2020 02:04:38 +0300
libgbinder (1.0.45) unstable; urgency=low
* Always provide data buffer for hidl vector
-- Slava Monich <slava.monich@jolla.com> Mon, 27 Jul 2020 23:19:25 +0300
libgbinder (1.0.44) unstable; urgency=low
* Never drop valid incoming transactions
-- Slava Monich <slava.monich@jolla.com> Mon, 29 Jun 2020 17:05:22 +0300
libgbinder (1.0.43) unstable; urgency=low
* Hide internal symbols
* Respect arch specific lib dir
* Allow strip command to be replaced via environment variable
-- Slava Monich <slava.monich@jolla.com> Wed, 03 Jun 2020 15:15:40 +0300
libgbinder (1.0.42) unstable; urgency=low
* Allow GBinderClient to use multiple interfaces
-- Slava Monich <slava.monich@jolla.com> Tue, 05 May 2020 19:56:39 +0300
libgbinder (1.0.41) unstable; urgency=low
* Stop using GUtilIdlePool
-- Slava Monich <slava.monich@jolla.com> Tue, 14 Apr 2020 12:36:54 +0300
libgbinder (1.0.40) unstable; urgency=low
* Support integration with non-glib event loops
-- Slava Monich <slava.monich@jolla.com> Thu, 09 Apr 2020 17:22:12 +0300
libgbinder (1.0.39) unstable; urgency=low
* Adapted to side-by-side linking
-- Slava Monich <slava.monich@jolla.com> Thu, 02 Apr 2020 18:07:16 +0300
libgbinder (1.0.38) unstable; urgency=low
* Allow to configure log level via environment

8
debian/control vendored
View File

@@ -2,7 +2,7 @@ Source: libgbinder
Section: libs
Priority: optional
Maintainer: Slava Monich <slava.monich@jolla.com>
Build-Depends: debhelper (>= 7), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.35)
Build-Depends: debhelper (>= 8.1.3), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.35)
Standards-Version: 3.8.4
Package: libgbinder
@@ -16,3 +16,9 @@ Section: libdevel
Architecture: any
Depends: libgbinder (= ${binary:Version}), ${misc:Depends}
Description: Development files for libgbinder
Package: libgbinder-tools
Section: utils
Architecture: any
Depends: libgbinder, ${misc:Depends}
Description: Binder command line utilities

View File

@@ -1,3 +0,0 @@
debian/tmp/usr/lib/libgbinder.so usr/lib
include/*.h usr/include/gbinder
build/libgbinder.pc usr/lib/pkgconfig

3
debian/libgbinder-dev.install.in vendored Normal file
View File

@@ -0,0 +1,3 @@
debian/tmp/@LIBDIR@/libgbinder.so @LIBDIR@
debian/tmp/@LIBDIR@/pkgconfig/libgbinder.pc @LIBDIR@/pkgconfig
debian/tmp/usr/include/* usr/include

1
debian/libgbinder-tools.install vendored Normal file
View File

@@ -0,0 +1 @@
debian/tmp/usr/bin/* usr/bin

View File

@@ -1 +0,0 @@
debian/tmp/usr/lib/libgbinder.so.* usr/lib

1
debian/libgbinder.install.in vendored Normal file
View File

@@ -0,0 +1 @@
debian/tmp/@LIBDIR@/libgbinder.so.* @LIBDIR@

11
debian/rules vendored
View File

@@ -4,8 +4,17 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
LIBDIR=usr/lib/$(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
override_dh_auto_build:
dh_auto_build -- LIBDIR=$(LIBDIR) release pkgconfig debian/libgbinder.install debian/libgbinder-dev.install
dh_auto_build -- -C test/binder-list release
dh_auto_build -- -C test/binder-ping release
override_dh_auto_install:
dh_auto_install -- install-dev
dh_auto_install -- LIBDIR=$(LIBDIR) install-dev
dh_auto_install -- -C test/binder-list
dh_auto_install -- -C test/binder-ping
%:
dh $@

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -37,6 +37,11 @@
G_BEGIN_DECLS
typedef struct gbinder_client_iface_info {
const char* iface;
guint32 last_code;
} GBinderClientIfaceInfo;
typedef
void
(*GBinderClientReplyFunc)(
@@ -50,6 +55,12 @@ gbinder_client_new(
GBinderRemoteObject* object,
const char* iface);
GBinderClient*
gbinder_client_new2(
GBinderRemoteObject* object,
const GBinderClientIfaceInfo* ifaces,
gsize count); /* since 1.0.42 */
GBinderClient*
gbinder_client_ref(
GBinderClient* client);
@@ -62,10 +73,20 @@ const char*
gbinder_client_interface(
GBinderClient* client); /* since 1.0.22 */
const char*
gbinder_client_interface2(
GBinderClient* client,
guint32 code); /* since 1.0.42 */
GBinderLocalRequest*
gbinder_client_new_request(
GBinderClient* client);
GBinderLocalRequest*
gbinder_client_new_request2(
GBinderClient* client,
guint32 code); /* since 1.0.42 */
GBinderRemoteReply*
gbinder_client_transact_sync_reply(
GBinderClient* client,

194
include/gbinder_eventloop.h Normal file
View File

@@ -0,0 +1,194 @@
/*
* 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_EVENTLOOP_H
#define GBINDER_EVENTLOOP_H
#include "gbinder_types.h"
G_BEGIN_DECLS
/* Since 1.0.40 */
typedef struct gbinder_eventloop_integration GBinderEventLoopIntegration;
typedef void (*GBinderEventLoopCallbackFunc)(gpointer data);
typedef struct gbinder_eventloop_timeout {
const GBinderEventLoopIntegration* eventloop;
} GBinderEventLoopTimeout;
typedef struct gbinder_eventloop_callback {
const GBinderEventLoopIntegration* eventloop;
} GBinderEventLoopCallback;
/**
* Main event loop integration. There is only one main event loop in the
* process (by definition).
*
* By default, GLib event loop is being used for callbacks and timeouts.
*
* It may be necessary to replace it with e.g. Qt event loop. Quite often
* Qt event loop is implemented by QEventDispatcherGlib which is sitting
* on top of GLib event and therefore works with the default implementation.
* But it won't work with e.g. QEventDispatcherUNIX.
*
* For Qt programs that use QEventDispatcherUNIX, it needs to be replaced
* with the one provided by libqbinder.
*/
typedef struct gbinder_eventloop_integration {
/**
* timeout_add
*
* Sets a function to be called at regular intervals (in milliseconds).
* If the function returns G_SOURCE_REMOVE, timeout is automatically
* destroyed (you must not call timeout_remove in this case). If the
* function returns G_SOURCE_CONTINUE, it will be called again after
* the same interval.
*/
GBinderEventLoopTimeout* (*timeout_add)(guint millis, GSourceFunc func,
gpointer data);
/**
* timeout_remove
*
* Removes a pending timeout and destroys it. The caller makes sure that
* argument is not NULL. Note that timeout is automatically destroyed if
* the callback function returns G_SOURCE_REMOVE.
*/
void (*timeout_remove)(GBinderEventLoopTimeout* timeout);
/**
* callback_new
*
* Creates a callback object. It returns you a reference, you must
* eventually pass the returned object to callback_unref to drop
* this reference.
*
* Note that it doesn't automatically schedule the callback. You
* must explicitly call callback_schedule to actually schedule it.
* The finalize function is invoked regardless of whether callback
* was cancelled or not.
*/
GBinderEventLoopCallback* (*callback_new)(GBinderEventLoopCallbackFunc fun,
gpointer data, GDestroyNotify finalize);
/**
* callback_ref
*
* Increments the reference count. That prevents the object from being
* deleted before you drop this reference. The caller makes sure that
* argument is not NULL.
*/
void (*callback_ref)(GBinderEventLoopCallback* cb);
/**
* callback_unref
*
* Decrements the reference count (drops the reference). When reference
* count reaches zero, the object gets deleted. The caller makes sure
* that argument is not NULL.
*
* Note that calling callback_schedule temporarily adds an internal
* reference until the callback is invoked or callback_cancel is called,
* whichever happens first.
*/
void (*callback_unref)(GBinderEventLoopCallback* cb);
/**
* callback_schedule
*
* Schedules the callback to be invoked in the main loop at some point
* in the future (but as soon as possible). The caller makes sure that
* argument is not NULL.
*
* This adds an internal reference to the GBinderEventLoopCallback object
* until the callback is invoked or callback_cancel is called, whichever
* happens first.
*/
void (*callback_schedule)(GBinderEventLoopCallback* cb);
/**
* callback_cancel
*
* Makes sure that callback won't be invoked (if it hasn't been
* invoked yet) and drops the internal reference. Does nothing
* if the callback has already been invoked. The caller makes sure that
* argument is not NULL.
*/
void (*callback_cancel)(GBinderEventLoopCallback* cb);
/**
* cleanup
*
* This function is called when event loop integration is being replaced
* with a different one, or libgbinder is being unloaded.
*/
void (*cleanup)(void);
/* Padding for future expansion */
void (*_reserved1)(void);
void (*_reserved2)(void);
void (*_reserved3)(void);
void (*_reserved4)(void);
void (*_reserved5)(void);
void (*_reserved6)(void);
void (*_reserved7)(void);
void (*_reserved8)(void);
void (*_reserved9)(void);
/*
* api_level will remain zero (and ignored) until we run out of
* the above placeholders. Hopefully, forever.
*/
int api_level;
} GBinderEventLoopIntegration;
/**
* gbinder_eventloop_set should be called before libgbinder creates any of
* its internal threads. And it must be done from the main thread.
*/
void
gbinder_eventloop_set(
const GBinderEventLoopIntegration* loop);
G_END_DECLS
#endif /* GBINDER_EVENTLOOP_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

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

View File

@@ -1,10 +1,10 @@
name=gbinder
libdir=/usr/lib
libdir=@libdir@
includedir=/usr/include
Name: libgbinder
Description: Binder client library
Version: [version]
Requires: glib-2.0 libglibutil
Version: @version@
Requires.private: glib-2.0 libglibutil
Libs: -L${libdir} -l${name}
Cflags: -I${includedir} -I${includedir}/${name}

View File

@@ -1,14 +1,16 @@
Name: libgbinder
Version: 1.0.38
Version: 1.1.0
Release: 0
Summary: Binder client library
Group: Development/Libraries
License: BSD
URL: https://github.com/mer-hybris/libgbinder
Source: %{name}-%{version}.tar.bz2
Requires: libglibutil >= 1.0.35
%define libglibutil_version 1.0.35
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libglibutil) >= 1.0.35
BuildRequires: pkgconfig(libglibutil) >= %{libglibutil_version}
Requires: libglibutil >= %{libglibutil_version}
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
@@ -27,11 +29,15 @@ This package contains the development library for %{name}.
%setup -q
%build
make KEEP_SYMBOLS=1 release pkgconfig
make LIBDIR=%{_libdir} KEEP_SYMBOLS=1 release pkgconfig
make -C test/binder-list release
make -C test/binder-ping release
%install
rm -rf %{buildroot}
make install-dev DESTDIR=%{buildroot}
make LIBDIR=%{_libdir} DESTDIR=%{buildroot} install-dev
make -C test/binder-list DESTDIR=%{buildroot} install
make -C test/binder-ping DESTDIR=%{buildroot} install
%check
make -C unit test
@@ -49,3 +55,16 @@ make -C unit test
%{_libdir}/pkgconfig/*.pc
%{_libdir}/%{name}.so
%{_includedir}/gbinder/*.h
# Tools
%package tools
Summary: Binder tools
%description tools
Binder command line utilities
%files tools
%defattr(-,root,root,-)
%{_bindir}/binder-list
%{_bindir}/binder-ping

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -42,42 +42,51 @@ gbinder_buffer_new(
GBinderDriver* driver,
void* data,
gsize size,
void** objects);
void** objects)
GBINDER_INTERNAL;
GBinderBuffer*
gbinder_buffer_new_with_parent(
GBinderBuffer* parent,
void* data,
gsize size);
gsize size)
GBINDER_INTERNAL;
GBinderDriver*
gbinder_buffer_driver(
GBinderBuffer* buf);
GBinderBuffer* buf)
GBINDER_INTERNAL;
GBinderBufferContents*
gbinder_buffer_contents(
GBinderBuffer* buf);
GBinderBuffer* buf)
GBINDER_INTERNAL;
gconstpointer
gbinder_buffer_data(
GBinderBuffer* buf,
gsize* size);
gsize* size)
GBINDER_INTERNAL;
const GBinderIo*
gbinder_buffer_io(
GBinderBuffer* buf);
GBinderBuffer* buf)
GBINDER_INTERNAL;
void**
gbinder_buffer_objects(
GBinderBuffer* buffer);
GBinderBuffer* buffer)
GBINDER_INTERNAL;
GBinderBufferContents*
gbinder_buffer_contents_ref(
GBinderBufferContents* contents);
GBinderBufferContents* contents)
GBINDER_INTERNAL;
void
gbinder_buffer_contents_unref(
GBinderBufferContents* contents);
GBinderBufferContents* contents)
GBINDER_INTERNAL;
#endif /* GBINDER_BUFFER_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -37,17 +37,20 @@
void
gbinder_cleanup_free(
GBinderCleanup* cleanup);
GBinderCleanup* cleanup)
GBINDER_INTERNAL;
void
gbinder_cleanup_reset(
GBinderCleanup* cleanup);
GBinderCleanup* cleanup)
GBINDER_INTERNAL;
GBinderCleanup*
gbinder_cleanup_add(
GBinderCleanup* cleanup,
GDestroyNotify destroy,
gpointer pointer);
gpointer pointer)
GBINDER_INTERNAL;
#endif /* GBINDER_CLEANUP_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -41,14 +41,22 @@
#include <gutil_macros.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
typedef struct gbinder_client_iface_range {
char* iface;
GBytes* rpc_header;
GBinderLocalRequest* basic_req;
guint32 last_code;
} GBinderClientIfaceRange;
typedef struct gbinder_client_priv {
GBinderClient pub;
guint32 refcount;
char* iface;
GBytes* rpc_header;
GBinderLocalRequest* basic_req;
GBinderClientIfaceRange* ranges;
guint nr;
} GBinderClientPriv;
typedef struct gbinder_client_tx {
@@ -65,19 +73,79 @@ static inline GBinderClientPriv* gbinder_client_cast(GBinderClient* client)
* Implementation
*==========================================================================*/
static
const GBinderClientIfaceRange*
gbinder_client_find_range(
GBinderClientPriv* priv,
guint32 code)
{
guint i;
for (i = 0; i < priv->nr; i++) {
const GBinderClientIfaceRange* r = priv->ranges + i;
if (r->last_code >= code) {
return r;
}
}
return NULL;
}
/*
* Generates basic request (without additional parameters) for the
* specified interface and pulls header data out of it. The basic
* request can be reused for those transactions which have no
* additional parameters. The header data are needed for building
* non-trivial requests.
*/
static
void
gbinder_client_init_range(
GBinderClientIfaceRange* r,
GBinderDriver* driver,
const GBinderClientIfaceInfo* info)
{
GBinderOutputData* hdr;
r->basic_req = gbinder_driver_local_request_new(driver, info->iface);
hdr = gbinder_local_request_data(r->basic_req);
r->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
r->iface = g_strdup(info->iface);
r->last_code = info->last_code;
}
static
int
gbinder_client_sort_ranges(
const void* p1,
const void* p2)
{
const GBinderClientIfaceRange* r1 = p1;
const GBinderClientIfaceRange* r2 = p2;
return (r1->last_code < r2->last_code) ? (-1) :
(r1->last_code > r2->last_code) ? 1 : 0;
}
static
void
gbinder_client_free(
GBinderClientPriv* priv)
{
GBinderClient* self = &priv->pub;
guint i;
gbinder_remote_object_unref(self->remote);
gbinder_local_request_unref(priv->basic_req);
g_free(priv->iface);
if (priv->rpc_header) {
g_bytes_unref(priv->rpc_header);
for (i = 0; i < priv->nr; i++) {
GBinderClientIfaceRange* r = priv->ranges + i;
gbinder_local_request_unref(r->basic_req);
g_free(r->iface);
if (r->rpc_header) {
g_bytes_unref(r->rpc_header);
}
}
g_free(priv->ranges);
gbinder_remote_object_unref(self->remote);
g_slice_free(GBinderClientPriv, priv);
}
@@ -115,9 +183,10 @@ gbinder_client_transact_destroy(
*==========================================================================*/
GBinderClient*
gbinder_client_new(
gbinder_client_new2(
GBinderRemoteObject* remote,
const char* iface)
const GBinderClientIfaceInfo* ifaces,
gsize count)
{
if (G_LIKELY(remote)) {
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
@@ -126,22 +195,22 @@ gbinder_client_new(
g_atomic_int_set(&priv->refcount, 1);
self->remote = gbinder_remote_object_ref(remote);
if (count > 0) {
gsize i;
/*
* Generate basic request (without additional parameters) and pull
* header data out of it. The basic request can be reused for those
* transactions which has no additional parameters. The header data
* are needed for building non-trivial requests.
*/
if (iface) {
GBinderOutputData* hdr;
priv->basic_req = gbinder_driver_local_request_new(driver, iface);
hdr = gbinder_local_request_data(priv->basic_req);
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
self->iface = priv->iface = g_strdup(iface);
priv->nr = count;
priv->ranges = g_new(GBinderClientIfaceRange, priv->nr);
for (i = 0; i < count; i++) {
gbinder_client_init_range(priv->ranges + i, driver, ifaces + i);
}
qsort(priv->ranges, count, sizeof(GBinderClientIfaceRange),
gbinder_client_sort_ranges);
} else {
priv->basic_req = gbinder_local_request_new
/* No interface info */
priv->nr = 1;
priv->ranges = g_new0(GBinderClientIfaceRange, 1);
priv->ranges[0].last_code = UINT_MAX;
priv->ranges[0].basic_req = gbinder_local_request_new
(gbinder_driver_io(driver), NULL);
}
return self;
@@ -149,6 +218,18 @@ gbinder_client_new(
return NULL;
}
GBinderClient*
gbinder_client_new(
GBinderRemoteObject* remote,
const char* iface)
{
GBinderClientIfaceInfo info;
info.iface = iface;
info.last_code = UINT_MAX;
return gbinder_client_new2(remote, &info, 1);
}
GBinderClient*
gbinder_client_ref(
GBinderClient* self)
@@ -180,7 +261,23 @@ const char*
gbinder_client_interface(
GBinderClient* self) /* since 1.0.22 */
{
return G_LIKELY(self) ? gbinder_client_cast(self)->iface : NULL;
return G_LIKELY(self) ? gbinder_client_cast(self)->ranges->iface : NULL;
}
const char*
gbinder_client_interface2(
GBinderClient* self,
guint32 code) /* since 1.0.42 */
{
if (G_LIKELY(self)) {
const GBinderClientIfaceRange* r =
gbinder_client_find_range(gbinder_client_cast(self), code);
if (r) {
return r->iface;
}
}
return NULL;
}
GBinderLocalRequest*
@@ -190,7 +287,27 @@ gbinder_client_new_request(
if (G_LIKELY(self)) {
GBinderClientPriv* priv = gbinder_client_cast(self);
const GBinderIo* io = gbinder_driver_io(self->remote->ipc->driver);
return gbinder_local_request_new(io, priv->rpc_header);
return gbinder_local_request_new(io, priv->ranges->rpc_header);
}
return NULL;
}
GBinderLocalRequest*
gbinder_client_new_request2(
GBinderClient* self,
guint32 code) /* since 1.0.42 */
{
if (G_LIKELY(self)) {
GBinderClientPriv* priv = gbinder_client_cast(self);
const GBinderClientIfaceRange* r = gbinder_client_find_range
(priv, code);
if (r) {
const GBinderIo* io = gbinder_driver_io(self->remote->ipc->driver);
return gbinder_local_request_new(io, r->rpc_header);
}
}
return NULL;
}
@@ -207,8 +324,13 @@ gbinder_client_transact_sync_reply(
if (G_LIKELY(!obj->dead)) {
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
if (r) {
req = r->basic_req;
}
}
return gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
code, req, status);
@@ -229,8 +351,13 @@ gbinder_client_transact_sync_oneway(
if (G_LIKELY(!obj->dead)) {
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
if (r) {
req = r->basic_req;
}
}
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
code, req);
@@ -263,8 +390,13 @@ gbinder_client_transact(
tx->user_data = user_data;
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
if (r) {
req = r->basic_req;
}
}
return gbinder_ipc_transact(obj->ipc, obj->handle, code,

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -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
@@ -38,7 +38,6 @@
#include "gbinder_types_p.h"
struct gbinder_client {
const char* iface;
GBinderRemoteObject* remote;
};

384
src/gbinder_config.c Normal file
View File

@@ -0,0 +1,384 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_config.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_log.h"
#include <gutil_strv.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/*
* The contents of the config file is queried from (at least) two places,
* and pretty much always this happens the same stack. Which means that
* we can avoid reading the same file twice if we delay dereferencing of
* GKeyFile until the next idle loop.
*/
static GKeyFile* gbinder_config_keyfile = NULL;
static GBinderEventLoopCallback* gbinder_config_autorelease = NULL;
static const char gbinder_config_suffix[] = ".conf";
static const char gbinder_config_default_file[] = "/etc/gbinder.conf";
static const char gbinder_config_default_dir[] = "/etc/gbinder.d";
const char* gbinder_config_file = gbinder_config_default_file;
const char* gbinder_config_dir = gbinder_config_default_dir;
/*
* Presets for particular API level can be chosen with ApiLevel
* setting, e.g.
*
* [General]
* ApiLevel=29
*
*/
static const char CONF_GENERAL[] = "General";
static const char CONG_API_LEVEL[] = "ApiLevel";
typedef struct gbinder_config_preset_entry {
const char* key;
const char* value;
} GBinderConfigPresetEntry;
typedef struct gbinder_config_preset_group {
const char* name;
const GBinderConfigPresetEntry* entries;
} GBinderConfigPresetGroup;
typedef struct gbinder_config_preset {
guint api_level;
const GBinderConfigPresetGroup* groups;
} GBinderConfigPreset;
/* API level 28 */
static const GBinderConfigPresetEntry gbinder_config_28_servicemanager[] = {
{ "/dev/binder", "aidl2" },
{ "/dev/vndbinder", "aidl2" },
{ NULL, NULL }
};
static const GBinderConfigPresetGroup gbinder_config_28[] = {
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_28_servicemanager },
{ NULL, NULL }
};
/* API level 29 */
static const GBinderConfigPresetEntry gbinder_config_29_protocol[] = {
{ "/dev/binder", "aidl2" },
{ "/dev/vndbinder", "aidl2" },
{ NULL, NULL }
};
#define gbinder_config_29_servicemanager gbinder_config_28_servicemanager
static const GBinderConfigPresetGroup gbinder_config_29[] = {
{ GBINDER_CONFIG_GROUP_PROTOCOL, gbinder_config_29_protocol },
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_29_servicemanager },
{ NULL, NULL }
};
/* Presets sorted by API level in descending order */
static const GBinderConfigPreset gbinder_config_presets[] = {
{ 29, gbinder_config_29 },
{ 28, gbinder_config_28 }
};
static
char**
gbinder_config_collect_files(
const char* path,
const char* suffix)
{
/*
* Returns sorted list of regular files in the directory,
* optionally having the specified suffix (e.g. ".conf").
* Returns NULL if nothing appropriate has been found.
*/
char** files = NULL;
if (path) {
GDir* dir = g_dir_open(path, 0, NULL);
if (dir) {
GPtrArray* list = g_ptr_array_new();
const gchar* name;
while ((name = g_dir_read_name(dir)) != NULL) {
if (g_str_has_suffix(name, suffix)) {
char* fullname = g_build_filename(path, name, NULL);
struct stat st;
if (!stat(fullname, &st) && S_ISREG(st.st_mode)) {
g_ptr_array_add(list, fullname);
} else {
g_free(fullname);
}
}
}
if (list->len > 0) {
g_ptr_array_add(list, NULL);
files = (char**) g_ptr_array_free(list, FALSE);
gutil_strv_sort(files, TRUE);
} else {
g_ptr_array_free(list, TRUE);
}
g_dir_close(dir);
}
}
return files;
}
static
GKeyFile*
gbinder_config_merge_keyfiles(
GKeyFile* dest,
GKeyFile* src)
{
gsize i, ngroups;
gchar** groups = g_key_file_get_groups(src, &ngroups);
for (i = 0; i < ngroups; i++) {
gsize k, nkeys;
const char* group = groups[i];
char** keys = g_key_file_get_keys(src, group, &nkeys, NULL);
for (k = 0; k < nkeys; k++) {
const char* key = keys[k];
char* value = g_key_file_get_value(src, group, key, NULL);
g_key_file_set_value(dest, group, key, value);
g_free(value);
}
g_strfreev(keys);
}
g_strfreev(groups);
return dest;
}
static
void
gbinder_config_apply_presets(
GKeyFile* config,
const GBinderConfigPreset* preset)
{
const GBinderConfigPresetGroup* g;
GDEBUG("Applying presets for API level %d", preset->api_level);
for (g = preset->groups; g->name; g++) {
const GBinderConfigPresetEntry* e;
for (e = g->entries; e->key; e++) {
if (!g_key_file_has_key(config, g->name, e->key, NULL)) {
g_key_file_set_value(config, g->name, e->key, e->value);
}
}
}
}
static
GKeyFile*
gbinder_config_load_files()
{
GError* error = NULL;
GKeyFile* out = NULL;
char** files = gbinder_config_collect_files(gbinder_config_dir,
gbinder_config_suffix);
if (gbinder_config_file &&
g_file_test(gbinder_config_file, G_FILE_TEST_EXISTS)) {
out = g_key_file_new();
if (g_key_file_load_from_file(out, gbinder_config_file,
G_KEY_FILE_NONE, &error)) {
GDEBUG("Loaded %s", gbinder_config_file);
} else {
GERR("Error loading %s: %s", gbinder_config_file, error->message);
g_error_free(error);
error = NULL;
gbinder_config_file = NULL; /* Don't retry */
g_key_file_unref(out);
out = NULL;
}
}
/* Files in the config directory overwrite /etc/gbinder.conf */
if (files) {
char** ptr;
GKeyFile* override = NULL;
for (ptr = files; *ptr; ptr++) {
const char* file = *ptr;
if (!override) {
override = g_key_file_new();
}
if (g_key_file_load_from_file(override, file,
G_KEY_FILE_NONE, &error)) {
GDEBUG("Loaded %s", file);
if (!out) {
out = override;
override = NULL;
} else {
out = gbinder_config_merge_keyfiles(out, override);
}
} else {
GERR("Error loading %s: %s", file, error->message);
g_error_free(error);
error = NULL;
}
}
g_strfreev(files);
if (override) {
g_key_file_unref(override);
}
}
if (out) {
/* Apply presets */
const int api_level = g_key_file_get_integer(out,
CONF_GENERAL, CONG_API_LEVEL, NULL);
if (api_level > 0) {
int i;
GDEBUG("API level %d", api_level);
for (i = 0; i < G_N_ELEMENTS(gbinder_config_presets); i++) {
const GBinderConfigPreset* preset = gbinder_config_presets + i;
if (api_level >= preset->api_level) {
gbinder_config_apply_presets(out, preset);
break;
}
}
}
}
return out;
}
static
void
gbinder_config_autorelease_cb(
gpointer data)
{
GASSERT(gbinder_config_keyfile == data);
gbinder_config_keyfile = NULL;
g_key_file_unref(data);
}
GKeyFile* /* autoreleased */
gbinder_config_get()
{
if (!gbinder_config_keyfile &&
(gbinder_config_file || gbinder_config_dir)) {
gbinder_config_keyfile = gbinder_config_load_files();
if (gbinder_config_keyfile) {
/* See the comment at the top of the file why this is needed */
gbinder_config_autorelease = gbinder_idle_callback_schedule_new
(gbinder_config_autorelease_cb, gbinder_config_keyfile, NULL);
}
}
return gbinder_config_keyfile;
}
/* Helper for loading config group in device = ident format */
GHashTable*
gbinder_config_load(
const char* group,
GBinderConfigValueMapFunc mapper)
{
GKeyFile* k = gbinder_config_get();
GHashTable* map = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
if (k) {
gsize n;
char** devs = g_key_file_get_keys(k, group, &n, NULL);
if (devs) {
gsize i;
for (i = 0; i < n; i++) {
char* dev = devs[i];
char* sval = g_key_file_get_value(k, group, dev, NULL);
gconstpointer val = mapper(sval);
if (val) {
g_hash_table_replace(map, dev, (gpointer) val);
} else {
GWARN("Unknown gbinder config '%s' for %s in group [%s]",
sval, dev, group);
g_free(dev);
}
g_free(sval);
}
/* Shallow delete (contents got stolen or freed) */
g_free(devs);
}
}
return map;
}
void
gbinder_config_exit()
{
if (gbinder_config_autorelease) {
gbinder_idle_callback_destroy(gbinder_config_autorelease);
gbinder_config_autorelease = NULL;
}
if (gbinder_config_keyfile) {
g_key_file_unref(gbinder_config_keyfile);
gbinder_config_keyfile = NULL;
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

78
src/gbinder_config.h Normal file
View File

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

View File

@@ -1,322 +0,0 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 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_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_servicepoll.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#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 {
GBinderServicePoll* poll;
char* name;
gulong handler_id;
guint notify_id;
} GBinderDefaultServiceManagerWatch;
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass;
typedef struct gbinder_defaultservicemanager {
GBinderServiceManager manager;
GBinderServicePoll* poll;
GHashTable* watch_table;
} GBinderDefaultServiceManager;
G_DEFINE_TYPE(GBinderDefaultServiceManager,
gbinder_defaultservicemanager,
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)
enum gbinder_defaultservicemanager_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);
}
static
void
gbinder_defaultservicemanager_watch_proc(
GBinderServicePoll* poll,
const char* name_added,
void* user_data)
{
GBinderDefaultServiceManagerWatch* watch = user_data;
if (!g_strcmp0(name_added, watch->name)) {
GBinderServiceManager* manager =
gbinder_servicepoll_manager(watch->poll);
if (watch->notify_id) {
g_source_remove(watch->notify_id);
watch->notify_id = 0;
}
gbinder_servicemanager_service_registered(manager, name_added);
}
}
static
gboolean
gbinder_defaultservicemanager_watch_notify(
gpointer user_data)
{
GBinderDefaultServiceManagerWatch* watch = user_data;
GBinderServiceManager* manager = gbinder_servicepoll_manager(watch->poll);
char* name = g_strdup(watch->name);
GASSERT(watch->notify_id);
watch->notify_id = 0;
gbinder_servicemanager_service_registered(manager, name);
g_free(name);
return G_SOURCE_REMOVE;
}
static
void
gbinder_defaultservicemanager_watch_free(
gpointer user_data)
{
GBinderDefaultServiceManagerWatch* watch = user_data;
if (watch->notify_id) {
g_source_remove(watch->notify_id);
}
gbinder_servicepoll_remove_handler(watch->poll, watch->handler_id);
gbinder_servicepoll_unref(watch->poll);
g_free(watch->name);
g_slice_free(GBinderDefaultServiceManagerWatch, watch);
}
static
GBinderDefaultServiceManagerWatch*
gbinder_defaultservicemanager_watch_new(
GBinderDefaultServiceManager* manager,
const char* name)
{
GBinderDefaultServiceManagerWatch* watch =
g_slice_new0(GBinderDefaultServiceManagerWatch);
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);
return watch;
}
static
GBinderLocalRequest*
gbinder_servicemanager_list_services_req(
GBinderServiceManager* self,
gint32 index)
{
return gbinder_local_request_append_int32
(gbinder_client_new_request(self->client), index);
}
static
char**
gbinder_defaultservicemanager_list(
GBinderServiceManager* self)
{
GPtrArray* list = g_ptr_array_new();
GBinderLocalRequest* req = gbinder_servicemanager_list_services_req(self,0);
GBinderRemoteReply* reply;
while ((reply = gbinder_client_transact_sync_reply(self->client,
LIST_SERVICES_TRANSACTION, req, NULL)) != NULL) {
char* service = gbinder_remote_reply_read_string16(reply);
gbinder_remote_reply_unref(reply);
if (service) {
g_ptr_array_add(list, service);
gbinder_local_request_unref(req);
req = gbinder_servicemanager_list_services_req(self, list->len);
} else {
break;
}
}
gbinder_local_request_unref(req);
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
static
GBinderRemoteObject*
gbinder_defaultservicemanager_get_service(
GBinderServiceManager* self,
const char* name,
int* status)
{
GBinderRemoteObject* obj;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
gbinder_local_request_append_string16(req, name);
reply = gbinder_client_transact_sync_reply(self->client,
CHECK_SERVICE_TRANSACTION, req, status);
obj = gbinder_remote_reply_read_object(reply);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return obj;
}
static
int
gbinder_defaultservicemanager_add_service(
GBinderServiceManager* self,
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,
ADD_SERVICE_TRANSACTION, req, &status);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return status;
}
static
GBINDER_SERVICEMANAGER_NAME_CHECK
gbinder_defaultservicemanager_check_name(
GBinderServiceManager* self,
const char* name)
{
return GBINDER_SERVICEMANAGER_NAME_OK;
}
static
gboolean
gbinder_defaultservicemanager_watch(
GBinderServiceManager* manager,
const char* name)
{
GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(manager);
GBinderDefaultServiceManagerWatch* watch =
gbinder_defaultservicemanager_watch_new(self, name);
g_hash_table_replace(self->watch_table, watch->name, watch);
if (gbinder_servicepoll_is_known_name(watch->poll, name)) {
watch->notify_id =
g_idle_add(gbinder_defaultservicemanager_watch_notify, watch);
}
return TRUE;
}
static
void
gbinder_defaultservicemanager_unwatch(
GBinderServiceManager* manager,
const char* name)
{
g_hash_table_remove(GBINDER_DEFAULTSERVICEMANAGER(manager)->watch_table,
name);
}
static
void
gbinder_defaultservicemanager_init(
GBinderDefaultServiceManager* self)
{
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, gbinder_defaultservicemanager_watch_free);
}
static
void
gbinder_defaultservicemanager_finalize(
GObject* object)
{
GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(object);
g_hash_table_destroy(self->watch_table);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
gbinder_defaultservicemanager_class_init(
GBinderDefaultServiceManagerClass* klass)
{
klass->iface = DEFAULTSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_BINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
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;
/* normalize_name is not needed */
klass->watch = gbinder_defaultservicemanager_watch;
klass->unwatch = gbinder_defaultservicemanager_unwatch;
G_OBJECT_CLASS(klass)->finalize = gbinder_defaultservicemanager_finalize;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -447,8 +447,14 @@ gbinder_driver_handle_transaction(
tx.code, tx.flags, &status);
break;
case GBINDER_LOCAL_TRANSACTION_SUPPORTED:
reply = gbinder_handler_transact(h, obj, req, tx.code, tx.flags,
&status);
/*
* NULL GBinderHandler means that this is a synchronous call
* executed on the main thread, meaning that we can call the
* local object directly.
*/
reply = h ? gbinder_handler_transact(h, obj, req, tx.code, tx.flags,
&status) : gbinder_local_object_handle_transaction(obj, req,
tx.code, tx.flags, &status);
break;
default:
GWARN("Unhandled transaction %s 0x%08x", iface, tx.code);
@@ -963,6 +969,7 @@ int
gbinder_driver_transact(
GBinderDriver* self,
GBinderObjectRegistry* reg,
GBinderHandler* handler,
guint32 handle,
guint32 code,
GBinderLocalRequest* req,
@@ -1019,7 +1026,7 @@ gbinder_driver_transact(
if (err < 0) {
txstatus = err;
} else {
txstatus = gbinder_driver_txstatus(self, reg, NULL, &rb, reply);
txstatus = gbinder_driver_txstatus(self, reg, handler, &rb, reply);
}
}
@@ -1028,14 +1035,14 @@ gbinder_driver_transact(
GASSERT(write.consumed == write.size || txstatus > 0);
/* Loop until we have handled all the incoming commands */
gbinder_driver_handle_commands(self, reg, NULL, &rb);
gbinder_driver_handle_commands(self, reg, handler, &rb);
while (rb.buf.consumed) {
int err = gbinder_driver_write_read(self, NULL, &rb.buf);
if (err < 0) {
txstatus = err;
break;
} else {
gbinder_driver_handle_commands(self, reg, NULL, &rb);
gbinder_driver_handle_commands(self, reg, handler, &rb);
}
}
}
@@ -1058,7 +1065,7 @@ gbinder_driver_ping(
gbinder_local_request_init_writer(req, &writer);
protocol->write_ping(&writer);
ret = gbinder_driver_transact(self, reg, handle, protocol->ping_tx,
ret = gbinder_driver_transact(self, reg, NULL, handle, protocol->ping_tx,
req, reply);
gbinder_local_request_unref(req);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -40,107 +40,129 @@ struct pollfd;
GBinderDriver*
gbinder_driver_new(
const char* dev,
const GBinderRpcProtocol* protocol);
const GBinderRpcProtocol* protocol)
GBINDER_INTERNAL;
GBinderDriver*
gbinder_driver_ref(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
void
gbinder_driver_unref(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
int
gbinder_driver_fd(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
int
gbinder_driver_poll(
GBinderDriver* driver,
struct pollfd* pollfd);
struct pollfd* pollfd)
GBINDER_INTERNAL;
const char*
gbinder_driver_dev(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
const GBinderIo*
gbinder_driver_io(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
gboolean
gbinder_driver_request_death_notification(
GBinderDriver* driver,
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
gboolean
gbinder_driver_clear_death_notification(
GBinderDriver* driver,
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
gboolean
gbinder_driver_increfs(
GBinderDriver* driver,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
gboolean
gbinder_driver_decrefs(
GBinderDriver* driver,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
gboolean
gbinder_driver_acquire(
GBinderDriver* driver,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
gboolean
gbinder_driver_release(
GBinderDriver* driver,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
void
gbinder_driver_close_fds(
GBinderDriver* self,
void** objects,
const void* end);
const void* end)
GBINDER_INTERNAL;
void
gbinder_driver_free_buffer(
GBinderDriver* driver,
void* buffer);
void* buffer)
GBINDER_INTERNAL;
gboolean
gbinder_driver_enter_looper(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
gboolean
gbinder_driver_exit_looper(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
int
gbinder_driver_read(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
GBinderHandler* handler);
GBinderHandler* handler)
GBINDER_INTERNAL;
int
gbinder_driver_transact(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
GBinderHandler* handler,
guint32 handle,
guint32 code,
GBinderLocalRequest* request,
GBinderRemoteReply* reply);
GBinderRemoteReply* reply)
GBINDER_INTERNAL;
int
gbinder_driver_ping(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_driver_local_request_new(
GBinderDriver* self,
const char* iface);
const char* iface)
GBINDER_INTERNAL;
#endif /* GBINDER_DRIVER_H */

347
src/gbinder_eventloop.c Normal file
View File

@@ -0,0 +1,347 @@
/*
* 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_eventloop_p.h"
#include <gutil_macros.h>
#define GBINDER_DEFAULT_EVENTLOOP (&gbinder_eventloop_glib)
static const GBinderEventLoopIntegration gbinder_eventloop_glib;
/*==========================================================================*
* GLib event loop integration
*==========================================================================*/
typedef struct gbinder_eventloop_glib_timeout {
GBinderEventLoopTimeout timeout;
guint id;
GSourceFunc func;
gpointer data;
} GBinderEventLoopTimeoutGLib;
typedef struct gbinder_eventloop_glib_callback {
GSource source;
GBinderEventLoopCallback callback;
} GBinderEventLoopCallbackGLib;
static
inline
GBinderEventLoopTimeoutGLib*
gbinder_eventloop_glib_timeout_cast(
GBinderEventLoopTimeout* timeout)
{
return G_CAST(timeout,GBinderEventLoopTimeoutGLib,timeout);
}
static
inline
GSource*
gbinder_eventloop_glib_callback_source(
GBinderEventLoopCallback* callback)
{
return &(G_CAST(callback,GBinderEventLoopCallbackGLib,callback)->source);
}
static
gboolean
gbinder_eventloop_glib_timeout_callback(
gpointer data)
{
GBinderEventLoopTimeoutGLib* timeout = data;
return timeout->func(timeout->data);
}
static
void
gbinder_eventloop_glib_timeout_finalize(
gpointer data)
{
g_slice_free1(sizeof(GBinderEventLoopTimeoutGLib), data);
}
static
GBinderEventLoopTimeout*
gbinder_eventloop_glib_timeout_add(
guint interval,
GSourceFunc func,
gpointer data)
{
GBinderEventLoopTimeoutGLib* impl =
g_slice_new(GBinderEventLoopTimeoutGLib);
impl->timeout.eventloop = &gbinder_eventloop_glib;
impl->func = func;
impl->data = data;
impl->id = g_timeout_add_full(G_PRIORITY_DEFAULT, interval,
gbinder_eventloop_glib_timeout_callback, impl,
gbinder_eventloop_glib_timeout_finalize);
return &impl->timeout;
}
static
void
gbinder_eventloop_glib_timeout_remove(
GBinderEventLoopTimeout* timeout)
{
g_source_remove(gbinder_eventloop_glib_timeout_cast(timeout)->id);
}
static
gboolean
gbinder_eventloop_glib_callback_prepare(
GSource* source,
gint* timeout)
{
*timeout = 0;
return TRUE;
}
static
gboolean
gbinder_eventloop_glib_callback_check(
GSource* source)
{
return TRUE;
}
static
gboolean
gbinder_eventloop_glib_callback_dispatch(
GSource* source,
GSourceFunc callback,
gpointer user_data)
{
((GBinderEventLoopCallbackFunc)callback)(user_data);
return G_SOURCE_REMOVE;
}
static
GBinderEventLoopCallback*
gbinder_eventloop_glib_callback_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify finalize)
{
static GSourceFuncs callback_funcs = {
gbinder_eventloop_glib_callback_prepare,
gbinder_eventloop_glib_callback_check,
gbinder_eventloop_glib_callback_dispatch
};
GBinderEventLoopCallbackGLib* impl = (GBinderEventLoopCallbackGLib*)
g_source_new(&callback_funcs, sizeof(GBinderEventLoopCallbackGLib));
impl->callback.eventloop = &gbinder_eventloop_glib;
g_source_set_callback(&impl->source, (GSourceFunc) func, data, finalize);
return &impl->callback;
}
static
void
gbinder_eventloop_glib_callback_ref(
GBinderEventLoopCallback* cb)
{
g_source_ref(gbinder_eventloop_glib_callback_source(cb));
}
static
void
gbinder_eventloop_glib_callback_unref(
GBinderEventLoopCallback* cb)
{
g_source_unref(gbinder_eventloop_glib_callback_source(cb));
}
static
void
gbinder_eventloop_glib_callback_schedule(
GBinderEventLoopCallback* cb)
{
static GMainContext* context = NULL;
if (!context) context = g_main_context_default();
g_source_attach(gbinder_eventloop_glib_callback_source(cb), context);
}
static
void
gbinder_eventloop_glib_callback_cancel(
GBinderEventLoopCallback* cb)
{
g_source_destroy(gbinder_eventloop_glib_callback_source(cb));
}
static
void
gbinder_eventloop_glib_cleanup(
void)
{
}
static const GBinderEventLoopIntegration gbinder_eventloop_glib = {
gbinder_eventloop_glib_timeout_add,
gbinder_eventloop_glib_timeout_remove,
gbinder_eventloop_glib_callback_new,
gbinder_eventloop_glib_callback_ref,
gbinder_eventloop_glib_callback_unref,
gbinder_eventloop_glib_callback_schedule,
gbinder_eventloop_glib_callback_cancel,
gbinder_eventloop_glib_cleanup
};
/*==========================================================================*
* Internal interface
*==========================================================================*/
static const GBinderEventLoopIntegration* gbinder_eventloop =
GBINDER_DEFAULT_EVENTLOOP;
GBinderEventLoopTimeout*
gbinder_timeout_add(
guint interval,
GSourceFunc function,
gpointer data)
{
return gbinder_eventloop->timeout_add(interval, function, data);
}
GBinderEventLoopTimeout*
gbinder_idle_add(
GSourceFunc function,
gpointer data)
{
return gbinder_eventloop->timeout_add(0, function, data);
}
void
gbinder_timeout_remove(
GBinderEventLoopTimeout* timeout)
{
if (timeout) {
timeout->eventloop->timeout_remove(timeout);
}
}
GBinderEventLoopCallback*
gbinder_idle_callback_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify finalize)
{
return gbinder_eventloop->callback_new(func, data, finalize);
}
GBinderEventLoopCallback*
gbinder_idle_callback_schedule_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify finalize)
{
GBinderEventLoopCallback* cb =
gbinder_eventloop->callback_new(func, data, finalize);
gbinder_idle_callback_schedule(cb);
return cb;
}
GBinderEventLoopCallback*
gbinder_idle_callback_ref(
GBinderEventLoopCallback* cb)
{
if (cb) {
cb->eventloop->callback_ref(cb);
return cb;
}
return NULL;
}
void
gbinder_idle_callback_unref(
GBinderEventLoopCallback* cb)
{
if (cb) {
cb->eventloop->callback_unref(cb);
}
}
void
gbinder_idle_callback_schedule(
GBinderEventLoopCallback* cb)
{
if (cb) {
cb->eventloop->callback_schedule(cb);
}
}
void
gbinder_idle_callback_cancel(
GBinderEventLoopCallback* cb)
{
if (cb) {
cb->eventloop->callback_cancel(cb);
}
}
void
gbinder_idle_callback_destroy(
GBinderEventLoopCallback* cb)
{
if (cb) {
const GBinderEventLoopIntegration* eventloop = cb->eventloop;
eventloop->callback_cancel(cb);
eventloop->callback_unref(cb);
}
}
void
gbinder_eventloop_set(
const GBinderEventLoopIntegration* loop)
{
if (!loop) loop = GBINDER_DEFAULT_EVENTLOOP;
if (gbinder_eventloop != loop) {
const GBinderEventLoopIntegration* prev = gbinder_eventloop;
gbinder_eventloop = loop;
prev->cleanup();
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

104
src/gbinder_eventloop_p.h Normal file
View File

@@ -0,0 +1,104 @@
/*
* 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_EVENTLOOP_PRIVATE_H
#define GBINDER_EVENTLOOP_PRIVATE_H
#include "gbinder_types_p.h"
#include "gbinder_eventloop.h"
GBinderEventLoopTimeout*
gbinder_timeout_add(
guint millis,
GSourceFunc func,
gpointer data)
GBINDER_INTERNAL;
GBinderEventLoopTimeout*
gbinder_idle_add(
GSourceFunc func,
gpointer data)
GBINDER_INTERNAL;
void
gbinder_timeout_remove(
GBinderEventLoopTimeout* timeout)
GBINDER_INTERNAL;
GBinderEventLoopCallback*
gbinder_idle_callback_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
GBINDER_INTERNAL;
GBinderEventLoopCallback*
gbinder_idle_callback_schedule_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
GBINDER_INTERNAL;
GBinderEventLoopCallback*
gbinder_idle_callback_ref(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_unref(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_schedule(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_cancel(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_destroy(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
#endif /* GBINDER_EVENTLOOP_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -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

View File

@@ -181,8 +181,8 @@ struct gbinder_io {
int (*write_read)(int fd, GBinderIoBuf* write, GBinderIoBuf* read);
};
extern const GBinderIo gbinder_io_32;
extern const GBinderIo gbinder_io_64;
extern const GBinderIo gbinder_io_32 GBINDER_INTERNAL;
extern const GBinderIo gbinder_io_64 GBINDER_INTERNAL;
#endif /* GBINDER_IO_H */

View File

@@ -36,6 +36,7 @@
#include "gbinder_driver.h"
#include "gbinder_handler.h"
#include "gbinder_io.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_object_registry.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply.h"
@@ -43,10 +44,10 @@
#include "gbinder_remote_object_p.h"
#include "gbinder_remote_reply_p.h"
#include "gbinder_remote_request_p.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_writer.h"
#include "gbinder_log.h"
#include <gutil_idlepool.h>
#include <gutil_macros.h>
#include <unistd.h>
@@ -60,7 +61,6 @@ struct gbinder_ipc_priv {
GBinderIpc* self;
GThreadPool* tx_pool;
GHashTable* tx_table;
GMainContext* context;
char* key;
GBinderObjectRegistry object_registry;
@@ -163,6 +163,11 @@ struct gbinder_ipc_looper {
int txfd[2];
};
typedef struct gbinder_ipc_tx_handler {
int pipefd[2];
int txfd[2];
} GBinderIpcTxHandler;
typedef struct gbinder_ipc_tx_priv GBinderIpcTxPriv;
typedef
@@ -175,7 +180,7 @@ typedef struct gbinder_ipc_tx_priv {
GBinderIpcTxPrivFunc fn_exec;
GBinderIpcTxPrivFunc fn_done;
GBinderIpcTxPrivFunc fn_free;
GSource* completion;
GBinderEventLoopCallback* completion;
} GBinderIpcTxPriv;
typedef struct gbinder_ipc_tx_internal {
@@ -205,6 +210,40 @@ GBinderIpcLooper*
gbinder_ipc_looper_new(
GBinderIpc* ipc);
/*==========================================================================*
* Utilities
*==========================================================================*/
static
gboolean
gbinder_ipc_wait(
int fd_wakeup,
int fd_read,
guint8* out)
{
struct pollfd fds[2];
memset(fds, 0, sizeof(fds));
fds[0].fd = fd_wakeup;
fds[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
fds[1].fd = fd_read;
fds[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
if (poll(fds, 2, -1) < 0) {
GWARN("Transaction pipe polling error: %s", strerror(errno));
} else if (fds[1].revents & POLLIN) {
const ssize_t n = read(fds[1].fd, out, 1);
if (n == 1) {
return TRUE;
} else if (n < 0) {
GWARN("Transaction pipe read error: %s", strerror(errno));
} else {
GWARN("Nothing was read from the transaction pipe");
}
}
return FALSE;
}
/*==========================================================================*
* GBinderIpcLooperTx
*==========================================================================*/
@@ -406,7 +445,7 @@ gbinder_ipc_looper_unref(
}
static
gboolean
void
gbinder_ipc_looper_tx_handle(
gpointer data)
{
@@ -480,7 +519,6 @@ gbinder_ipc_looper_tx_handle(
if (write(tx->pipefd[1], &done, sizeof(done)) <= 0) {
GWARN("Failed to wake up the looper");
}
return G_SOURCE_REMOVE;
}
static
@@ -591,80 +629,60 @@ gbinder_ipc_looper_transact(
GBinderIpcLooperTx* tx = gbinder_ipc_looper_tx_new(obj, code, flags,
req, looper->txfd);
GBinderIpcPriv* priv = ipc->priv;
struct pollfd fds[2];
guint8 done = 0;
GSource* source = g_idle_source_new();
gboolean was_blocked = FALSE;
/* Let GBinderLocalObject handle the transaction on the main thread */
g_source_set_callback(source, gbinder_ipc_looper_tx_handle,
gbinder_ipc_looper_tx_ref(tx), gbinder_ipc_looper_tx_done);
g_source_attach(source, priv->context);
GBinderEventLoopCallback* callback =
gbinder_idle_callback_schedule_new(gbinder_ipc_looper_tx_handle,
gbinder_ipc_looper_tx_ref(tx), gbinder_ipc_looper_tx_done);
/* Wait for either transaction completion or looper shutdown */
memset(fds, 0, sizeof(fds));
fds[0].fd = looper->pipefd[0];
fds[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
fds[1].fd = tx->pipefd[0];
fds[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
poll(fds, 2, -1);
if (gbinder_ipc_wait(looper->pipefd[0], tx->pipefd[0], &done) &&
done == TX_BLOCKED) {
/*
* We are going to block this looper for potentially
* significant period of time. Start new looper to
* accept normal incoming requests and terminate this
* one when we are done with this transaction.
*
* For the duration of the transaction, this looper is
* moved to the blocked_loopers list.
*/
GBinderIpcPriv* priv = looper->ipc->priv;
GBinderIpcLooper* new_looper = NULL;
if ((fds[1].revents & POLLIN) &&
read(fds[1].fd, &done, sizeof(done)) == 1) {
/* Normal completion */
if (done == TX_BLOCKED) {
/*
* We are going to block this looper for potentially
* significant period of time. Start new looper to
* accept normal incoming requests and terminate this
* one when we are done with this transaction.
*
* For the duration of the transaction, this looper is
* moved to the blocked_loopers list.
*/
GBinderIpcPriv* priv = looper->ipc->priv;
GBinderIpcLooper* new_looper = NULL;
/* Lock */
g_mutex_lock(&priv->looper_mutex);
if (gbinder_ipc_looper_remove_primary(looper)) {
GDEBUG("Primary looper %s is blocked", looper->name);
looper->next = priv->blocked_loopers;
priv->blocked_loopers = looper;
was_blocked = TRUE;
/* Lock */
g_mutex_lock(&priv->looper_mutex);
if (gbinder_ipc_looper_remove_primary(looper)) {
GDEBUG("Primary looper %s is blocked", looper->name);
looper->next = priv->blocked_loopers;
priv->blocked_loopers = looper;
was_blocked = TRUE;
/* If there's no more primary loopers left, create one */
if (!priv->primary_loopers) {
new_looper = gbinder_ipc_looper_new(ipc);
if (new_looper) {
/* Will unref it after it gets started */
gbinder_ipc_looper_ref(new_looper);
priv->primary_loopers = new_looper;
}
/* If there's no more primary loopers left, create one */
if (!priv->primary_loopers) {
new_looper = gbinder_ipc_looper_new(ipc);
if (new_looper) {
/* Will unref it after it gets started */
gbinder_ipc_looper_ref(new_looper);
priv->primary_loopers = new_looper;
}
}
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
}
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
if (new_looper) {
/* Wait until it gets started */
gbinder_ipc_looper_start(new_looper);
gbinder_ipc_looper_unref(new_looper);
}
if (new_looper) {
/* Wait until it gets started */
gbinder_ipc_looper_start(new_looper);
gbinder_ipc_looper_unref(new_looper);
}
/* Block until asynchronous transaction gets completed. */
done = 0;
memset(fds, 0, sizeof(fds));
fds[0].fd = looper->pipefd[0];
fds[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
fds[1].fd = tx->pipefd[0];
fds[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
poll(fds, 2, -1);
if ((fds[1].revents & POLLIN) &&
read(fds[1].fd, &done, sizeof(done)) == 1) {
GDEBUG("Looper %s is released", looper->name);
GASSERT(done == TX_DONE);
}
/* Block until asynchronous transaction gets completed. */
done = 0;
if (gbinder_ipc_wait(looper->pipefd[0], tx->pipefd[0], &done)) {
GDEBUG("Looper %s is released", looper->name);
GASSERT(done == TX_DONE);
}
}
@@ -672,21 +690,19 @@ gbinder_ipc_looper_transact(
GASSERT(done == TX_DONE);
reply = gbinder_local_reply_ref(tx->reply);
status = tx->status;
if (!gbinder_ipc_looper_tx_unref(tx, TRUE)) {
/*
* This wasn't the last references meaning that
* gbinder_ipc_looper_tx_free() will close the
* descriptors and we will have to create a new
* pipe for the next transaction.
*/
looper->txfd[0] = looper->txfd[1] = -1;
}
} else {
gbinder_ipc_looper_tx_unref(tx, FALSE);
}
g_source_destroy(source);
g_source_unref(source);
if (!gbinder_ipc_looper_tx_unref(tx, TRUE)) {
/*
* This wasn't the last reference meaning that
* gbinder_ipc_looper_tx_free() will close the
* descriptors and we will have to create a new
* pipe for the next transaction.
*/
looper->txfd[0] = looper->txfd[1] = -1;
}
gbinder_idle_callback_destroy(callback);
if (was_blocked) {
guint n;
@@ -922,6 +938,117 @@ gbinder_ipc_looper_join(
looper->ipc = NULL;
}
/*==========================================================================*
* GBinderIpcTxHandler
*
* It's needed to handle the following scenario:
*
* 1. Asynchronous call is made. The actual transaction is performed on
* gbinder_ipc_tx_proc thread.
* 2. While we were are waiting for completion of our transaction, we
* receive a valid incoming transation.
* 3. This transaction is handled by gbinder_ipc_tx_handler_transact.
*
* This seems to be quite a rare scenario, so we allocate a new
* GBinderIpcTxHandler (and new pipes) for each such transaction,
* to keep things as simple as possible.
*
*==========================================================================*/
static
GBinderIpcTxHandler*
gbinder_ipc_tx_handler_new(
void)
{
GBinderIpcTxHandler* h = g_slice_new0(GBinderIpcTxHandler);
/* Note: pipe() calls can actually fail */
if (!pipe(h->txfd)) {
if (!pipe(h->pipefd)) {
return h;
} else {
GERR("Failed to create a tx pipe: %s", strerror(errno));
}
close(h->txfd[0]);
close(h->txfd[1]);
} else {
GERR("Failed to create a tx pipe: %s", strerror(errno));
}
g_slice_free(GBinderIpcTxHandler, h);
return NULL;
}
static
void
gbinder_ipc_tx_handler_free(
GBinderIpcTxHandler* h)
{
close(h->pipefd[0]);
close(h->pipefd[1]);
if (h->txfd[0] >= 0) {
close(h->txfd[0]);
close(h->txfd[1]);
}
g_slice_free(GBinderIpcTxHandler, h);
}
static
GBinderLocalReply*
gbinder_ipc_tx_handler_transact(
GBinderHandler* handler,
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* result)
{
GBinderIpcTxHandler* h = gbinder_ipc_tx_handler_new();
GBinderLocalReply* reply = NULL;
int status = -EFAULT;
if (h) {
GBinderIpcLooperTx* tx = gbinder_ipc_looper_tx_new(obj, code, flags,
req, h->txfd);
guint8 done = 0;
/* Handle transaction on the main thread */
GBinderEventLoopCallback* callback =
gbinder_idle_callback_schedule_new(gbinder_ipc_looper_tx_handle,
gbinder_ipc_looper_tx_ref(tx), gbinder_ipc_looper_tx_done);
/* Wait for completion */
if (gbinder_ipc_wait(h->pipefd[0], tx->pipefd[0], &done) &&
done == TX_BLOCKED) {
/* Block until asynchronous transaction gets completed. */
done = 0;
if (gbinder_ipc_wait(h->pipefd[0], tx->pipefd[0], &done)) {
GASSERT(done == TX_DONE);
}
}
if (done) {
GASSERT(done == TX_DONE);
reply = gbinder_local_reply_ref(tx->reply);
status = tx->status;
}
if (!gbinder_ipc_looper_tx_unref(tx, TRUE)) {
/*
* This wasn't the last references meaning that
* gbinder_ipc_looper_tx_free() will close the
* descriptors and we will have to create a new
* pipe for the next transaction.
*/
h->txfd[0] = h->txfd[1] = -1;
}
gbinder_idle_callback_destroy(callback);
gbinder_ipc_tx_handler_free(h);
}
*result = status;
return reply;
}
/*==========================================================================*
* GBinderObjectRegistry
*==========================================================================*/
@@ -1197,7 +1324,7 @@ gbinder_ipc_tx_free(
GBinderIpc* self = pub->ipc;
GBinderIpcPriv* priv = self->priv;
g_source_unref(tx->completion);
gbinder_idle_callback_unref(tx->completion);
g_hash_table_remove(priv->tx_table, GINT_TO_POINTER(pub->id));
tx->fn_free(tx);
@@ -1206,7 +1333,7 @@ gbinder_ipc_tx_free(
}
static
gboolean
void
gbinder_ipc_tx_done(
gpointer data)
{
@@ -1216,7 +1343,6 @@ gbinder_ipc_tx_done(
if (!pub->cancelled) {
tx->fn_done(tx);
}
return G_SOURCE_REMOVE;
}
static
@@ -1247,8 +1373,7 @@ gbinder_ipc_tx_priv_init(
priv->fn_exec = fn_exec;
priv->fn_done = fn_done;
priv->fn_free = fn_free;
priv->completion = g_idle_source_new();
g_source_set_callback(priv->completion, gbinder_ipc_tx_done, priv,
priv->completion = gbinder_idle_callback_new(gbinder_ipc_tx_done, priv,
gbinder_ipc_tx_free);
}
@@ -1295,19 +1420,23 @@ void
gbinder_ipc_tx_internal_exec(
GBinderIpcTxPriv* priv)
{
static const GBinderHandlerFunctions handler_fn = {
gbinder_ipc_tx_handler_transact
};
GBinderIpcTxInternal* tx = gbinder_ipc_tx_internal_cast(priv);
GBinderIpcTx* pub = &priv->pub;
GBinderIpc* self = pub->ipc;
GBinderObjectRegistry* reg = &self->priv->object_registry;
GBinderHandler handler = { &handler_fn };
/* Perform synchronous transaction */
if (tx->flags & GBINDER_TX_FLAG_ONEWAY) {
tx->status = gbinder_driver_transact(self->driver, reg, tx->handle,
tx->code, tx->req, NULL);
tx->status = gbinder_driver_transact(self->driver, reg, &handler,
tx->handle, tx->code, tx->req, NULL);
} else {
tx->reply = gbinder_remote_reply_new(&self->priv->object_registry);
tx->status = gbinder_driver_transact(self->driver, reg, tx->handle,
tx->code, tx->req, tx->reply);
tx->status = gbinder_driver_transact(self->driver, reg, &handler,
tx->handle, tx->code, tx->req, tx->reply);
if (tx->status != GBINDER_STATUS_OK &&
gbinder_remote_reply_is_empty(tx->reply)) {
/* Drop useless reply */
@@ -1425,8 +1554,6 @@ gbinder_ipc_tx_proc(
gpointer object)
{
GBinderIpcTxPriv* tx = data;
GBinderIpc* self = GBINDER_IPC(object);
GBinderIpcPriv* priv = self->priv;
if (!tx->pub.cancelled) {
tx->fn_exec(tx);
@@ -1435,7 +1562,7 @@ gbinder_ipc_tx_proc(
}
/* The result is handled by the main thread */
g_source_attach(tx->completion, priv->context);
gbinder_idle_callback_schedule(tx->completion);
}
/*==========================================================================*
@@ -1444,12 +1571,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) {
@@ -1521,8 +1650,8 @@ gbinder_ipc_transact_sync_reply(
GBinderIpcPriv* priv = self->priv;
GBinderObjectRegistry* reg = &priv->object_registry;
GBinderRemoteReply* reply = gbinder_remote_reply_new(reg);
int ret = gbinder_driver_transact(self->driver, reg, handle, code,
req, reply);
int ret = gbinder_driver_transact(self->driver, reg, NULL, handle,
code, req, reply);
if (status) *status = ret;
if (ret == GBINDER_STATUS_OK || !gbinder_remote_reply_is_empty(reply)) {
@@ -1547,7 +1676,7 @@ gbinder_ipc_transact_sync_oneway(
GBinderIpcPriv* priv = self->priv;
return gbinder_driver_transact(self->driver, &priv->object_registry,
handle, code, req, NULL);
NULL, handle, code, req, NULL);
} else {
return (-EINVAL);
}
@@ -1641,14 +1770,12 @@ gbinder_ipc_init(
g_mutex_init(&priv->looper_mutex);
g_mutex_init(&priv->local_objects_mutex);
g_mutex_init(&priv->remote_objects_mutex);
priv->context = g_main_context_default();
priv->tx_table = g_hash_table_new(g_direct_hash, g_direct_equal);
priv->tx_pool = g_thread_pool_new(gbinder_ipc_tx_proc, self,
GBINDER_IPC_MAX_TX_THREADS, FALSE, NULL);
priv->object_registry.f = &object_registry_functions;
priv->self = self;
self->priv = priv;
self->pool = gutil_idle_pool_new();
}
static
@@ -1729,7 +1856,6 @@ gbinder_ipc_finalize(
}
GASSERT(!g_hash_table_size(priv->tx_table));
g_hash_table_unref(priv->tx_table);
gutil_idle_pool_unref(self->pool);
gbinder_driver_unref(self->driver);
g_free(priv->key);
G_OBJECT_CLASS(gbinder_ipc_parent_class)->finalize(object);
@@ -1795,11 +1921,9 @@ gbinder_ipc_exit()
}
for (k = tx_keys; k; k = k->next) {
GBinderIpcTxPriv* tx = g_hash_table_lookup(priv->tx_table, k->data);
GSource* source = g_source_ref(tx->completion);
GVERBOSE_("tx %lu", tx->pub.id);
g_source_destroy(source);
g_source_unref(source);
gbinder_idle_callback_cancel(tx->completion);
}
/* The above loop must destroy all uncompleted transactions */
@@ -1830,6 +1954,7 @@ gbinder_ipc_exit()
g_slist_free_full(local_objs, g_object_unref);
}
g_slist_free_full(ipcs, g_object_unref);
gbinder_eventloop_set(NULL);
}
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -42,7 +42,6 @@ struct gbinder_ipc {
GObject object;
GBinderIpcPriv* priv;
GBinderDriver* driver;
GUtilIdlePool* pool;
const char* dev;
};
@@ -68,69 +67,67 @@ void
int status,
void* user_data);
G_GNUC_INTERNAL
GBinderIpc*
gbinder_ipc_new(
const char* dev,
const GBinderRpcProtocol* protocol);
const char* dev)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
GBinderIpc*
gbinder_ipc_ref(
GBinderIpc* ipc);
GBinderIpc* ipc)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
void
gbinder_ipc_unref(
GBinderIpc* ipc);
GBinderIpc* ipc)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
void
gbinder_ipc_looper_check(
GBinderIpc* ipc);
GBinderIpc* ipc)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
GBinderObjectRegistry*
gbinder_ipc_object_registry(
GBinderIpc* ipc);
GBinderIpc* ipc)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
void
gbinder_ipc_register_local_object(
GBinderIpc* ipc,
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
GBinderRemoteObject*
gbinder_ipc_get_remote_object(
GBinderIpc* ipc,
guint32 handle,
gboolean maybe_dead);
gboolean maybe_dead)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
void
gbinder_ipc_invalidate_remote_handle(
GBinderIpc* ipc,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
GBinderRemoteReply*
gbinder_ipc_transact_sync_reply(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req,
int* status);
int* status)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
int
gbinder_ipc_transact_sync_oneway(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req);
GBinderLocalRequest* req)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
gulong
gbinder_ipc_transact(
GBinderIpc* ipc,
@@ -140,43 +137,44 @@ gbinder_ipc_transact(
GBinderLocalRequest* req,
GBinderIpcReplyFunc func,
GDestroyNotify destroy,
void* user_data);
void* user_data)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
gulong
gbinder_ipc_transact_custom(
GBinderIpc* ipc,
GBinderIpcTxFunc exec,
GBinderIpcTxFunc done,
GDestroyNotify destroy,
void* user_data);
void* user_data)
GBINDER_INTERNAL;
G_GNUC_INTERNAL
void
gbinder_ipc_cancel(
GBinderIpc* ipc,
gulong id);
gulong id)
GBINDER_INTERNAL;
/* Internal for GBinderLocalObject */
G_GNUC_INTERNAL
void
gbinder_ipc_local_object_disposed(
GBinderIpc* self,
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
/* Internal for GBinderRemoteObject */
G_GNUC_INTERNAL
void
gbinder_ipc_remote_object_disposed(
GBinderIpc* self,
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
/* Declared for unit tests */
G_GNUC_INTERNAL
__attribute__((destructor))
void
gbinder_ipc_exit(
void);
void)
GBINDER_INTERNAL
GBINDER_DESTRUCTOR;
#endif /* GBINDER_IPC_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -79,7 +79,7 @@ typedef struct gbinder_local_object_class {
/* Need to add some placeholders if this class becomes public */
} GBinderLocalObjectClass;
GType gbinder_local_object_get_type(void);
GType gbinder_local_object_get_type(void) GBINDER_INTERNAL;
#define GBINDER_TYPE_LOCAL_OBJECT (gbinder_local_object_get_type())
#define GBINDER_LOCAL_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObject))
@@ -91,24 +91,28 @@ gulong
gbinder_local_object_add_weak_refs_changed_handler(
GBinderLocalObject* obj,
GBinderLocalObjectFunc func,
void* user_data);
void* user_data)
GBINDER_INTERNAL;
gulong
gbinder_local_object_add_strong_refs_changed_handler(
GBinderLocalObject* obj,
GBinderLocalObjectFunc func,
void* user_data);
void* user_data)
GBINDER_INTERNAL;
void
gbinder_local_object_remove_handler(
GBinderLocalObject* obj,
gulong id);
gulong id)
GBINDER_INTERNAL;
GBINDER_LOCAL_TRANSACTION_SUPPORT
gbinder_local_object_can_handle_transaction(
GBinderLocalObject* self,
const char* iface,
guint code);
guint code)
GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_local_object_handle_transaction(
@@ -116,7 +120,8 @@ gbinder_local_object_handle_transaction(
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status);
int* status)
GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_local_object_handle_looper_transaction(
@@ -124,23 +129,28 @@ gbinder_local_object_handle_looper_transaction(
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status);
int* status)
GBINDER_INTERNAL;
void
gbinder_local_object_handle_increfs(
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
void
gbinder_local_object_handle_decrefs(
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
void
gbinder_local_object_handle_acquire(
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
void
gbinder_local_object_handle_release(
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
#endif /* GBINDER_LOCAL_OBJECT_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -39,15 +39,18 @@
GBinderLocalReply*
gbinder_local_reply_new(
const GBinderIo* io);
const GBinderIo* io)
GBINDER_INTERNAL;
GBinderOutputData*
gbinder_local_reply_data(
GBinderLocalReply* reply);
GBinderLocalReply* reply)
GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_local_reply_new_from_data(
GBinderBuffer* buffer);
GBinderBuffer* buffer)
GBINDER_INTERNAL;
#endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -40,15 +40,18 @@
GBinderLocalRequest*
gbinder_local_request_new(
const GBinderIo* io,
GBytes* init);
GBytes* init)
GBINDER_INTERNAL;
GBinderOutputData*
gbinder_local_request_data(
GBinderLocalRequest* req);
GBinderLocalRequest* req)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_local_request_new_from_data(
GBinderBuffer* buffer);
GBinderBuffer* buffer)
GBINDER_INTERNAL;
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -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
@@ -33,17 +33,17 @@
#ifndef GBINDER_LOG_H
#define GBINDER_LOG_H
#include "gbinder_types.h"
#include "gbinder_types_p.h"
#define GLOG_MODULE_NAME GBINDER_LOG_MODULE
#include <gutil_log.h>
/* Declared for unit tests */
G_GNUC_INTERNAL
__attribute__((constructor))
void
gbinder_log_init(
void);
void)
GBINDER_INTERNAL;
#endif /* GBINDER_LOG_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -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

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -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

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -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
@@ -48,7 +48,8 @@ gbinder_reader_init(
GBinderReader* reader,
GBinderReaderData* data,
gsize offset,
gsize len);
gsize len)
GBINDER_INTERNAL;
#endif /* GBINDER_READER_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -55,15 +55,18 @@ GBinderRemoteObject*
gbinder_remote_object_new(
GBinderIpc* ipc,
guint32 handle,
gboolean maybe_dead);
gboolean maybe_dead)
GBINDER_INTERNAL;
gboolean
gbinder_remote_object_reanimate(
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
void
gbinder_remote_object_handle_death_notification(
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_OBJECT_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -39,16 +39,19 @@
GBinderRemoteReply*
gbinder_remote_reply_new(
GBinderObjectRegistry* reg);
GBinderObjectRegistry* reg)
GBINDER_INTERNAL;
void
gbinder_remote_reply_set_data(
GBinderRemoteReply* reply,
GBinderBuffer* buffer);
GBinderBuffer* buffer)
GBINDER_INTERNAL;
gboolean
gbinder_remote_reply_is_empty(
GBinderRemoteReply* reply);
GBinderRemoteReply* reply)
GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_REPLY_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -46,13 +46,15 @@ gbinder_remote_request_new(
GBinderObjectRegistry* reg,
const GBinderRpcProtocol* protocol,
pid_t pid,
uid_t euid);
uid_t euid)
GBINDER_INTERNAL;
void
gbinder_remote_request_set_data(
GBinderRemoteRequest* request,
guint txcode,
GBinderBuffer* buffer);
GBinderBuffer* buffer)
GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */

View File

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

View File

@@ -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:
*
@@ -13,10 +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.
* 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
@@ -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,13 +49,18 @@ struct gbinder_rpc_protocol {
char** iface);
};
extern const GBinderRpcProtocol gbinder_rpc_protocol_binder;
extern const GBinderRpcProtocol gbinder_rpc_protocol_hwbinder;
/* Returns one of the above based on the device name */
const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device(
const char* dev);
const char* dev)
GBINDER_INTERNAL;
/* Runs at exit, declared here strictly for unit tests */
void
gbinder_rpc_protocol_exit(
void)
GBINDER_DESTRUCTOR
GBINDER_INTERNAL;
#endif /* GBINDER_RPC_PROTOCOL_H */

View File

@@ -34,19 +34,65 @@
#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"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gutil_idlepool.h>
#include <gutil_misc.h>
#include <errno.h>
/*==========================================================================*
*
* Different versions of Android come with different flavors of service
* managers. They are usually based on these two more or less independent
* variants:
*
* platform/frameworks/native/cmds/servicemanager/ServiceManager.cpp
* platform/system/hwservicemanager/ServiceManager.cpp
*
* They are talking slightly different protocols which slightly mutate
* from version to version. If that's not complex enough, different
* kinds of service managers can be running simultaneously, serving
* different binder devices. Specific device => servicemanager mapping
* can be optionally configured in /etc/gbinder.conf file. The default
* service manager configuration looks like this:
*
* [ServiceManager]
* Default = aidl
* /dev/binder = aidl
* /dev/hwbinder = hidl
*
*==========================================================================*/
#define CONF_GROUP GBINDER_CONFIG_GROUP_SERVICEMANAGER
#define CONF_DEFAULT GBINDER_CONFIG_VALUE_DEFAULT
typedef struct gbinder_servicemanager_type {
const char* name;
GType (*get_type)(void);
} GBinderServiceManagerType;
static const GBinderServiceManagerType gbinder_servicemanager_types[] = {
{ "aidl", gbinder_servicemanager_aidl_get_type },
{ "aidl2", gbinder_servicemanager_aidl2_get_type },
{ "hidl", gbinder_servicemanager_hidl_get_type }
};
#define SERVICEMANAGER_TYPE_AIDL (gbinder_servicemanager_types + 0)
#define SERVICEMANAGER_TYPE_HIDL (gbinder_servicemanager_types + 2)
#define SERVICEMANAGER_TYPE_DEFAULT SERVICEMANAGER_TYPE_AIDL
static GHashTable* gbinder_servicemanager_map = NULL;
static const GBinderServiceManagerType* gbinder_servicemanager_default =
SERVICEMANAGER_TYPE_DEFAULT;
#define PRESENSE_WAIT_MS_MIN (100)
#define PRESENSE_WAIT_MS_MAX (1000)
#define PRESENSE_WAIT_MS_STEP (100)
@@ -62,8 +108,10 @@ struct gbinder_servicemanager_priv {
GHashTable* watch_table;
gulong death_id;
gboolean present;
guint presence_check_id;
GBinderEventLoopTimeout* presence_check;
guint presence_check_delay_ms;
GBinderEventLoopCallback* autorelease_cb;
GSList* autorelease;
};
G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
@@ -73,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)
@@ -275,9 +320,9 @@ gbinder_servicemanager_reanimated(
{
GBinderServiceManagerPriv* priv = self->priv;
if (priv->presence_check_id) {
g_source_remove(priv->presence_check_id);
priv->presence_check_id = 0;
if (priv->presence_check) {
gbinder_timeout_remove(priv->presence_check);
priv->presence_check = NULL;
}
GINFO("Service manager %s has appeared", self->dev);
/* Re-arm the watches */
@@ -317,13 +362,14 @@ gbinder_servicemanager_presense_check_timer(
gbinder_servicemanager_ref(self);
if (gbinder_remote_object_reanimate(remote)) {
/* Done */
priv->presence_check_id = 0;
priv->presence_check = NULL;
gbinder_servicemanager_reanimated(self);
result = G_SOURCE_REMOVE;
} else if (priv->presence_check_delay_ms < PRESENSE_WAIT_MS_MAX) {
priv->presence_check_delay_ms += PRESENSE_WAIT_MS_STEP;
priv->presence_check_id = g_timeout_add(priv->presence_check_delay_ms,
gbinder_servicemanager_presense_check_timer, self);
priv->presence_check =
gbinder_timeout_add(priv->presence_check_delay_ms,
gbinder_servicemanager_presense_check_timer, self);
result = G_SOURCE_REMOVE;
} else {
result = G_SOURCE_CONTINUE;
@@ -339,9 +385,9 @@ gbinder_servicemanager_presence_check_start(
{
GBinderServiceManagerPriv* priv = self->priv;
GASSERT(!priv->presence_check_id);
GASSERT(!priv->presence_check);
priv->presence_check_delay_ms = PRESENSE_WAIT_MS_MIN;
priv->presence_check_id = g_timeout_add(PRESENSE_WAIT_MS_MIN,
priv->presence_check = gbinder_timeout_add(PRESENSE_WAIT_MS_MIN,
gbinder_servicemanager_presense_check_timer, self);
}
@@ -391,6 +437,78 @@ gbinder_servicemanager_sleep_ms(
(wait.tv_sec > 0 || wait.tv_nsec > 0));
}
static
void
gbinder_servicemanager_autorelease_cb(
gpointer data)
{
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(data);
GBinderServiceManagerPriv* priv = self->priv;
GSList* list = priv->autorelease;
priv->autorelease_cb = NULL;
priv->autorelease = NULL;
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
*==========================================================================*/
@@ -407,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);
@@ -500,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*
@@ -675,10 +817,15 @@ gbinder_servicemanager_get_service_sync(
if (G_LIKELY(self) && name) {
obj = GBINDER_SERVICEMANAGER_GET_CLASS(self)->get_service
(self, name, status);
if (!self->pool) {
self->pool = gutil_idle_pool_new();
if (obj) {
GBinderServiceManagerPriv* priv = self->priv;
priv->autorelease = g_slist_prepend(priv->autorelease, obj);
if (!priv->autorelease_cb) {
priv->autorelease_cb = gbinder_idle_callback_schedule_new
(gbinder_servicemanager_autorelease_cb, self, NULL);
}
}
gutil_idle_pool_add_object(self->pool, obj);
} else if (status) {
*status = (-EINVAL);
}
@@ -848,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
*==========================================================================*/
@@ -915,12 +1084,11 @@ gbinder_servicemanager_finalize(
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
GBinderServiceManagerPriv* priv = self->priv;
if (priv->presence_check_id) {
g_source_remove(priv->presence_check_id);
}
gbinder_timeout_remove(priv->presence_check);
gbinder_remote_object_remove_handler(self->client->remote, priv->death_id);
gbinder_idle_callback_destroy(priv->autorelease_cb);
g_slist_free_full(priv->autorelease, g_object_unref);
g_hash_table_destroy(priv->watch_table);
gutil_idle_pool_destroy(self->pool);
gbinder_client_unref(self->client);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}

View File

@@ -0,0 +1,340 @@
/*
* 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:
*
* 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.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_servicemanager_aidl.h"
#include "gbinder_servicepoll.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
typedef struct gbinder_servicemanager_aidl_watch {
GBinderServicePoll* poll;
char* name;
gulong handler_id;
GBinderEventLoopTimeout* notify;
} GBinderServiceManagerAidlWatch;
struct gbinder_servicemanager_aidl_priv {
GBinderServicePoll* poll;
GHashTable* watch_table;
};
G_DEFINE_TYPE(GBinderServiceManagerAidl,
gbinder_servicemanager_aidl,
GBINDER_TYPE_SERVICEMANAGER)
#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_servicemanager_aidl_calls {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION
};
#define SERVICEMANAGER_AIDL_IFACE "android.os.IServiceManager"
static
void
gbinder_servicemanager_aidl_watch_proc(
GBinderServicePoll* poll,
const char* name_added,
void* user_data)
{
GBinderServiceManagerAidlWatch* watch = user_data;
if (!g_strcmp0(name_added, watch->name)) {
GBinderServiceManager* manager =
gbinder_servicepoll_manager(watch->poll);
if (watch->notify) {
gbinder_timeout_remove(watch->notify);
watch->notify = NULL;
}
gbinder_servicemanager_service_registered(manager, name_added);
}
}
static
gboolean
gbinder_servicemanager_aidl_watch_notify(
gpointer user_data)
{
GBinderServiceManagerAidlWatch* watch = user_data;
GBinderServiceManager* manager = gbinder_servicepoll_manager(watch->poll);
char* name = g_strdup(watch->name);
GASSERT(watch->notify);
watch->notify = NULL;
gbinder_servicemanager_service_registered(manager, name);
g_free(name);
return G_SOURCE_REMOVE;
}
static
void
gbinder_servicemanager_aidl_watch_free(
gpointer 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(GBinderServiceManagerAidlWatch, watch);
}
static
GBinderServiceManagerAidlWatch*
gbinder_servicemanager_aidl_watch_new(
GBinderServiceManagerAidl* self,
const char* name)
{
GBinderServiceManagerAidlPriv* priv = self->priv;
GBinderServiceManagerAidlWatch* watch =
g_slice_new0(GBinderServiceManagerAidlWatch);
watch->name = g_strdup(name);
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_aidl_list_services_req(
GBinderClient* client,
gint32 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_servicemanager_aidl_list(
GBinderServiceManager* manager)
{
GPtrArray* list = g_ptr_array_new();
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(client,
LIST_SERVICES_TRANSACTION, req, NULL)) != NULL) {
char* service = gbinder_remote_reply_read_string16(reply);
gbinder_remote_reply_unref(reply);
if (service) {
g_ptr_array_add(list, service);
gbinder_local_request_unref(req);
req = klass->list_services_req(client, list->len);
} else {
break;
}
}
gbinder_local_request_unref(req);
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
static
GBinderRemoteObject*
gbinder_servicemanager_aidl_get_service(
GBinderServiceManager* self,
const char* name,
int* status)
{
GBinderRemoteObject* obj;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
gbinder_local_request_append_string16(req, name);
reply = gbinder_client_transact_sync_reply(self->client,
CHECK_SERVICE_TRANSACTION, req, status);
obj = gbinder_remote_reply_read_object(reply);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return obj;
}
static
int
gbinder_servicemanager_aidl_add_service(
GBinderServiceManager* manager,
const char* name,
GBinderLocalObject* obj)
{
int status;
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);
gbinder_local_request_unref(req);
return status;
}
static
GBINDER_SERVICEMANAGER_NAME_CHECK
gbinder_servicemanager_aidl_check_name(
GBinderServiceManager* self,
const char* name)
{
return GBINDER_SERVICEMANAGER_NAME_OK;
}
static
gboolean
gbinder_servicemanager_aidl_watch(
GBinderServiceManager* manager,
const char* name)
{
GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
GBinderServiceManagerAidlPriv* priv = self->priv;
GBinderServiceManagerAidlWatch* watch =
gbinder_servicemanager_aidl_watch_new(self, name);
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_servicemanager_aidl_watch_notify, watch);
}
return TRUE;
}
static
void
gbinder_servicemanager_aidl_unwatch(
GBinderServiceManager* manager,
const char* name)
{
GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
GBinderServiceManagerAidlPriv* priv = self->priv;
g_hash_table_remove(priv->watch_table, name);
}
static
void
gbinder_servicemanager_aidl_init(
GBinderServiceManagerAidl* self)
{
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_servicemanager_aidl_finalize(
GObject* object)
{
GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(object);
GBinderServiceManagerAidlPriv* priv = self->priv;
g_hash_table_destroy(priv->watch_table);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
gbinder_servicemanager_aidl_class_init(
GBinderServiceManagerAidlClass* klass)
{
GBinderServiceManagerClass* manager = GBINDER_SERVICEMANAGER_CLASS(klass);
GObjectClass* object = G_OBJECT_CLASS(klass);
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 */
manager->watch = gbinder_servicemanager_aidl_watch;
manager->unwatch = gbinder_servicemanager_aidl_unwatch;
object->finalize = gbinder_servicemanager_aidl_finalize;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

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

View File

@@ -0,0 +1,101 @@
/*
* 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 (8)
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_DEFAULT);
return req;
}
static
GBinderLocalRequest*
gbinder_servicemanager_aidl2_add_service_req(
GBinderClient* client,
const char* name,
GBinderLocalObject* obj)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT);
return req;
}
static
void
gbinder_servicemanager_aidl2_init(
GBinderServiceManagerAidl* self)
{
}
static
void
gbinder_servicemanager_aidl2_class_init(
GBinderServiceManagerAidl2Class* cls)
{
cls->list_services_req = gbinder_servicemanager_aidl2_list_services_req;
cls->add_service_req = gbinder_servicemanager_aidl2_add_service_req;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

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

View File

@@ -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
@@ -49,7 +49,6 @@ typedef struct gbinder_servicemanager {
GBinderServiceManagerPriv* priv;
const char* dev;
GBinderClient* client;
GUtilIdlePool* pool;
} GBinderServiceManager;
typedef enum gbinder_servicemanager_name_check {
@@ -65,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);
@@ -85,18 +83,36 @@ typedef struct gbinder_servicemanager_class {
void (*unwatch)(GBinderServiceManager* self, const char* name);
} GBinderServiceManagerClass;
GType gbinder_servicemanager_get_type(void);
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(
GType type,
const char* dev);
const char* dev)
GBINDER_INTERNAL;
void
gbinder_servicemanager_service_registered(
GBinderServiceManager* self,
const char* name);
const char* name)
GBINDER_INTERNAL;
/* Declared for unit tests */
void
gbinder_servicemanager_exit(
void)
GBINDER_INTERNAL
GBINDER_DESTRUCTOR;
/* Derived types */
GType gbinder_servicemanager_aidl_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_aidl2_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_hidl_get_type(void) GBINDER_INTERNAL;
#endif /* GBINDER_SERVICEMANAGER_PRIVATE_H */

View File

@@ -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:
*
@@ -32,6 +32,7 @@
#include "gbinder_servicepoll.h"
#include "gbinder_servicemanager.h"
#include "gbinder_eventloop_p.h"
#include <gutil_strv.h>
@@ -46,7 +47,7 @@ struct gbinder_servicepoll {
GBinderServiceManager* manager;
char** list;
gulong list_id;
guint timer_id;
GBinderEventLoopTimeout* timer;
};
G_DEFINE_TYPE(GBinderServicePoll, gbinder_servicepoll, G_TYPE_OBJECT)
@@ -230,7 +231,7 @@ void
gbinder_servicepoll_init(
GBinderServicePoll* self)
{
self->timer_id = g_timeout_add(gbinder_servicepoll_interval_ms,
self->timer = gbinder_timeout_add(gbinder_servicepoll_interval_ms,
gbinder_servicepoll_timer, self);
}
@@ -241,7 +242,7 @@ gbinder_servicepoll_finalize(
{
GBinderServicePoll* self = GBINDER_SERVICEPOLL(object);
g_source_remove(self->timer_id);
gbinder_timeout_remove(self->timer);
gbinder_servicemanager_cancel(self->manager, self->list_id);
gbinder_servicemanager_unref(self->manager);
g_strfreev(self->list);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -35,7 +35,7 @@
#include "gbinder_types_p.h"
extern guint gbinder_servicepoll_interval_ms;
extern guint gbinder_servicepoll_interval_ms GBINDER_INTERNAL;
typedef
void
@@ -47,35 +47,42 @@ void
GBinderServicePoll*
gbinder_servicepoll_new(
GBinderServiceManager* manager,
GBinderServicePoll** weakptr);
GBinderServicePoll** weakptr)
GBINDER_INTERNAL;
GBinderServicePoll*
gbinder_servicepoll_ref(
GBinderServicePoll* poll);
GBinderServicePoll* poll)
GBINDER_INTERNAL;
void
gbinder_servicepoll_unref(
GBinderServicePoll* poll);
GBinderServicePoll* poll)
GBINDER_INTERNAL;
GBinderServiceManager*
gbinder_servicepoll_manager(
GBinderServicePoll* poll);
GBinderServicePoll* poll)
GBINDER_INTERNAL;
gboolean
gbinder_servicepoll_is_known_name(
GBinderServicePoll* poll,
const char* name);
const char* name)
GBINDER_INTERNAL;
gulong
gbinder_servicepoll_add_handler(
GBinderServicePoll* poll,
GBinderServicePollFunc func,
void* user_data);
void* user_data)
GBINDER_INTERNAL;
void
gbinder_servicepoll_remove_handler(
GBinderServicePoll* poll,
gulong id);
gulong id)
GBINDER_INTERNAL;
#endif /* GBINDER_SERVICEPOLL_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -38,29 +38,34 @@
int
gbinder_system_open(
const char* path,
int flags);
int flags)
GBINDER_INTERNAL;
int
gbinder_system_close(
int fd);
int fd)
GBINDER_INTERNAL;
int
gbinder_system_ioctl(
int fd,
int request,
void* data);
void* data)
GBINDER_INTERNAL;
void*
gbinder_system_mmap(
size_t length,
int prot,
int flags,
int fd);
int fd)
GBINDER_INTERNAL;
int
gbinder_system_munmap(
void* addr,
size_t length);
size_t length)
GBINDER_INTERNAL;
#endif /* GBINDER_SYSTEM_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -47,6 +47,8 @@ typedef struct gbinder_servicepoll GBinderServicePoll;
typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
#define GBINDER_INLINE_FUNC static inline
#define GBINDER_INTERNAL G_GNUC_INTERNAL
#define GBINDER_DESTRUCTOR __attribute__((destructor))
#define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
#define GBINDER_PING_TRANSACTION GBINDER_TRANSACTION('P','N','G')

View File

@@ -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
@@ -686,13 +686,9 @@ gbinder_writer_data_append_hidl_vec(
vec->owns_buffer = TRUE;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, vec);
/* Write the buffer object pointing to the vector descriptor */
/* Every vector, even the one without data, requires two buffer objects */
gbinder_writer_data_write_buffer_object(data, vec, sizeof(*vec), NULL);
/* Not sure what's the right way to deal with NULL vectors... */
if (buf) {
gbinder_writer_data_write_buffer_object(data, buf, total, &vec_parent);
}
gbinder_writer_data_write_buffer_object(data, buf, total, &vec_parent);
}
void
@@ -732,13 +728,14 @@ gbinder_writer_data_append_hidl_string(
gbinder_writer_data_write_buffer_object(data, hidl_string,
sizeof(*hidl_string), NULL);
/* Not sure what's the right way to deal with NULL strings... */
if (str) {
/* Write the buffer pointing to the string data including the
* NULL terminator, referencing string descriptor as a parent. */
gbinder_writer_data_write_buffer_object(data, str, len+1, &str_parent);
GVERBOSE_("\"%s\" %u %u %u", str, (guint)len, (guint)str_parent.index,
(guint)data->buffers_size);
} else {
gbinder_writer_data_write_buffer_object(data, NULL, 0, &str_parent);
}
}
@@ -819,9 +816,16 @@ gbinder_writer_data_append_hidl_string_vec(
GVERBOSE_("%d. \"%s\" %u %u %u", i + 1, hidl_str->data.str,
(guint)hidl_str->len, (guint)str_parent.index,
(guint)data->buffers_size);
} else {
GVERBOSE_("%d. NULL %u %u %u", i + 1, (guint)hidl_str->len,
(guint)str_parent.index, (guint)data->buffers_size);
gbinder_writer_data_write_buffer_object(data, NULL, 0,
&str_parent);
}
str_parent.offset += sizeof(GBinderHidlString);
}
} else {
gbinder_writer_data_write_buffer_object(data, NULL, 0, &vec_parent);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -48,94 +48,111 @@ typedef struct gbinder_writer_data {
void
gbinder_writer_init(
GBinderWriter* writer,
GBinderWriterData* data);
GBinderWriterData* data)
GBINDER_INTERNAL;
void
gbinder_writer_data_set_contents(
GBinderWriterData* data,
GBinderBuffer* buffer);
GBinderBuffer* buffer)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_bool(
GBinderWriterData* data,
gboolean value);
gboolean value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_int32(
GBinderWriterData* data,
guint32 value);
guint32 value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_int64(
GBinderWriterData* data,
guint64 value);
guint64 value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_float(
GBinderWriterData* data,
gfloat value);
gfloat value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_double(
GBinderWriterData* data,
gdouble value);
gdouble value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_string8(
GBinderWriterData* data,
const char* str);
const char* str)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_string8_len(
GBinderWriterData* data,
const char* str,
gsize len);
gsize len)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_string16(
GBinderWriterData* data,
const char* utf8);
const char* utf8)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_string16_len(
GBinderWriterData* data,
const char* utf8,
gssize num_bytes);
gssize num_bytes)
GBINDER_INTERNAL;
guint
gbinder_writer_data_append_buffer_object(
GBinderWriterData* data,
const void* ptr,
gsize size,
const GBinderParent* parent);
const GBinderParent* parent)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_hidl_vec(
GBinderWriterData* data,
const void* base,
guint count,
guint elemsize);
guint elemsize)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_hidl_string(
GBinderWriterData* data,
const char* str);
const char* str)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_hidl_string_vec(
GBinderWriterData* data,
const char* strv[],
gssize count);
gssize count)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_local_object(
GBinderWriterData* data,
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_remote_object(
GBinderWriterData* data,
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
#endif /* GBINDER_WRITER_PRIVATE_H */

View File

@@ -138,3 +138,17 @@ libgbinder-debug:
libgbinder-release:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
#
# Install
#
INSTALL = install
INSTALL_BIN_DIR = $(DESTDIR)/usr/bin
install: release $(INSTALL_BIN_DIR)
$(INSTALL) -m 755 $(RELEASE_EXE) $(INSTALL_BIN_DIR)
$(INSTALL_BIN_DIR):
$(INSTALL) -d $@

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -39,7 +39,7 @@
#define RET_INVARG (2)
#define RET_ERR (3)
#define DEV_DEFAULT "/dev/binder"
#define DEV_DEFAULT GBINDER_DEFAULT_HWBINDER
typedef struct app_options {
char* dev;

View File

@@ -138,3 +138,17 @@ libgbinder-debug:
libgbinder-release:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
#
# Install
#
INSTALL = install
INSTALL_BIN_DIR = $(DESTDIR)/usr/bin
install: release $(INSTALL_BIN_DIR)
$(INSTALL) -m 755 $(RELEASE_EXE) $(INSTALL_BIN_DIR)
$(INSTALL_BIN_DIR):
$(INSTALL) -d $@

View File

@@ -5,7 +5,9 @@ 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 $*
@$(MAKE) -C unit_local_object $*
@$(MAKE) -C unit_local_reply $*

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,9 @@ TESTS="\
unit_buffer \
unit_cleanup \
unit_client \
unit_config \
unit_driver \
unit_eventloop \
unit_ipc \
unit_local_object \
unit_local_reply \

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -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);
@@ -75,10 +75,13 @@ test_null(
void)
{
g_assert(!gbinder_client_new(NULL, NULL));
g_assert(!gbinder_client_new2(NULL, NULL, 0));
g_assert(!gbinder_client_ref(NULL));
g_assert(!gbinder_client_interface(NULL));
g_assert(!gbinder_client_interface2(NULL, 0));
gbinder_client_unref(NULL);
g_assert(!gbinder_client_new_request(NULL));
g_assert(!gbinder_client_new_request2(NULL, 0));
g_assert(!gbinder_client_transact_sync_reply(NULL, 0, NULL, NULL));
g_assert(gbinder_client_transact_sync_oneway(NULL, 0, NULL) == (-EINVAL));
g_assert(!gbinder_client_transact(NULL, 0, 0, NULL, NULL, NULL, NULL));
@@ -94,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";
@@ -102,7 +105,7 @@ test_basic(
g_assert(client);
g_assert(gbinder_client_ref(client) == client);
g_assert(!g_strcmp0(gbinder_client_interface(client), iface));
g_assert_cmpstr(gbinder_client_interface(client), == ,iface);
gbinder_client_unref(client);
gbinder_client_cancel(client, 0); /* does nothing */
@@ -111,6 +114,44 @@ test_basic(
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* interfaces
*==========================================================================*/
static
void
test_interfaces(
void)
{
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[] = {
{"33", 33 }, { "11", 11 }, { "22", 22 }
};
GBinderClient* client = gbinder_client_new2(obj, ifaces,
G_N_ELEMENTS(ifaces));
g_assert(client);
g_assert_cmpstr(gbinder_client_interface(client), == ,"11");
g_assert_cmpstr(gbinder_client_interface2(client, 11), == ,"11");
g_assert_cmpstr(gbinder_client_interface2(client, 22), == ,"22");
g_assert_cmpstr(gbinder_client_interface2(client, 33), == ,"33");
g_assert(!gbinder_client_interface2(client, 34));
g_assert(!gbinder_client_new_request2(client, 34));
gbinder_client_unref(client);
/* Client with no interface info */
client = gbinder_client_new2(obj, NULL, 0);
g_assert(client);
g_assert(!gbinder_client_interface(client));
g_assert(!gbinder_client_interface2(client, 1));
gbinder_client_unref(client);
gbinder_remote_object_unref(obj);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* no_header
*==========================================================================*/
@@ -344,8 +385,9 @@ test_reply(
GDestroyNotify destroy)
{
GBinderClient* client = test_client_new(0, TEST_INTERFACE);
GBinderLocalRequest* req = gbinder_client_new_request(client);
GBinderLocalRequest* req = gbinder_client_new_request2(client, 0);
g_assert(req);
test_reply_tx(client, req, done, destroy);
gbinder_local_request_unref(req);
@@ -391,6 +433,7 @@ int main(int argc, char* argv[])
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("interfaces"), test_interfaces);
g_test_add_func(TEST_("dead"), test_dead);
g_test_add_func(TEST_("no_header"), test_no_header);
g_test_add_func(TEST_("sync_oneway"), test_sync_oneway);

View File

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

View File

@@ -0,0 +1,505 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_common.h"
#include "gbinder_config.h"
#include <gutil_strv.h>
#include <gutil_log.h>
#include <sys/stat.h>
#include <sys/types.h>
static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-config-XXXXXX";
static
const char*
test_value(
GKeyFile* keyfile,
const char* group,
const char* key,
GString* buf)
{
char* value = g_key_file_get_value(keyfile, group, key, NULL);
g_string_set_size(buf, 0);
if (value) {
g_string_append(buf, value);
g_free(value);
return buf->str;
} else {
return NULL;
}
}
static
gboolean
test_keyfiles_equal(
GKeyFile* keyfile1,
GKeyFile* keyfile2)
{
gboolean equal = FALSE;
gsize ngroups;
char** groups = g_key_file_get_groups(keyfile1, &ngroups);
char** groups2 = g_key_file_get_groups(keyfile2, NULL);
gutil_strv_sort(groups, TRUE);
gutil_strv_sort(groups2, TRUE);
if (gutil_strv_equal(groups, groups2)) {
gsize i;
equal = TRUE;
for (i = 0; i < ngroups && equal; i++) {
const char* group = groups[i];
gsize nkeys;
char** keys = g_key_file_get_keys(keyfile1, group, &nkeys, NULL);
char** keys2 = g_key_file_get_keys(keyfile2, group, &nkeys, NULL);
equal = FALSE;
gutil_strv_sort(keys, TRUE);
gutil_strv_sort(keys2, TRUE);
if (gutil_strv_equal(keys, keys2)) {
gsize k;
equal = TRUE;
for (k = 0; k < nkeys && equal; k++) {
const char* key = keys[k];
char* v1 = g_key_file_get_value(keyfile1, group, key, NULL);
char* v2 = g_key_file_get_value(keyfile2, group, key, NULL);
if (g_strcmp0(v1, v2)) {
equal = FALSE;
GDEBUG("Values for %s/%s don't match ('%s' vs '%s')",
group, key, v1, v2);
}
g_free(v1);
g_free(v2);
}
} else {
GDEBUG("Keys for %s don't match", group);
}
g_strfreev(keys);
g_strfreev(keys2);
}
} else {
GDEBUG("Groups don't match");
}
g_strfreev(groups);
g_strfreev(groups2);
if (!equal) {
char* data1 = g_key_file_to_data(keyfile1, NULL, NULL);
char* data2 = g_key_file_to_data(keyfile2, NULL, NULL);
GDEBUG("This:");
GDEBUG("%s", data1);
GDEBUG("Doesn't match this:");
GDEBUG("%s", data2);
g_free(data1);
g_free(data2);
}
return equal;
}
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
const char* default_name = gbinder_config_file;
/* Reset the state */
gbinder_config_exit();
gbinder_config_file = NULL;
gbinder_config_dir = NULL;
g_assert(!gbinder_config_get());
/* Reset the state again */
gbinder_config_file = default_name;
}
/*==========================================================================*
* non_exist
*==========================================================================*/
static
void
test_non_exit(
void)
{
const char* default_name = gbinder_config_file;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
/* Reset the state */
gbinder_config_exit();
gbinder_config_file = file;
g_assert(!gbinder_config_get());
/* Reset the state again */
gbinder_config_file = default_name;
g_free(file);
remove(dir);
g_free(dir);
}
/*==========================================================================*
* bad_config
*==========================================================================*/
static
void
test_bad_config(
void)
{
const char* default_name = gbinder_config_file;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
static const char garbage[] = "foo";
/* Reset the state */
gbinder_config_exit();
/* Try to load the garbage */
g_assert(g_file_set_contents(file, garbage, -1, NULL));
gbinder_config_file = file;
g_assert(!gbinder_config_get());
/* Reset the state again */
gbinder_config_file = default_name;
remove(file);
g_free(file);
remove(dir);
g_free(dir);
}
/*==========================================================================*
* dirs
*==========================================================================*/
static
void
test_dirs(
void)
{
GKeyFile* k;
GString* b = g_string_new(NULL);
const char* default_file = gbinder_config_file;
const char* default_dir = gbinder_config_dir;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* subdir = g_build_filename(dir, "d", NULL);
char* notafile = g_build_filename(subdir, "dir.conf", NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
char* file1 = g_build_filename(subdir, "a.conf", NULL);
char* file2 = g_build_filename(subdir, "b.conf", NULL);
char* random_file = g_build_filename(subdir, "foo", NULL);
static const char garbage[] = "foo";
static const char config[] =
"[Protocol]\n"
"/dev/binder = aidl\n"
"/dev/hbinder = hidl\n";
static const char config1[] =
"[Protocol]\n"
"/dev/hwbinder = hidl\n"
"[ServiceManager]\n"
"/dev/binder = aidl\n";
static const char config2[] =
"[Protocol]\n"
"/dev/binder = aidl2\n"
"[ServiceManager]\n"
"/dev/binder = aidl2\n";
g_assert_cmpint(mkdir(subdir, 0700), == ,0);
g_assert_cmpint(mkdir(notafile, 0700), == ,0);
g_assert(g_file_set_contents(file, config, -1, NULL));
g_assert(g_file_set_contents(file1, config1, -1, NULL));
g_assert(g_file_set_contents(file2, config2, -1, NULL));
g_assert(g_file_set_contents(random_file, garbage, -1, NULL));
/* Reset the state */
gbinder_config_exit();
gbinder_config_file = file;
gbinder_config_dir = subdir;
/* Load the config */
k = gbinder_config_get();
g_assert(k);
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"Protocol","/dev/hbinder",b), == ,"hidl");
g_assert_cmpstr(test_value(k,"Protocol","/dev/hwbinder",b), == ,"hidl");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
/* Remove the default file and try again */
gbinder_config_exit();
g_assert_cmpint(remove(file), == ,0);
k = gbinder_config_get();
g_assert(k);
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"Protocol","/dev/hwbinder",b), == ,"hidl");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
/* Damage one of the files and try again */
gbinder_config_exit();
g_assert(g_file_set_contents(file1, garbage, -1, NULL));
k = gbinder_config_get();
g_assert(k);
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert(!test_value(k,"Protocol","/dev/hwbinder",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
/* Disallow access to one of the files and try again */
gbinder_config_exit();
g_assert_cmpint(chmod(file1, 0), == ,0);
k = gbinder_config_get();
g_assert(k);
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert(!test_value(k,"Protocol","/dev/hwbinder",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
/* Delete the remaining files and try again */
gbinder_config_exit();
g_assert_cmpint(remove(file1), == ,0);
g_assert_cmpint(remove(file2), == ,0);
g_assert(!gbinder_config_get());
/* Undo all the damage */
gbinder_config_exit();
gbinder_config_file = default_file;
gbinder_config_dir = default_dir;
remove(random_file);
g_free(file);
g_free(file1);
g_free(file2);
g_free(random_file);
remove(notafile);
remove(subdir);
remove(dir);
g_free(notafile);
g_free(subdir);
g_free(dir);
g_string_free(b, TRUE);
}
/*==========================================================================*
* autorelease
*==========================================================================*/
static
void
test_autorelease(
void)
{
const char* default_file = gbinder_config_file;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GKeyFile* keyfile;
static const char config[] = "[Protocol]";
gbinder_config_exit(); /* Reset the state */
/* Load the file */
g_assert(g_file_set_contents(file, config, -1, NULL));
gbinder_config_file = file;
keyfile = gbinder_config_get();
g_assert(keyfile);
/* Second call returns the same pointer */
g_assert(keyfile == gbinder_config_get());
test_quit_later_n(loop, 2);
test_run(&test_opt, loop);
g_main_loop_unref(loop);
/* Reset the state again */
gbinder_config_exit();
gbinder_config_file = default_file;
remove(file);
g_free(file);
remove(dir);
g_free(dir);
}
/*==========================================================================*
* Presets
*==========================================================================*/
typedef struct test_presets_data {
const char* name;
const char* in;
const char* out;
} TestPresetsData;
static
void
test_presets(
gconstpointer test_data)
{
const TestPresetsData* test = test_data;
const char* default_file = gbinder_config_file;
char* dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char* file = g_build_filename(dir, "test.conf", NULL);
GKeyFile* expected = g_key_file_new();
GKeyFile* keyfile;
/* Reset the state */
gbinder_config_exit();
/* Load the file */
if (test->in) {
g_assert(g_file_set_contents(file, test->in, -1, NULL));
gbinder_config_file = file;
} else {
gbinder_config_file = NULL;
}
keyfile = gbinder_config_get();
g_assert(keyfile);
/* Compare it against the expected value */
g_assert(g_key_file_load_from_data(expected, test->out, (gsize)-1,
G_KEY_FILE_NONE, NULL));
g_assert(test_keyfiles_equal(keyfile, expected));
/* Reset the state again */
gbinder_config_exit();
gbinder_config_file = default_file;
remove(file);
g_free(file);
remove(dir);
g_free(dir);
g_key_file_unref(expected);
}
static const TestPresetsData test_presets_data [] = {
{
"override",
"[General]\n"
"ApiLevel = 28\n"
"[ServiceManager]\n"
"/dev/vndbinder = aidl\n",
"[General]\n"
"ApiLevel = 28\n"
"[ServiceManager]\n"
"/dev/binder = aidl2\n"
"/dev/vndbinder = aidl\n" /* Preset is overridden */
},{
"too_small",
"[General]\n"
"ApiLevel = 27\n",
"[General]\n"
"ApiLevel = 27\n"
},{
"28",
"[General]\n"
"ApiLevel = 28",
"[General]\n"
"ApiLevel = 28\n"
"[ServiceManager]\n"
"/dev/binder = aidl2\n"
"/dev/vndbinder = aidl2\n"
},{
"29",
"[General]\n"
"ApiLevel = 29",
"[General]\n"
"ApiLevel = 29\n"
"[Protocol]\n"
"/dev/binder = aidl2\n"
"/dev/vndbinder = aidl2\n"
"[ServiceManager]\n"
"/dev/binder = aidl2\n"
"/dev/vndbinder = aidl2\n"
}
};
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/config/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
guint i;
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("non_exist"), test_non_exit);
g_test_add_func(TEST_("dirs"), test_dirs);
g_test_add_func(TEST_("bad_config"), test_bad_config);
g_test_add_func(TEST_("autorelease"), test_autorelease);
for (i = 0; i < G_N_ELEMENTS(test_presets_data); i++) {
const TestPresetsData* test = test_presets_data + i;
char* path;
path = g_strconcat(TEST_("presets/"), test->name, NULL);
g_test_add_data_func(path, test, test_presets);
g_free(path);
}
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

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

View File

@@ -0,0 +1,262 @@
/*
* 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_eventloop_p.h"
static TestOpt test_opt;
static int test_eventloop_timeout_add_called;
static int test_eventloop_callback_new_called;
static int test_eventloop_cleanup_called;
static
gboolean
test_unreached_proc(
gpointer data)
{
g_assert_not_reached();
return G_SOURCE_CONTINUE;
}
/*==========================================================================*
* Test event loop integration
*==========================================================================*/
static
GBinderEventLoopTimeout*
test_eventloop_timeout_add(
guint interval,
GSourceFunc func,
gpointer data)
{
test_eventloop_timeout_add_called++;
return NULL;
}
static
void
test_eventloop_timeout_remove(
GBinderEventLoopTimeout* timeout)
{
g_assert_not_reached();
}
static
GBinderEventLoopCallback*
test_eventloop_callback_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
{
test_eventloop_callback_new_called++;
return NULL;
}
static
void
test_eventloop_callback_ref(
GBinderEventLoopCallback* cb)
{
g_assert_not_reached();
}
static
void
test_eventloop_callback_unref(
GBinderEventLoopCallback* cb)
{
g_assert_not_reached();
}
static
void
test_eventloop_callback_schedule(
GBinderEventLoopCallback* cb)
{
g_assert_not_reached();
}
static
void
test_eventloop_callback_cancel(
GBinderEventLoopCallback* cb)
{
g_assert_not_reached();
}
static
void
test_eventloop_cleanup(
void)
{
test_eventloop_cleanup_called++;
}
static const GBinderEventLoopIntegration test_eventloop = {
test_eventloop_timeout_add,
test_eventloop_timeout_remove,
test_eventloop_callback_new,
test_eventloop_callback_ref,
test_eventloop_callback_unref,
test_eventloop_callback_schedule,
test_eventloop_callback_cancel,
test_eventloop_cleanup
};
/*==========================================================================*
* replace
*==========================================================================*/
static
void
test_replace(
void)
{
test_eventloop_timeout_add_called = 0;
test_eventloop_callback_new_called = 0;
test_eventloop_cleanup_called = 0;
gbinder_eventloop_set(NULL);
gbinder_eventloop_set(&test_eventloop);
g_assert(!gbinder_timeout_add(0, test_unreached_proc, NULL));
g_assert_cmpint(test_eventloop_timeout_add_called, == ,1);
g_assert(!gbinder_idle_add(test_unreached_proc, NULL));
g_assert_cmpint(test_eventloop_timeout_add_called, == ,2);
gbinder_timeout_remove(NULL);
g_assert(!gbinder_idle_callback_new(NULL, NULL, NULL));
g_assert_cmpint(test_eventloop_callback_new_called, == ,1);
g_assert(!gbinder_idle_callback_ref(NULL));
gbinder_idle_callback_unref(NULL);
gbinder_idle_callback_schedule(NULL);
gbinder_idle_callback_cancel(NULL);
gbinder_eventloop_set(NULL);
g_assert_cmpint(test_eventloop_cleanup_called, == ,1);
}
/*==========================================================================*
* idle
*==========================================================================*/
static
gboolean
test_quit_func(
gpointer data)
{
g_main_loop_quit((GMainLoop*)data);
return G_SOURCE_REMOVE;
}
static
void
test_idle(
void)
{
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gbinder_eventloop_set(NULL);
g_assert(gbinder_idle_add(test_quit_func, loop));
test_run(&test_opt, loop);
g_main_loop_unref(loop);
}
/*==========================================================================*
* timeout
*==========================================================================*/
static
void
test_timeout(
void)
{
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gbinder_eventloop_set(NULL);
g_assert(gbinder_timeout_add(10, test_quit_func, loop));
test_run(&test_opt, loop);
g_main_loop_unref(loop);
}
/*==========================================================================*
* callback
*==========================================================================*/
static
void
test_quit_cb(
gpointer data)
{
g_main_loop_quit((GMainLoop*)data);
}
static
void
test_callback(
void)
{
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderEventLoopCallback* cb;
gbinder_eventloop_set(NULL);
cb = gbinder_idle_callback_new(test_quit_cb, loop, NULL);
gbinder_idle_callback_schedule(cb);
test_run(&test_opt, loop);
gbinder_idle_callback_unref(cb);
g_main_loop_unref(loop);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_(t) "/eventloop/" t
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("replace"), test_replace);
g_test_add_func(TEST_("idle"), test_idle);
g_test_add_func(TEST_("timeout"), test_timeout);
g_test_add_func(TEST_("callback"), test_callback);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 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:
*
@@ -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,14 +119,14 @@ 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();
}
@@ -153,7 +153,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 +180,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);
@@ -202,7 +202,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);
@@ -258,7 +258,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);
@@ -316,7 +316,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);
@@ -374,7 +374,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);
@@ -421,7 +421,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);
@@ -470,7 +470,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);
@@ -512,7 +512,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);
@@ -543,7 +543,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);
@@ -575,7 +575,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,
@@ -624,7 +624,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);
@@ -669,7 +669,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,
@@ -683,6 +683,94 @@ test_transact_cancel2(
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_2way
*==========================================================================*/
static
GBinderLocalReply*
test_transact_2way_incoming_proc(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
int* incoming_call = user_data;
GVERBOSE_("\"%s\" %u", gbinder_remote_request_interface(req), code);
g_assert_cmpuint(flags, == ,0);
g_assert_cmpint(gbinder_remote_request_sender_pid(req), == ,getpid());
g_assert_cmpint(gbinder_remote_request_sender_euid(req), == ,geteuid());
g_assert_cmpstr(gbinder_remote_request_interface(req), == ,"test");
g_assert_cmpstr(gbinder_remote_request_read_string8(req), == ,"message");
g_assert_cmpuint(code, == ,2);
g_assert_cmpint(*incoming_call, == ,0);
(*incoming_call)++;
*status = GBINDER_STATUS_OK;
return gbinder_local_object_new_reply(obj);
}
static
void
test_transact_2way(
void)
{
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);
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
const char* const ifaces[] = { "test", NULL };
const guint32 handle = 0;
const guint32 code = 1;
int incoming_call = 0;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_2way_incoming_proc, &incoming_call);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderLocalRequest* incoming_req = gbinder_local_request_new(io, NULL);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
/* Prepare reply */
g_assert(gbinder_local_reply_append_string16(reply, TEST_REQ_PARAM_STR));
/* Prepare incoming request */
gbinder_local_request_init_writer(req, &writer);
prot->write_rpc_header(&writer, "test");
gbinder_writer_append_string8(&writer, "message");
test_binder_br_transaction(fd, obj, 2,
gbinder_local_request_data(req)->bytes);
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply(fd, handle, code,
gbinder_local_reply_data(reply)->bytes);
/* NB. Reusing test_transact_ok_done and test_transact_ok_destroy */
g_assert(gbinder_ipc_transact(ipc, handle, code, 0, req,
test_transact_ok_done, test_transact_ok_destroy, loop));
test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */
GDEBUG("waiting for GBinderIpc to get destroyed");
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
gbinder_local_object_unref(obj);
gbinder_local_request_unref(req);
gbinder_local_request_unref(incoming_req);
gbinder_local_reply_unref(reply);
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_incoming
*==========================================================================*/
@@ -715,7 +803,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);
@@ -724,16 +812,21 @@ test_transact_incoming(
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_incoming_proc, loop);
GBinderLocalRequest* ping = gbinder_local_request_new(io, NULL);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
gbinder_local_request_init_writer(ping, &writer);
prot->write_ping(&writer);
gbinder_local_request_init_writer(req, &writer);
prot->write_rpc_header(&writer, "test");
gbinder_writer_append_string8(&writer, "message");
data = gbinder_local_request_data(req);
test_binder_br_transaction(fd, obj, 1, data->bytes);
test_binder_br_transaction(fd, obj, prot->ping_tx,
gbinder_local_request_data(ping)->bytes);
test_binder_br_transaction(fd, obj, 1,
gbinder_local_request_data(req)->bytes);
test_binder_set_looper_enabled(fd, TRUE);
test_run(&test_opt, loop);
@@ -741,6 +834,7 @@ test_transact_incoming(
GDEBUG("waiting for GBinderIpc to get destroyed");
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
gbinder_local_object_unref(obj);
gbinder_local_request_unref(ping);
gbinder_local_request_unref(req);
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
@@ -779,7 +873,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);
@@ -886,7 +980,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);
@@ -959,7 +1053,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);
@@ -1013,7 +1107,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);
@@ -1055,7 +1149,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);
@@ -1097,6 +1191,7 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_("transact_custom3"), test_transact_custom3);
g_test_add_func(TEST_("transact_cancel"), test_transact_cancel);
g_test_add_func(TEST_("transact_cancel2"), test_transact_cancel2);
g_test_add_func(TEST_("transact_2way"), test_transact_2way);
g_test_add_func(TEST_("transact_incoming"), test_transact_incoming);
g_test_add_func(TEST_("transact_status_reply"), test_transact_status_reply);
g_test_add_func(TEST_("transact_async"), test_transact_async);

View File

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

View File

@@ -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
@@ -357,10 +357,10 @@ test_hidl_string(
gbinder_local_reply_append_hidl_string(reply, NULL);
data = gbinder_local_reply_data(reply);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
g_assert(offsets->count == 2);
g_assert(offsets->data[0] == 0);
g_assert(gbinder_output_data_buffers_size(data)==sizeof(GBinderHidlString));
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
g_assert(data->bytes->len == 2*BUFFER_OBJECT_SIZE_32);
gbinder_local_reply_unref(reply);
}
@@ -380,10 +380,10 @@ test_hidl_string_vec(
gbinder_local_reply_append_hidl_string_vec(reply, NULL, 0);
data = gbinder_local_reply_data(reply);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
g_assert(offsets->count == 2);
g_assert(offsets->data[0] == 0);
g_assert(gbinder_output_data_buffers_size(data) == sizeof(GBinderHidlVec));
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
g_assert(data->bytes->len == 2*BUFFER_OBJECT_SIZE_32);
gbinder_local_reply_unref(reply);
}
@@ -399,7 +399,7 @@ test_local_object(
GBinderLocalReply* reply;
GBinderOutputData* data;
GUtilIntArray* offsets;
GBinderIpc* ipc = gbinder_ipc_new(NULL, NULL);
GBinderIpc* ipc = gbinder_ipc_new(NULL);
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-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
@@ -385,10 +385,10 @@ test_hidl_string(
gbinder_local_request_append_hidl_string(req, NULL);
data = gbinder_local_request_data(req);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
g_assert(offsets->count == 2);
g_assert(offsets->data[0] == 0);
g_assert(gbinder_output_data_buffers_size(data)==sizeof(GBinderHidlString));
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
g_assert(data->bytes->len == 2*BUFFER_OBJECT_SIZE_32);
gbinder_local_request_unref(req);
}
@@ -408,10 +408,10 @@ test_hidl_string_vec(
gbinder_local_request_append_hidl_string_vec(req, NULL, 0);
data = gbinder_local_request_data(req);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
g_assert(offsets->count == 2);
g_assert(offsets->data[0] == 0);
g_assert(gbinder_output_data_buffers_size(data) == sizeof(GBinderHidlVec));
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
g_assert(data->bytes->len == 2*BUFFER_OBJECT_SIZE_32);
gbinder_local_request_unref(req);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -485,8 +485,6 @@ typedef struct test_hidl_vec_data {
guint buffers_size;
} TestHidlVecData;
static guint test_hidl_vec_offsets_0[] =
{ 0 };
static guint test_hidl_vec_offsets_32[] =
{ 0, BUFFER_OBJECT_SIZE_32 };
static guint test_hidl_vec_offsets_64[] =
@@ -494,12 +492,12 @@ static guint test_hidl_vec_offsets_64[] =
static const TestHidlVecData test_hidl_vec_tests[] = {
{ "32/null", &gbinder_io_32, NULL, 0, 0,
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(GBinderHidlVec) },
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_32), sizeof(GBinderHidlVec) },
{ "32/2x1", &gbinder_io_32, "xy", 2, 1,
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_32),
sizeof(GBinderHidlVec) + 8 /* vec data aligned at 8 bytes boundary */ },
{ "64/null", &gbinder_io_64, NULL, 0, 0,
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(GBinderHidlVec) },
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_64), sizeof(GBinderHidlVec) },
{ "64/2x2", &gbinder_io_64, "xxyy", 2, 2,
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_64),
sizeof(GBinderHidlVec) + 8 /* vec data aligned at 8 bytes boundary */ }
@@ -544,8 +542,6 @@ typedef struct test_hidl_string_data {
guint buffers_size;
} TestHidlStringData;
static guint test_hidl_string_offsets_0[] =
{ 0 };
static guint test_hidl_string_offsets_32[] =
{ 0, BUFFER_OBJECT_SIZE_32 };
static guint test_hidl_string_offsets_64[] =
@@ -553,13 +549,13 @@ static guint test_hidl_string_offsets_64[] =
static const TestHidlStringData test_hidl_string_tests[] = {
{ "32/null", &gbinder_io_32, NULL,
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0),
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_32),
sizeof(GBinderHidlString) },
{ "32/xxx", &gbinder_io_32, "xxx",
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_32),
sizeof(GBinderHidlString) + 8 /* string data aligned at 8 bytes */ },
{ "64/null", &gbinder_io_64, NULL,
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0),
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_64),
sizeof(GBinderHidlString) },
{ "64/xxxxxxx", &gbinder_io_64, "xxxxxxx",
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_64),
@@ -607,7 +603,7 @@ test_hidl_string2(
data = gbinder_local_request_data(req);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets);
g_assert(offsets->count == 3);
g_assert(offsets->count == 4);
g_assert(offsets->data[0] == 0);
g_assert(offsets->data[1] == BUFFER_OBJECT_SIZE_32);
g_assert(offsets->data[2] == 2*BUFFER_OBJECT_SIZE_32);
@@ -634,8 +630,10 @@ typedef struct test_hidl_string_vec_data {
static char* test_hidl_string_vec_data_1[] = { "test" };
static guint test_hidl_string_vec_offsets_empty[] =
{ 0 };
static guint test_hidl_string_vec_offsets_empty_32[] =
{ 0, BUFFER_OBJECT_SIZE_32 };
static guint test_hidl_string_vec_offsets_empty_64[] =
{ 0, BUFFER_OBJECT_SIZE_64 };
static guint test_hidl_string_vec_offsets_1_32[] =
{ 0, BUFFER_OBJECT_SIZE_32, 2*BUFFER_OBJECT_SIZE_32 };
static guint test_hidl_string_vec_offsets_1_64[] =
@@ -643,14 +641,14 @@ static guint test_hidl_string_vec_offsets_1_64[] =
static const TestHidlStringVecData test_hidl_string_vec_tests[] = {
{ "32/null", &gbinder_io_32, NULL, -1,
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty_32),
sizeof(GBinderHidlVec) },
{ "32/1", &gbinder_io_32,
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_1_32),
sizeof(GBinderHidlVec) + sizeof(GBinderHidlString) + 8 },
{ "64/null", &gbinder_io_64, NULL, -1,
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty_64),
sizeof(GBinderHidlVec) },
{ "64/1", &gbinder_io_64,
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),